关于 lit-sync
lit-sync 将 BibTeX 文献同步到 Zotero,并在 Obsidian 中创建文献笔记;适用于项目负责人管理研究引用的工作流。它通过 Better BibTeX 刷新引用快照,并可按需检索全文。
主要功能
- 01解析 BibTeX 条目
- 02去重后同步文献到 Zotero
- 03验证 Better BibTeX 引用快照
- 04在 Obsidian 创建文献笔记
- 05按需检索全文并生成报告
适用场景
- 01将检索到的文献加入项目 Zotero 集合
- 02检查 refs.bib 快照是否更新
- 03把文献整理为 Obsidian 笔记
- 04按需获取并汇总论文全文
MCP 相关
可使用 Zotero MCP 服务搜索、添加文献并管理集合;未连接时会跳过该同步阶段。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ aperivue/ medsci-skills --skill lit-sync安装后在 Claude Code 中输入/lit-sync确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
skill.ymlreferences/bbt_lookup.mdconcept_note_template.mdfulltext_report.mdreferences/locale/ko/note_templates.mdscripts/check_citekey_provenance.pytests/citekey_provenance_challenge_selftest.shcitekey_provenance_challenge.shtest_poll_logic.sh详细介绍
文献同步:Zotero + Obsidian 流水线
获取 /search-lit 的 .bib 输出(或用户指定的任意 .bib 文件),将参考文献同步到 Zotero 文库和 Obsidian 文献笔记中,并在文献笔记积累到足够数量后提取跨主题概念笔记。
前置条件
- 仅限项目所有者。 协作者只能以只读方式使用已提交的
manuscript/_src/refs.bib快照。若当前用户是协作者(根据SSOT.yaml中的reference_manager.required_for,其无权访问 Zotero),则中止操作,并说明应在稿件中标记[@NEW:topic]占位符并通知所有者。 - Zotero 桌面版 7.x + Better BibTeX 插件,并已将 Better BibTeX 的“Keep updated”自动导出配置为
<project>/manuscript/_src/refs.bib。 - Zotero MCP 服务(若未连接,则跳过阶段 2;重新打开 Zotero 后,自动导出仍会刷新文件)。
- Obsidian CLI 或直接写入保管库文件;保管库路径取自用户环境(例如
$OBSIDIAN_VAULT)。
产物约定
/lit-sync 是 manuscript/_src/refs.bib(通过触发 Better BibTeX 自动导出)、references/zotero_collection.json 和 references/fulltext_retrieval.json(阶段 2.7)的唯一写入者。切勿直接写入 refs.bib——即使是为了弥补 Zotero 连接缺失也不行,因为只有 Better BibTeX 导出才能确保文件与文库保持同步;若自动导出出现故障,请修复 Zotero 设置。直接手动编辑 refs.bib 会造成偏离,发现后立即还原。
阶段 1:解析 BibTeX
使用正则表达式解析用户指定的 .bib 文件,或 /search-lit 刚生成的 references/library.bib。逐条提取:citekey、doi、pmid、标题、作者(至少提取名和姓)、期刊、年份,以及存在时的卷号、期号和页码。记录解析失败的条目并跳过。后续阶段中的所有书目信息均来自这些条目或 API 响应。
解析出的 citekey 还不是文库键:/search-lit 的候选键(Kim_2024_Validation)只是临时键,阶段 2 添加条目时,Better BibTeX 才会生成真正的键。切勿自行拼造键;步骤 3.2 的 §Citekey provenance 说明了笔记键的来源。
阶段 2:Zotero 同步
若 Zotero MCP 未连接,则跳过此阶段(仍需写入步骤 2.3 的文件,并设置 status: "skipped"),然后继续阶段 3。
步骤 2.1:确定项目集合
根据当前工作目录或用户明确指定的覆盖值识别项目。若已记录集合键,则重复使用;否则检查 Zotero 中是否已有该项目的集合,若没有,则使用 zotero_create_collection 创建集合。记录集合键;若创建了新集合,则向用户报告该键。
步骤 2.2:去重并添加
对每个条目:
- 使用
zotero_search_items按 DOI 或标题搜索——若条目已存在,则跳过。 先搜索再操作是防止重复的关键;zotero_add_by_doi本身不会去重(它会从 CrossRef 获取信息并创建条目),因此切勿跳过搜索。 - 否则,调用
zotero_add_by_doi(有 DOI 时)或zotero_add_by_url(只有 PMID 时,使用 PubMed URL)。既没有 DOI 也没有 PMID 的条目不会被添加:将其计为失败,并请用户手动添加。zotero_add_by_doi接受attach_mode参数,用于控制添加时尝试附加 OA 子级 PDF的行为(已安装的服务会将linked_url视为“为 PDF URL 创建书签”;其他值则会下载/导入)。具体接受值因服务版本而异,请对照已连接的服务进行确认。不要使用zotero_add_from_file为此处添加的条目附加 PDF:它没有父条目参数,会创建重复的父条目。
- 使用
zotero_manage_collections将条目放入项目集合。
步骤 2.3:结果报告
Zotero Sync:
Added: 8 papers (new)
Skipped: 3 papers (already in library)
Failed: 1 paper (no DOI/PMID)
Collection: RFA-Meta (TZQEP4NH)
始终在项目工作区中写入 references/zotero_collection.json:
{
"schema_version": 1,
"status": "synced",
"collection": "RFA-Meta",
"collection_key": "TZQEP4NH",
"added": 8,
"skipped": 3,
"failed": 1
}
如果 Zotero 不可用,则写入同一文件,并将 status 设为 "skipped",同时提供人类可读的 reason。
阶段 2.5:刷新 refs.bib 快照
Better BibTeX 的“保持更新”自动导出通常会在 Zotero 更改后的几秒内刷新
manuscript/_src/refs.bib。此阶段会验证快照是否确实已更新,以免后续技能使用过期内容。
步骤 2.5.1:解析路径
读取 SSOT.yaml → truth.refs_bib。默认值:manuscript/_src/refs.bib。如果不存在(旧版项目),则回退到 manuscript/_src/refs.bib,并发出 WARN,建议迁移 SSOT。
步骤 2.5.1b:前置条件断言(提前退出,不要轮询)
在进入步骤 2.5.2 的 10 秒轮询循环之前,验证两个前置条件。如果任一条件失败,则中止阶段 2.5 并提供设置说明,而不是等待永远无法解决的超时。
-
**Better BibTeX 正在响应。**探测正在运行的插件,而不是磁盘上的文件:
curl -s -m 5 -o /dev/null -w "%{http_code}" \ http://127.0.0.1:23119/better-bibtex/json-rpc # expect 200如果返回非 200,说明 Zotero 已关闭,或 BBT 尚未完成启动。等 Zotero 窗口出现后重试一次;BBT 会在应用启动几秒后注册其端点。
⚠️ **不要将
~/Zotero/better-bibtex/read-only.json作为判断条件。**当前版本的 BBT 会在自己的存储中保留自动导出注册信息,因此在正常安装中该文件通常为[];将其视为“未配置”会导致此阶段在正常运行的设置中被跳过,进而使过期的refs.bib和虚构的 citekey 被带入稿件。失败时打印:
阶段 2.5 已跳过:Better BibTeX 未在
127.0.0.1:23119上响应(HTTP<code>)。打开 Zotero,等待其完成加载,然后重新运行/lit-sync。 -
**目标 refs.bib 存在。**步骤 2.5.1 中解析出的
truth.refs_bib路径必须在磁盘上存在(即使为空也可以——BBT 会覆盖它)。失败时打印:阶段 2.5 已跳过:未找到目标快照
<path>。将 BBT 自动导出配置为使用“更改时”导出到 SSOT 路径,然后重新运行。
在任一提前退出情况下,在步骤 2.5.3 的 JSON 中将 refs_bib_refreshed: false 和 reason: "precondition:<which>" 设为相应值,告知用户,并将控制权返回给调用方。后续没有任何步骤会强制检查此标志,因此,告知用户是防止过期的 refs.bib 进入稿件的关键。
步骤 2.5.2:验证刷新
阶段 2 添加条目后:
- 在 Zotero 写入之前,捕获
stat -f "%m" manuscript/_src/refs.bib的结果。 - 最多等待 10 秒(Better BibTeX 防抖时间)。轮询 mtime。
- 如果 10 秒后 mtime 仍未变化:
- 提示用户检查 Zotero 是否正在运行,以及 BBT 导出是否设置为“保持更新”。
- 如果 BBT 自动导出路径有误,打印预期路径(
<project>/manuscript/_src/refs.bib)。 - 作为最后手段,提供手动导出方式:
File → Export Library → Better BibTeX → target path。
- mtime 更新后,搜索新添加的 citekey。所有 citekey 都必须存在;如果缺少任何一个,则报告失败(不要伪造条目)。
步骤 2.5.3:记录到 zotero_collection.json
追加到步骤 2.3 写入的 JSON 中:
{
"refs_bib_path": "manuscript/_src/refs.bib",
"refs_bib_mtime": "2026-04-24T14:32:11Z",
"refs_bib_refreshed": true,
"citekeys_verified": ["smithDeepLearningRadiology2024", "..."]
}
如果刷新失败,将 refs_bib_refreshed: false 设为相应值,并填写 reason。
阶段 2.7:全文检索(选择加入,仅限所有者)
仅在用户要求获取全文时运行(例如“下载 PDF”“获取全文”,或用户提供了明确要求获取全文的工作清单)。默认情况下,/lit-sync 仅处理元数据且尽量减少网络访问——不要自动运行此阶段。此阶段在条目加入 Zotero(阶段 2)且快照已验证(阶段 2.5)之后、Obsidian 笔记(阶段 3)之前运行。
提供以下两种途径,并在一份报告中汇总结果。只能通过这两种途径获取全文: 不要自动化已认证的浏览器会话,不要绕过付费墙或访问控制,也不要在此技能中硬编码机构代理、凭据或主机。对于这两种途径都无法获取的内容,转向机构访问、馆际互借或联系作者。
路线 A — 磁盘上的 OA PDF(供下游技能使用)
委托 /fulltext-retrieval 引擎(不要重新实现 OA 检索流程,也不要导入其代码;按路径调用):
ENGINE="${CLAUDE_SKILL_DIR}/../fulltext-retrieval/fetch_oa.py"
python3 "$ENGINE" <worklist> -o pdfs/ -e <contact-email> --report pdfs/retrieval_report.json
<worklist> 是 DOI/PMID(/标题)列表——Phase-1 .bib 中的 DOI、Standalone Modes 中提供的工作列表,或项目文献集的 DOI。输出:供 /meta-analysis 和 pdf_to_md.py 使用的 pdfs/*.pdf,以及 pdfs/retrieval_report.json(schema 2:检索 status/source、source_identity 和 file_sha256)。请区分文件是否存在与其身份是否已评估。
路线 B — 文献库中的 PDF(Zotero 原生方式,检索率更高,支持代理)
输出 ${CLAUDE_SKILL_DIR}/../fulltext-retrieval/references/find_available_pdf.js,供用户在选中项目文献集后粘贴到 Zotero(工具 → 开发者 → 运行 JavaScript)。此脚本会触发 Zotero 自带的 addAvailablePDF/addAvailablePDFs,复用用户自己的 OpenURL 解析器 / 机构代理——因此通常比仅检索 OA 的方式获取更多 PDF,同时此技能不会接触任何凭据或机构标识符。无需编写代码的等效操作是右键 →“查找可用 PDF”。记录打印出的 JSON 中 {attached, missing} 摘要。
报告
将路线 A 的 pdfs/retrieval_report.json(以及用户报告的路线 B 摘要)合并到 references/fulltext_retrieval.json,并在 references/zotero_collection.json 中添加一个简短的 fulltext 计数块。写入前请阅读 ${CLAUDE_SKILL_DIR}/references/fulltext_report.md——其中包含 schema 和身份依据规则(检索到的文件不等于已验证的论文;consistent 状态仅供参考;未评估的条目应列入 identity_review_needed)。
第 3 阶段:Obsidian 文献笔记
创建笔记前,先检测库中已有的目录结构。如果库已采用某种文件夹结构(包括韩语结构),请遵循现有结构——切勿擅自重命名用户的文件夹。对于新建或结构不明确的库,默认使用英文文件夹 Literature/ 和 Concepts/,以及英文模板(步骤 3.2、步骤 4.3)。对于韩语结构的库,或偏好韩语笔记的用户,请使用韩语文件夹布局和韩语标题模板,路径为 ${CLAUDE_SKILL_DIR}/references/locale/ko/note_templates.md(以及库自身的中心笔记名称)。
步骤 3.1:检查现有文献笔记
# Default English layout; substitute the vault's existing folder if one is present
# (e.g. "02 연구/문헌/" for a Korean-structured vault — see references/locale/ko/note_templates.md).
ls "$VAULT/Literature/" | grep -v "📊" | wc -l
步骤 3.2:创建文献笔记
为每个 .bib 条目创建 Literature/{citekey}.md(或使用库中现有的文献文件夹)。
如果文件已存在,则跳过——切勿覆盖,因为用户可能已添加高亮或个人笔记。
引文键溯源——笔记文件名代表对文献库的断言
笔记的文件名和 citekey: 字段表明 Zotero 中有一条使用该键的条目。手稿中的 [@key]、笔记之间的 [[key]],以及 Zotero Integration 插件的 {{citekey}}.md 都依赖这个键,而一个无法解析到任何条目的键看起来仍然正确。因此,键只能读取,不能编造:
- 从 Better BibTeX 导出的
refs.bib条目中获取,或通过 Better BibTeX 查询(json-rpc 上的item.search——参见${CLAUDE_SKILL_DIR}/references/bbt_lookup.md)。 - 如果 Zotero 中没有这篇论文,先添加(
zotero_add_by_doi),再由 BBT 生成键。第二阶段负责这一步是有原因的:在文献库条目之前写好笔记,就无法确定键是否正确。 - 如果无法添加(没有 DOI、处于离线状态),将笔记的
citekey: ""留空,并添加标签_needs-citekey。空字段可以补全;编造的键则不行,因为下游无法区分它和真实键。
完成前请验证:
python3 "${CLAUDE_SKILL_DIR}/scripts/check_citekey_provenance.py" --vault "$VAULT" --bib "$REFS_BIB"
INVENTED 表示笔记中的键不存在,但其 DOI 能解析到真实键;请在此处修正。
MISMATCH 表示键是真实的,但笔记的 DOI 是文献库中属于另一键的 DOI,因此引用了另一篇论文;请将文件重命名为建议的键(已知限制:如果笔记 DOI 的拼写与文献库不同,例如带引号或花括号,则不会触发此提示)。UNPARSED 表示文献笔记的 frontmatter 没有闭合,因此未读取其键。使用 --strict 时,这三种情况都会以状态码 1 退出;如果扫描未找到任何文献笔记,则以状态码 2 退出。始终按 DOI(而非键)将笔记与论文匹配(AMBIGUOUS、UNUSABLE、NO_IDENTIFIER:参见脚本的 --help),并在导入任何报告为缺失的内容前,搜索完整文献库(--live)。
模板
---
notetype: literature
citekey: "{citekey}"
title: "{title}"
authors: "{authors}"
journal: "{journal}"
year: {year}
doi: "{doi}"
pmid: "{pmid}"
created: "{today}"
tags:
- type/literature
- _unread
---
# {title}
## Bibliographic info
- **Authors**: {authors}
- **Journal**: {journal}{volume_issue_pages}
- **Year**: {year}
- **DOI**: [{doi}](https://doi.org/{doi})
{pmid_line}
## Key points (in my own words)
## My thoughts
## Related notes
- [[Research Hub]]
- [[Papers & Reviews]]
-
-
规则:
notetype: literature——与 Zotero Integration 模板兼容。_unread标签——用户之后在 Zotero 中阅读 PDF 并添加高亮后,将其改为_read。- 将
## Key points和## My thoughts留空——由用户自行填写。 ## Related notes包含 2 个中心笔记链接和 2 个空位(留待之后链接概念笔记)。- 如果有 PMID,请添加 PubMed 链接。
步骤 3.3:结果报告
Obsidian Literature Notes:
Created: 8 notes (new)
Skipped: 3 notes (already exist)
Location: Literature/
Total in vault: 12 literature notes
阶段 4:概念提取(条件执行)
触发条件
仅当知识库中有 ≥10 篇文献笔记时运行此阶段。如果不足,请打印类似“N 篇文献笔记——概念提取需达到 ≥10 篇”的状态消息,然后停止。
步骤 4.1:跨主题概念扫描
读取 Literature/*.md 下的所有文件(或知识库现有的文献文件夹),从每篇论文的标题、期刊和标签中提取关键词,并从 .bib 条目标题中提取主要概念,然后识别至少在 3 篇文献笔记中共同出现的概念。
步骤 4.2:筛选(5 条排除规则)
从概念候选项中排除:模型名称(GPT-4、Claude 等)、数据集名称(MedQA、ImageNet 等)、期刊名称、机构名称,以及泛化的技术名称(过于宽泛)。其余内容成为概念笔记候选项。
步骤 4.3:起草概念笔记
根据 ${CLAUDE_SKILL_DIR}/references/concept_note_template.md 中的模板创建 Concepts/{concept name}.md(或使用知识库现有的概念笔记文件夹;采用韩语结构的知识库请使用 references/locale/ko/note_templates.md 中的概念模板)。
关键规则:
- 绝不自动填写
## Definition——保留> TODO标记;只有用户用自己的话写下定义后,第二层笔记才有意义。 status始终以🌱Seedling开始。## Related notes下至少包含 4 个维基链接(遵循知识库惯例)。
步骤 4.4:向用户提出建议
Concept-note candidates (≥3 papers cross-referenced):
1. {Concept A} (4 papers)
2. {Concept B} (3 papers)
3. {Concept C} (5 papers)
Create? (all / selected / skip)
自动起草,但只有在用户确认后才创建。
独立模式
此技能无需新的 .bib 文件即可运行。
仅提取概念
收到明确的概念提取请求时,扫描现有的 Literature/*.md(或知识库中现有的文献文件夹),并且只运行 Phase 4。
整理参考文献
收到“整理此项目的参考文献”请求时,在工作区内查找 .bib 文件并运行 Phase 1–3。
仅同步 Zotero
收到“同步 Zotero”请求时,将 Zotero 文献集与 .bib 文件进行比对,并补充缺失的内容。
导入 PMID 列表(无 .bib)
用户提供 PMID 列表时(例如来自 HANDOFF 或同事),先通过 PubMed esummary 将 PMID 解析为 DOI,然后使用这些 DOI 进入 Phase 2:
PMIDS="12345,67890,..."
curl -s "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi?db=pubmed&id=${PMIDS}&retmode=json" \
| jq -r '.result | to_entries[] | select(.key != "uids") | "\(.value.uid)\t\(.value.elocationid)\t\(.value.title)"'
对于已在文献库中的条目(通过 Step 2.2 搜索发现),使用 zotero_manage_collections 将其添加到项目文献集中,不要重新添加——通过 URL/PubMed-URL 重新添加会绕过搜索去重,造成重复。将 added 和 existing 条目都记录到 references/zotero_collection.json 中。如果 PMID 在 PubMed 中没有 DOI(较早发表或未被索引的论文),则使用 PubMed URL 调用 zotero_add_by_url,并将条目标记为 no_doi: true。
导入工作列表(DOI/PMID/标题;无 .bib)
用户提供工作列表文件时(包含 DOI 列以及可选的 PMID/Title 的 .tsv/.csv/.md 表格,或每行一个 DOI 的纯文本列表——例如 SR 纳入集合),直接从该文件进入 Phase 2:先将仅包含 PMID 的行解析为 DOI(使用上文的 esummary),然后运行先搜索去重再添加的循环。同一工作列表文件也可用于 Phase 2.7 Route A(fetch_oa.py 可原生读取 .tsv/.csv/.md/纯文本文件),因此无需重新格式化。