Live watching¶
Deep-dive on the watcher that keeps obsidian-brain's index in sync with vault edits. Architectural placement is in architecture.md.
Why it's on by default in server¶
Before v1.1, the server read a snapshot of the vault and relied on a separate scheduled obsidian-brain index to catch new edits — a 30-minute staleness window, plus the requirement to set up launchd/systemd just to make search usable.
Since v1.1, obsidian-brain server starts a chokidar watcher on the vault path. Every editor save in Obsidian triggers an incremental reindex of the changed file, typically within a few seconds. No extra daemon to install, no timer to tune, and the scheduled-index fallback is still there for people who want it (set OBSIDIAN_BRAIN_NO_WATCH=1).
Chokidar under the hood¶
We use chokidar, which wraps the platform-native change API:
- macOS: FSEvents
- Linux: inotify
- Windows: ReadDirectoryChangesW
No polling. Idle CPU is effectively zero; you pay only when a file changes.
Chokidar emits a few event types — add, change, unlink. We react to all three:
add/change→ reindex the file (parse frontmatter + inline Dataviewkey:: valuefields, re-embed, upsert node + edges).unlink→ delete the node and its edges from the index.
Only .md files are watched. Everything else is ignored.
The two debounces and why they differ¶
| Debounce | Default | What it covers |
|---|---|---|
| Per-file | 3000 ms | Collapses bursts of saves on a single file into one reindex. |
| Community (graph-wide) | 60000 ms | Delays Louvain community detection until the vault settles. |
Per-file debounce is keyed by path. If you save Note A.md three times in a second and then Note B.md once, you get exactly two reindex operations 3 s after the last save of each file. That's the Obsidian autosave behaviour covered in the next section.
Community debounce is separate because Louvain runs over the entire graph and dominates cost on large vaults. Running it after every single file change would thrash; running it once per minute keeps detect_themes responsive without making per-file reindex slow.
Flow: Obsidian saves file → chokidar change event → 3 s per-file debounce → indexSingleNote (src/pipeline/indexer.ts:indexSingleNote) parses, embeds, upserts → community flag set dirty → 60 s later Louvain re-runs and clears the flag.
Obsidian's autosave and how we layer on top¶
Obsidian writes files to disk on a roughly 2-second debounce after you stop typing. During a long editing session this means a single note may be rewritten dozens of times — once for each pause longer than 2 s.
Our 3-second per-file debounce sits just above Obsidian's, which means:
- A single pause-and-resume editing pattern produces one reindex per "real" pause, not one per keystroke.
- A 30-minute continuous editing session on one note produces exactly one reindex, 3 s after the last save.
- The debounce timer resets on every save event, so nothing is ever reindexed mid-edit.
If you actually want to see search-worthy updates within 2 s of every save, lower OBSIDIAN_BRAIN_WATCH_DEBOUNCE_MS. It costs CPU proportional to the number of autosaves you trigger.
Tuning¶
All three are environment variables read at server startup:
| Env var | Default | Effect |
|---|---|---|
OBSIDIAN_BRAIN_NO_WATCH |
unset | Set to 1 to disable the watcher entirely; falls back to the scheduled-index model. |
OBSIDIAN_BRAIN_WATCH_DEBOUNCE_MS |
3000 |
Per-file reindex debounce. Lower for snappier search, higher for less CPU. |
OBSIDIAN_BRAIN_COMMUNITY_DEBOUNCE_MS |
60000 |
Graph-wide community detection debounce. Keep this high unless you actively call detect_themes frequently. |
No restart hot-reload — changes take effect next time server (or watch) starts.
Standalone daemon mode: obsidian-brain watch¶
If you don't run an MCP client continuously — for example you only launch Claude Desktop occasionally, but still want the index fresh so the first search is instant — use the watch subcommand. It's the same watcher code as server, minus the MCP transport.
Point launchd (macOS) or systemd (Linux) at it and let it run continuously. Templates in launchd.md and systemd.md.
Troubleshooting pointers¶
If edits aren't landing in the index, see troubleshooting.md → Watcher not firing. Most common causes: vault on a network drive where FSEvents/inotify don't fire, or OBSIDIAN_BRAIN_NO_WATCH=1 inherited from a shell or plist.
For an EMBEDDING_MODEL swap, v1.4.0+ auto-reindexes on next boot when it detects the model (or dim, or provider) changed — no --drop needed. See troubleshooting.md → Embedding dimension mismatch for the pre-v1.4.0 migration path.