vault-wikilinks
Broken Obsidian wikilink detection and repair. Use when fixing `[[Target]]` links, rewriting renamed-note refs, or resolving Zettelkasten/work-namespace paths.
- License 许可
- MIT
- 最近更新
- 2026-11-15
- Stars
- ★ 60
- Forks
- 6
01 前言 Front Matter
- name
- vault-wikilinks
- created
- 1776384000000
- modified
- 1782604800000
- reviewed
- 1782604800000
- description
- Broken Obsidian wikilink detection and repair. Use when fixing `[[Target]]` links, rewriting renamed-note refs, or resolving Zettelkasten/work-namespace paths.
- allowed-tools
- Read, Edit, Grep, Glob
- user-invocable
- false
02 资源文件 17
- 参考文档evals/evals.json4.0 KB
- 参考文档evals/files/cache-refresh-repo/AGENTS.md351 B
- 参考文档evals/files/cache-refresh-repo/brain/index.md53 B
- 参考文档evals/files/cache-refresh-repo/brain/plans/index.md23 B
- 参考文档evals/files/cache-refresh-repo/README.md471 B
- 参考文档evals/files/duplicate-avoidance/brain/sagas/label-copy/PROGRESS.md228 B
- 参考文档evals/files/duplicate-avoidance/brain/sagas/label-copy/SAGA.md459 B
- 参考文档evals/files/duplicate-avoidance/README.md224 B
- 参考文档evals/files/resume-saga/brain/sagas/cache-refresh-20261105/PROGRESS.md640 B
- 参考文档evals/files/resume-saga/brain/sagas/cache-refresh-20261105/SAGA.md616 B
- 参考文档evals/files/resume-saga/git-state.txt322 B
- 脚本evals/grade_evals.py10.3 KB
- 脚本evals/test_grade_evals.py8.2 KB
- 参考文档README.md5.3 KB
- 参考文档references/continuing-a-saga.md3.9 KB
- 参考文档references/saga-spec-template.md6.5 KB
- 参考文档references/validation-strategies.md4.7 KB
03 SKILL.md 正文
Wikilink Integrity
When to Use This Skill
| Use this skill when... | Use the alternative instead when... |
|---|---|
Repairing broken [[Target]] wikilinks after a note rename or move |
Discovering which links Obsidian flags as unresolved in the first place — use search-discovery |
Resolving cross-namespace ambiguity between Zettelkasten/ and work/z/ notes |
Reorganising or merging the work-namespace stub itself — use vault-stubs |
Unqualifying path-prefixed [[Kanban/X]] links to bare basenames |
Reconnecting orphan notes that have no links at all — use vault-orphans |
Obsidian resolves [[Target]] by looking for a note whose basename is Target.md anywhere in the vault. Links break silently when a note is renamed, moved, or was never created. Ambiguity arises when two notes share a basename.
Link Syntax
[[Note Name]] # basename resolution
[[Note Name|Alias]] # custom display text
[[Note Name#Section heading]] # deep link to heading
[[folder/Note Name]] # path-qualified (usually unnecessary)
![[Image.png]] # embed (image, note, PDF)
Resolution Rules
- Unqualified target (
[[Docker]]) resolves to any note with basenameDocker.md. If two exist (e.g.Zettelkasten/Docker.mdandwork/z/Docker.md), Obsidian picks one non-deterministically — ambiguous. - Path-qualified target (
[[Kanban/Main]]) resolves toKanban/Main.mdexactly — no basename fallback. - Embeds (
![[X]]) follow the same resolution. Image embeds typically target files underFiles/.
Common Breakage Patterns
| Pattern | Fix |
|---|---|
[[OldTopic]] × many → note doesn't exist |
Rewrite to [[Topic]] (the actual note) |
[[Development MOC]] → note was renamed |
Rewrite to [[Development Workflows and Tools MOC]] |
[[Kanban/X]] → works but path-qualified is brittle |
Rewrite to [[X]] when basename is unique |
[[code]], [[project]] → never were real notes |
These were inline-tag syntax errors; delete the link and leave plain text |
[[Gen AI Some Idea]] (double space) |
Fix the extra whitespace in the link |
Cross-Namespace Ambiguity
When two notes share a basename (e.g. Docker.md in both Zettelkasten/ and work/z/), every [[Docker]] in the vault becomes ambiguous. Options:
- Rename one so they stop colliding (
work/z/Docker.md→ keep as redirect stub; content lives inZettelkasten/Docker.md). - Path-qualify the links that should resolve to the non-canonical copy:
[[work/z/Docker]]. - Never use bare
[[Docker]]going forward; always path-qualify.
The preferred pattern is #1: keep canonical content in Zettelkasten/, make work/z/ a tiny redirect stub.
Detection
# Build a set of note basenames
fd -e md -x basename {} .md
# Find all wikilinks
rg -o '\[\[([^\]|#]+)' --no-filename --glob '*.md'
# Broken links: pipe the above through comm(1) against the basename set
A more accurate scan uses the links.analyze_links analyzer in vault-agent, which handles aliases, sections, and embeds correctly.
Offline Fallback (App Closed)
The detection methodology above is unchanged — only the data source changes when Obsidian (and its obsidian CLI / live link index) is closed. The obsidian CLI and vault-agent analyzers are the live-index path; parsing the .md corpus directly with the rg/fd Detection snippet above is the deterministic headless default, and for batch/scheduled audits it is often the better choice (reproducible, free of app/index state). vault-frontmatter already operates this way.
Parse the corpus directly:
- Frontmatter — read each note's YAML block between the leading
---fences; extracttags,aliases,context. Seevault-frontmatterfor YAML-block mechanics. - Wikilinks — match
[[Target]],[[Target|Alias]],[[Target#Heading]],[[folder/Target]], and![[embed]]. Resolve each target to a note by basename, then relative path, then alias (from frontmatter), all case-insensitive. Resolve![[embed]]against attachments as well as notes — the attachment folder is per-vault configurable, so read it from.obsidian/app.json(attachmentFolderPath) and fall back to the vault root /Files/only when that key is unset.
A link is broken when its target resolves to no note after the basename → relpath → alias (case-insensitive) cascade — embeds against attachments included. A target is ambiguous when its basename matches 2+ notes (the cross-namespace case above). Feed the Detection snippet's output through this resolution cascade to reproduce the unresolved audit headlessly.
Rewriting Strategy
For a known-broken target with many references, rewrite in one commit:
fix(links): rewrite 44 × [[OldTopic]] → [[Topic]]
Use Edit with replace_all=True for the target string within each note. Don't use shell sed — it doesn't handle the frontmatter / codeblock boundary correctly, and Edit's per-file atomicity makes the commit review straightforward.
For small-count broken targets (1–2 references each), report them and let the user decide whether to delete the link, create the note, or redirect.
Ambiguous-Target Handling
Never auto-rewrite an ambiguous link. Report the ambiguity with both candidates and ask the user which resolution they want:
[[Docker]] in Zettelkasten/Kubernetes.md → candidates:
a) Zettelkasten/Docker.md
b) work/z/Docker.md (redirect stub)
Safety
- Never rewrite links inside code blocks or YAML frontmatter.
- Never auto-create missing target notes — that's a content decision, not a maintenance one.
- Preserve the alias form:
[[Ansible|my ansible]]→[[Ansible|my ansible]], not[[Ansible]].
Related Skills
- vault-orphans — notes with no links at all
- vault-mocs — structured outgoing-link hubs
- search-discovery — runtime link traversal via Obsidian CLI
04 同仓库更多 Skills
kitty-show-image
Show the user an image with a note on what to judge, via a file send or a labelled kitty tab. Use when the user must see an image, or icat fails with no /dev/tty.
kitty-session-persistence
Snapshot and restore kitty terminal sessions on macOS. Use when surviving WindowServer hangs without losing tabs, configuring snapshots, or restoring after a force-reboot.
kitty-remote-control
Safe kitty remote control from an agent — read panes with kitty @ ls/get-text, notify, and never mutate the live terminal unasked. Use when running inside kitty.
docs-reference-check
Dangling doc-reference gate: flag markdown naming repo paths or relative links that no longer exist. Use when docs cite moved/deleted files, or wiring a doc-drift lint.
youtube-upload
Upload a video to YouTube via the Data API v3 and edit its title, description, tags or thumbnail afterwards. Use when publishing or retitling a YouTube video.
youtube-studio-share
Share a private YouTube video with a whole Google Workspace organization by scripting YouTube Studio in the browser. Use when a video must be org-only.