English · 中文
Keeps your Obsidian vault linked — in plain Markdown, without ever touching what you wrote.
Vault Linker builds a link layer on top of your notes: an index page for every area of your vault, and a short "Related notes" list at the end of each note, ranked by the topics the notes share. It runs on its own as your vault changes, and everything it writes lives in clearly marked blocks that it can update or remove at any time.

grep, git,
scripts, AI agents and other apps see them too. Uninstall the plugin and the links stay.README, index, dates)
are ignored automatically.At the end of a note:
---
<!-- AUTO-LINKS:START -->
## Related notes
- Index: [[_moc/Projects]]
- [[Projects/Cache redesign|Cache redesign]]
- [[Research/Eviction policies|Eviction policies]]
<!-- AUTO-LINKS:END -->
And one index page per top-level folder in _moc/, with subfolders as sections, plus a home page (Home).
Notes in the vault root are listed on Other notes:
# Projects
> This page is generated by Vault Linker. Do not edit by hand.
- [[Projects/Roadmap|Roadmap]] — What we plan to ship this year…
## Search
- [[Projects/Search/v2|Search v2]] — Goals for the second version of search…

The same note in Obsidian's local graph — with the plugin off, and after one run:

When a folder is renamed or deleted, its old index page is moved to the trash on the next run. Only pages the plugin generated are ever removed.
| Typical auto-link plugins | Vault Linker | |
|---|---|---|
| What makes two notes related | One note mentions the other's title | The topics they share, weighted by how rare each topic is |
| Where links go | Inline, into your text | A managed block at the end; your text is untouched |
| Ranking | None | Rarer shared topics count more; notes in the same area get a boost; top N kept |
| Index pages | One per folder, if any | One per area; several folders can form one area, with a one-line summary per note |
| Running it twice | Usually "skip existing links" | Fully idempotent: blocks are rebuilt, and a second run changes nothing |
| Files changed outside Obsidian | Missed when no file event fires | Picked up by polling |
From the community plugin list (Obsidian 1.13+): Settings → Community plugins → Browse, search for "Vault Linker Auto", then install and enable it. Obsidian 1.13.0 or later is required — the settings page uses the declarative settings API; older Obsidian versions stay on the last compatible release (0.2.2).
Manually from a release
main.js, manifest.json and styles.css from the
latest release.<your vault>/.obsidian/plugins/vault-linker-auto/. (.obsidian is a hidden folder; in the macOS
Finder press ⌘ ⇧ . to show it.)With BRAT (updates automatically): install the BRAT plugin,
choose Add beta plugin, and enter goldenxingxing/obsidian-vault-linker.
From source: npm install && npm run build, then copy main.js, manifest.json and styles.css as above.
After you enable it, the plugin changes nothing on its own.
That is all the setup there is. The settings page has seven items: run now, update automatically, how long to wait, related links per note, index pages, folders to skip, and optional topic terms. Each top-level folder gets its own index page, including folders you create later. Finer options (scoring, generated text, timing) have sensible defaults and live in the settings JSON: Export, edit, Import.
The report after each run lists what changed, what was skipped and why. Every run is also appended to
.obsidian/plugins/vault-linker-auto/vault-linker.log.

Every write goes through these checks:
_moc/Home.md), or a file whose name differs only in case, that page is skipped and reported.node_modules/ is ignored, along with the
top-level folders _moc/, _tmp/ and _archive/. If your notes live in one of those, change or clear the
list under scan.excludeTopDirs / scan.excludeAnyDirs in the settings JSON (Export, edit, Import).vault-linker: ignore to a note's frontmatter.--- rule gets a ***
separator instead, so the plugin never turns your text into frontmatter by accident.No network access, no telemetry, no accounts, no runtime dependencies, nothing to sign up for. Everything the plugin touches lives inside your vault folder:
<configDir>/plugins/vault-linker-auto/vault-linker.log,
so you can check afterwards what a run did. Nothing else is written there, and deleting the file is harmless.templates.json, plugins/templater-obsidian/data.json and daily-notes.json from your
Obsidian config folder. These are never modified. If you'd rather it didn't read them at all, turn off
scan.excludeTemplates in the settings JSON.Topics are what the plugin uses to find related notes. No vocabulary is built in; these sources are combined:
| Source | What it is | Default |
|---|---|---|
| Note titles and aliases | Each note's title and aliases |
Always |
| Tags | Tags you already use | Always |
| Topic terms | Your own list, one per line, with optional aliases | Empty |
| Find in my notes | Terms mined from your vault; the ones you tick are added to your topic terms | On demand |
| Folder structure | Notes in the same folder share the folder name as a topic | Off |
| Folder names | Folder names become topic terms; a note that mentions one relates to the notes filed there | Off |
Find in my notes splits long identifiers into words and, for Chinese text, scores 2–4 character sequences by how tightly they stick together and how varied their neighbors are, so it finds real terms without a dictionary. On a 762-note Chinese vault, 39 of 41 hand-picked domain terms appeared among the candidates. It shows a searchable list rather than a top-N, because rare terms rank low but still matter.
Measured with titles and tags as entities (every run recomputes the whole vault):
| Notes | Time per run |
|---|---|
| 790 | ~1 s |
| 3,160 | ~6 s |
| 6,320 | ~25 s |
Topic matching scans each note once for all entities (Aho-Corasick), and ranking compares only notes that share a topic. On large vaults with automatic runs, a longer quiet period in the settings keeps runs infrequent.
| Command | What it does |
|---|---|
| Preview (changes nothing) | Report only |
| Update links now | Writes, verifies, rolls back on failure |
| Show last run report | The last report in a dialog, copyable |
| Find terms in your notes | Finds candidate terms in your vault |
A command-line version runs the same engine without Obsidian:
node tools/cli/cli.ts --vault <vault> --config <vault>/.obsidian/plugins/vault-linker-auto/data.json # preview
node tools/cli/cli.ts --vault <vault> --config <vault>/.obsidian/plugins/vault-linker-auto/data.json --apply # write
Settings → Import / export settings turns your whole configuration, including areas and term lists, into JSON that someone else can import.
npm install
npm run typecheck
npm test # run directly by Node (22.18+)
npm run build # main.js
src/core/ is the engine: pure functions with no Obsidian dependency, so it runs in Node for tests and the CLI.src/obsidian/ is the thin Obsidian layer (reading, writing, settings, watching). runner.ts and watch.ts
depend only on a small duck-typed subset of the API, so tests/adapter.test.ts runs the full
read → plan → write → verify → roll back path against an in-memory vault.node --test use only erasable TypeScript syntax (no enum, namespace or
parameter properties).npm version patch # bumps package.json, manifest.json and versions.json, and tags the commit
git push && git push --tags
The tag triggers .github/workflows/release.yml, which tests, builds, signs the provenance of
main.js, manifest.json and styles.css (GitHub artifact attestations), and publishes the GitHub
release automatically — no manual step. The tag must equal the version, with no v prefix (.npmrc
sets tag-version-prefix="").
MIT