协作办公
在 Obsidian 知识库中自动发现并写入缺失的交叉引用和…
当用户要求为 Obsidian wiki 补链、查找缺失 wikilink、连接孤立页面,或在大规模入库后把新页面织入知识图谱时使用。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 38/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 60/100 ×0.15
适用场景
在 Obsidian 知识库中自动发现并特定
解决思路
- 遵循 `llm-wiki/SKILL.md` 的 Retrieval Primitives 表;Step 1 建 registry 时只 grep frontmatter,不读全文;全文 `Read` 只留给未链接提及检测,并且只读摘要/标题看起来可能是合理链接目标的页面;避免盲目全库通读。
- 开始前若会起草/改写自然语言 Markdown,先阅读并应用 `llm-wiki/SKILL.md` 的 `Writing Profile Resolution`;框架的 schema、provenance、安全和操作特定要求优先;`WRITING.md` 偏好只适用于新起草/改写的自然语言 Markdown,保留源内容和结构化记录。
- 解析配置:按 `llm-wiki/SKILL.md` 的 Config Resolution Protocol(inline `@name` override → 从 CWD 向上找 `.env` → 全局配置 → 提示设置),得到 `OBSIDIAN_VAULT_PATH` 和 `OBSIDIAN_LINK_FORMAT`(默认 `wikilink`)。
- 读取 `index.md`,获得所有页面清单及一句话描述。
- 浏览 `log.md`,查看最近入库内容,把链接工作重点放在新页面上。
- Step 4 插入链接时,按 `llm-wiki/SKILL.md` 的 Link Format 部分和 `OBSIDIAN_LINK_FORMAT` 应用链接格式;当 `OBSIDIAN_LINK_FORMAT=markdown` 时,从正在编辑的文件计算到目标页面的相对 `.md` 路径。
- Step 1 建立页面 registry:glob vault 中所有 `.md` 文件,排除 `_archives/`、`_readouts/`、`.obsidian/`。
- 对每个页面提取:文件名(去掉 `.md`,作为 wikilink 目标)、frontmatter 的 title、aliases、tags、category(frontmatter 或目录推断)、一句话摘要(第一句或 `title` 字段)。
- 构建查找表 `page_name → { path, title, aliases, tags, summary }`;该表就是可用的 wikilink 词汇表,每个条目都是有效 wikilink 目标。
- Step 2 扫描缺失链接:对每个页面读取完整内容。
- 提取页面中已有的 wikilink(所有 `[[...]]` 引用)。
- 搜索未链接提及:检查文本中是否出现未被 `[[...]]` 包裹的页面文件名、frontmatter 标题、aliases、registry 中的实体名/项目名/概念名。
- 检查语义连接:共享多个 tags,或位于同一项目目录,但彼此没有链接的页面。
- 匹配规则:名称大小写不敏感匹配(如 `my-project` 匹配 `MyProject`)。
- 匹配规则:变音符号不敏感匹配;比较前对页面名和正文做 Unicode NFKD 归一化(把重音字符分解为基字符+组合记号,去除组合记号),使正文 `Muller` 能匹配 `[[entities/müller]]`,反之亦然。
- 匹配规则:跳过自引用,页面不应链接到自己。
- 匹配规则:跳过常见词,不要链接 `the`、`and` 等泛化词;只匹配有辨识度的名称。
- 匹配规则:优先最短且无歧义的 wikilink 路径;当名称全库唯一时用 `[[page-name]]` 而不是 `[[full/path/to/page-name]]`。
- 匹配规则:不要在代码块或 frontmatter 内链接。
- 匹配规则:不要重复链接;如果页面已有 `[[foo]]`,不要再添加。
- Step 3 对每个候选链接评分并打置信标签:精确名称出现在正文 +4;共享 tags(2+)+2;同一项目但无链接 +2;提及实体/概念 +2;跨 category 连接 +2(如 `concepts/` ↔ `entities/`、`skills/` ↔ `synthesis/`,跨知识层更有架构价值);外围→枢纽可达 +2(源页面总链接 ≤2 而目标 ≥8);部分名称匹配 +1。
- 根据分数打置信标签:≥6 为 `EXTRACTED`,基本确定,内联应用;3–5 为 `INFERRED`,合理推断,内联或放入 Related 区;1–2 为 `AMBIGUOUS`,弱/部分匹配,除非用户明确要求连接松散页面,否则跳过。
- 只处理 `EXTRACTED` 和 `INFERRED` 候选;在 Cross-Link Report 中包含置信标签,让用户可在信任 `INFERRED` 链接前审查。
- Step 4 写入前快照:首次写文件前,检查 vault 本身是否是 Git 仓库根;只是更大仓库的子目录不符合;如果 vault 不是独立 Git 仓库,静默跳过此步,不要唠叨或建议 `git init`。
- 快照命令逻辑:设置 `VAULT_REAL_PATH=$(cd "$OBSIDIAN_VAULT_PATH" && pwd -P)`;`VAULT_GIT_ROOT=$(git -C "$OBSIDIAN_VAULT_PATH" rev-parse --show-toplevel 2>/dev/null || true)`;`SNAPSHOT_SHA=""`;仅当 `VAULT_GIT_ROOT` 非空且等于 `VAULT_REAL_PATH` 时继续。
- 快照:如果工作区干净(`git diff --quiet`、`git diff --cached --quiet`、无未跟踪文件),`SNAPSHOT_SHA=$(git -C "$OBSIDIAN_VAULT_PATH" rev-parse HEAD)`。
- 快照:如果不干净,运行 `git -C "$OBSIDIAN_VAULT_PATH" add -A`;若失败,输出 `Pre-write snapshot failed; abort the skill without writing any vault files.` 并退出 1;再运行 `git -C "$OBSIDIAN_VAULT_PATH" commit -m "pre-cross-linker snapshot" --quiet`;若失败同样中止且不写 vault 文件;成功后记录 `SNAPSHOT_SHA`。干净仓库分支不要调用 `git commit`,所以 `nothing to commit` 不视为错误;若 `git add` 或 `git commit` 失败,必须在编辑 vault 前停止,绝不能在未获得承诺的快照时继续。
- 如果 `SNAPSHOT_SHA` 非空且技能写了文件,在最终报告中包含该 SHA;要丢弃整次运行,在确认没有后续值得保留的更改后,用户可运行 `git -C "$OBSIDIAN_VAULT_PATH" reset --hard "$SNAPSHOT_SHA"` 和 `git -C "$OBSIDIAN_VAULT_PATH" clean -fd`。
- 对每个有缺失链接的页面执行 4a 内联链接(首选):在正文中找到术语第一次自然出现处,用 wikilink 包裹;示例:`This project uses knowledge graphs...` 改为 `This project uses [[concepts/knowledge-graphs|knowledge graphs]]...`;当 wikilink 路径与显示文本不同时使用 `[[path|display text]]`。
- 执行 4b Related 区(兜底):如果正文没有自然提及该术语,但页面语义相关(共享 tags、同一项目),在页面底部添加 `## Related`;示例条目如 `- [[projects/my-project/my-project]] — Also uses AI agents for research automation`;如果已有 `## Related`,追加进去,不重复已有条目。
- 执行 4c 推断并写入关系类型:对每个新增的 `EXTRACTED` 或 `INFERRED` 链接(内联或 Related),从周围句子上下文推断语义关系类型,并写入页面的 `relationships:` frontmatter;跳过 `AMBIGUOUS` 链接。
- 关系类型推断规则:句子模式 `X extends / builds on / generalises Y` → `extends`;`X implements / is an implementation of Y` → `implements`;`X contradicts / opposes / refutes / is at odds with Y` → `contradicts`;`X is derived from / based on / adapted from Y` → `derived_from`;`X uses / relies on / depends on / requires Y` → `uses`;`X replaces / supersedes / deprecates Y` → `replaces`;共享 tags 或跨 category 推断且无方向线索 → `related_to`。
- 如果上下文有歧义或链接来自共享 tag 匹配(正文无提及),默认 `related_to`。
- 写 `relationships:` 块:读取页面 YAML frontmatter;如果已有 `relationships:`,追加新条目且不重复已有 target;如果没有,加在 `aliases:` 之后(没有 `aliases:` 时加在 `tags:` 之后)。
- YAML 格式示例:`relationships:` 下 `- target: "[[concepts/knowledge-graphs]]"` 和 `type: uses`。
- `relationships:` YAML 块中的 `target` 始终使用 wikilink 格式 `[[path/to/page]]`,无论 `OBSIDIAN_LINK_FORMAT` 是什么;`OBSIDIAN_LINK_FORMAT` 控制正文,frontmatter 属性始终用 wikilink,以便 `wiki-export` 可靠解析。
- 只为本轮 cross-linker 新增的链接添加 relationships 条目;不要改动已存在的 typed entries。
- Step 5 主链接流程后,为 `misc/` 中所有页面更新 affinity 分数(frontmatter 有 `promotion_status: misc`,或位于 `misc/` 目录)。
- 对每个 misc 页面:收集正文所有 `[[wikilinks]]` 作为 outgoing links。
- 收集 incoming links:grep vault 中 `[[misc/<slug>]]` 和 `[[<slug>]]` 引用。
- 对每个双向链接页面,判断是否属于某个项目:位于 `projects/<project-name>/` 下,或 frontmatter 有匹配项目名的 `project:` 字段。
- 按项目名分组并求和:`outgoing_links + incoming_links`。
- 更新 misc 页面 frontmatter 的 `affinity` 块,如 `affinity:` 下 `obsidian-wiki: 3`、`another-project: 1`。
- 如果某项目得分 ≥3,标记该页面为 promotion candidate 并记录到报告中。
- 效率注意:只读取 misc 页面的完整正文;其他页面只需 grep frontmatter 来判断项目归属。
- Step 6 输出报告:包含 `## Cross-Link Report`;`### Links Added: N across P pages` 表格(Page、Links Added、Confidence、Placement、Relationship Types);`### Orphan Pages Remaining: N` 列出无出入链页面和找不到相关页的页面;`### Misc Promotion Candidates: N` 列出 misc/ 中与单项目连接 ≥3 的页面及 top project 和 score,并说明升级方式:移动到 `projects/<project-name>/references/` 并更新所有 backlinks;`### Pages Skipped: N` 列出 `index.md`、`log.md`、`_archives/*`、`_readouts/*` 等跳过原因。
- Step 7 追加到 `log.md`:`- [TIMESTAMP] CROSS_LINK pages_scanned=N links_added=M typed_relations_written=T pages_modified=P orphans_remaining=Q misc_affinity_updated=R promotion_candidates=S`。
- 更新 `hot.md`:读取 `$OBSIDIAN_VAULT_PATH/hot.md`(不存在则按 `wiki-ingest` 模板创建);用一行摘要更新 Recent Activity,例如 `Cross-linked 23 mentions across 12 pages; 2 orphans remain.`;保留最近 3 次操作;更新 `updated` 时间戳。
- Tips:每次 ingest 后运行;新页面通常连接差,这是修复方法。
- Tips:内联链接要保守;只链接第一次自然出现处,不要链接每次出现。
- Tips:不要触碰 `_archives/` 或 `_readouts/`;archive 是冻结快照,readouts 是 `wiki-narrate` 的派生输出,不是知识页。
- Tips:尊重现有结构;如果页面已在 `## Key Concepts` 中精心整理链接,就往该区添加,而不是另建 `## Related`。
- Tips:实体页是链接磁铁;像 `jane-doe` 这样的实体应从几乎每个项目页链接过来,优先处理。
- QMD 刷新(vault 写入后):QMD 是搜索索引,不是事实来源;如果 `$QMD_WIKI_COLLECTION` 为空或未设置,跳过此步;只在本技能写入或改写 vault Markdown 后运行;如果 QMD 刷新失败,不要回滚 vault 更改,单独报告 QMD 状态。
- QMD 命令:若设置了 `$QMD_CLI` 用该命令,否则用 `qmd`;运行 `${QMD_CLI:-qmd} update`;如果输出说需要 vectors 或 embeddings 可能过期,运行 `${QMD_CLI:-qmd} embed`。
- QMD 验证:用 `${QMD_CLI:-qmd} ls "$QMD_WIKI_COLLECTION"`,或在已知具体页面路径时用 `${QMD_CLI:-qmd} get "qmd://$QMD_WIKI_COLLECTION/<page>.md" -l 5`。
- QMD 记录以下之一:`QMD refreshed: update + embed + verified`、`QMD refreshed: update only + verified`、`QMD skipped: QMD_WIKI_COLLECTION unset`、`QMD skipped: qmd CLI unavailable`、`QMD failed: <short error summary>`。
适用边界 · 注意事项
- 不适用于只想报告链接问题而不修改页面的场景;这种只读检查应使用 wiki-lint。
- 不适用于没有 Obsidian vault、OBSIDIAN_VAULT_PATH 或 llm-wiki 框架/技能文件的场景。
- 不要对 _archives/、_readouts/、代码块或 frontmatter 内的文本做链接;这些不是应修改的知识页或不应插入正文链接。