@owrede/vault-memory 0.9.1 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,89 +1,134 @@
1
1
  # vault-memory
2
2
 
3
- Local-first semantic memory MCP server for Obsidian vaults.
3
+ **Local-first semantic memory for Obsidian vaults, exposed to AI agents over MCP.**
4
4
 
5
- Reads one or more Obsidian vaults, indexes them with local embeddings via Ollama, and exposes them to Claude Code through the Model Context Protocol — with semantic + BM25 hybrid search, wikilink graph navigation, frontmatter queries, atomic writes with concurrency protection, and live file-watching.
5
+ vault-memory turns one or more Obsidian vaults into a queryable, AI-native knowledge
6
+ base — running entirely on your machine. It indexes your notes with local embeddings
7
+ (via Ollama), keeps the index live as you edit, and exposes the result to Claude Code
8
+ (and any other [Model Context Protocol](https://modelcontextprotocol.io)–aware agent)
9
+ as a set of well-defined tools for search, graph navigation, frontmatter queries, and
10
+ atomic writes.
6
11
 
7
- ## Status
12
+ Nothing leaves your machine. No cloud sync, no API keys, no telemetry.
8
13
 
9
- **v0.9.1** Body-hash short-circuit (migration 006): frontmatter-only edits (the common case for `update_frontmatter`, `/log-fact`, `/import-person`) no longer trigger chunk + embedding regeneration. A new `body_hash` column on `notes` lets the watcher detect "body unchanged, frontmatter changed" and keep all existing chunks/embeddings in place — saving one Ollama roundtrip per chunk per frontmatter edit. Legacy rows pre-migration self-heal on next touch.
14
+ > See [CHANGELOG.md](./CHANGELOG.md) for release history. Latest: **v0.10.0**.
10
15
 
11
- Previous: **v0.9.0** Agent-Compatibility & Self-Orientation: OB1-compatible `search`/`fetch` tools so ChatGPT Custom Connectors, Claude.ai, and Deep-Research modes can use vault-memory as a connector; `vault_stats` and `recent_notes` for agent self-orientation on first connect.
16
+ ## What is vault-memory?
12
17
 
13
- ## Architecture in one paragraph
18
+ It's an [MCP server](https://modelcontextprotocol.io) that sits between your Obsidian
19
+ vaults and an AI agent. The agent — whether that's Claude Code in your editor, the
20
+ Claude desktop app via a Custom Connector, ChatGPT in Deep-Research mode, or anything
21
+ else that speaks MCP — gets a set of tools to read, search, and (optionally) write
22
+ notes. vault-memory handles the hard parts:
14
23
 
15
- One SQLite database per vault under `~/.vault-memory/vaults/<name>.db`. Three storage layers: **raw** (notes, chunks — permanent, model-agnostic), **derived** (embeddings via sqlite-vec, FTS5, wikilinks regenerable from raw), **audit** (index runs, write history). Embeddings via Ollama HTTP. Cross-vault search via Reciprocal Rank Fusion in the query layer. Per-model `embeddings_m<id>_d<dim>` vec0 tables let multiple embedding models coexist for shadow-indexing and seamless model upgrades.
24
+ - **Hybrid retrieval** — semantic search over local embeddings, BM25 full-text search,
25
+ and Reciprocal Rank Fusion to merge them. Optional cross-encoder reranking for the
26
+ hardest queries.
27
+ - **Live indexing** — a file-watcher picks up changes the moment you save a note in
28
+ Obsidian. No manual re-index.
29
+ - **Multi-vault** — multiple vaults can be registered; search fans out by default and
30
+ merges results, or you can scope to one.
31
+ - **Graph awareness** — wikilinks, backlinks, broken-link detection, Obsidian-style
32
+ aliases.
33
+ - **Atomic, hash-protected writes** — the agent can edit notes, but only with explicit
34
+ opt-in and with concurrency control so it can't clobber your edits.
16
35
 
17
- ## Embedding model recommendation
36
+ ## What it provides
18
37
 
19
- Eval-v2 (May 2026) compared two multilingual Ollama-hosted embedding models on a 187-note real-world German+English vault:
38
+ ### MCP tools (23)
20
39
 
21
- | Model | Size | Dim | Verdict |
22
- |---|---|---|---|
23
- | **`bge-m3`** ⭐ | 1.1 GB | 1024 | **Recommended default.** Materially better at concept-paraphrase queries; finds the right note where qwen3 returns generic tool pages. MIT-licensed. |
24
- | `qwen3-embedding:0.6b` | 600 MB | 1024 | Low-RAM fallback. OK for direct keyword matches, weak on conceptual queries. Apache 2.0. |
25
- | `embeddinggemma:300m` | 600 MB | 768 | Not benchmarked yet — promising for laptops with <8 GB free RAM. Gemma 3 license. |
40
+ **Discovery & read**
41
+ - `list_vaults`, `read_note`
26
42
 
27
- See `vault-memory-eval-v2-results.md` for the full per-query benchmark table.
43
+ **Search**
44
+ - `search_semantic`, `search_text`, `search_hybrid` — all support optional
45
+ `exclude_paths` (glob) and an explicit `vaults` filter. Responses include a `note`
46
+ field when vaults were skipped (e.g. mid-indexing).
28
47
 
29
- ## Reranker — real ONNX cross-encoder (Phase 8)
48
+ **Graph**
49
+ - `list_backlinks`, `list_forward_links`, `find_broken_links`
30
50
 
31
- Replaces the v0.7.x L2-norm hack with a real cross-encoder forward pass over **BAAI/bge-reranker-v2-m3** (ONNX INT8, ≈570 MB) via `onnxruntime-node` + `@huggingface/tokenizers`. Sigmoid-of-logit gives a true [0, 1] relevance score per (query, chunk) pair, matching the `Reranker` contract directly. v0.8.1 fixed the tokenizer-constructor API (Hugging Face needs `Tokenizer(tokenizerJson, config)`) and added a near-empty-chunk pre-filter so the rerank pool isn't diluted by degenerate inputs.
51
+ **Frontmatter**
52
+ - `query_frontmatter` — safe JSON-path DSL
32
53
 
33
- Setup (one-time):
54
+ **Write (hash-protected, atomic)**
55
+ - `write_note`, `update_frontmatter`, `delete_note`
34
56
 
35
- ```bash
36
- bash scripts/download-reranker.sh # ≈590 MB into ~/.vault-memory/models/bge-reranker-v2-m3/
37
- ```
57
+ **Audit**
58
+ - `audit_log`, `index_runs`
38
59
 
39
- Then in `~/.vault-memory/config.toml`:
60
+ **Model management**
61
+ - `list_models`, `start_shadow_index`, `switch_active_model`
40
62
 
41
- ```toml
42
- [server]
43
- reranker_model = "bge-reranker-v2-m3"
44
- reranker_backend = "onnx" # default when reranker_model is set
45
- # reranker_model_dir = "..." # optional override; defaults to ~/.vault-memory/models/bge-reranker-v2-m3
46
- ```
63
+ **Maintenance**
64
+ - `vacuum_embeddings` — drop orphaned embedding rows whose `chunk_id` no longer exists
47
65
 
48
- Reranking remains **opt-in per query** via `rerank: true` in `search_hybrid`. The ONNX session loads lazily on the first reranked query, so users who never set `rerank: true` pay zero startup cost.
66
+ **Agent compatibility (OB1 / Custom Connectors)**
67
+ - `search`, `fetch` — flat-shape adapters for ChatGPT Custom Connectors, Claude.ai,
68
+ and Deep-Research modes. Backed by the same hybrid pipeline, so connector users get
69
+ full search quality through the standardized shape.
49
70
 
50
- The legacy `OllamaReranker` (L2-norm proxy) stays available via `reranker_backend = "ollama"` for back-compat, but is no longer recommended.
71
+ **Agent self-orientation**
72
+ - `vault_stats` — note count, top tags, top frontmatter keys, last index run
73
+ - `recent_notes` — most-recently-modified notes (mtime DESC). Use on first connect to
74
+ brief an agent on what's in the vault and what the user has been working on.
51
75
 
52
- ## Search scope (v0.8.1)
76
+ **Schema inference (v0.10.0)**
77
+ - `suggest_frontmatter` — for an existing note (by `path`) or a draft (by `content +
78
+ folder_hint`), returns `{existing, suggestions, conflicts}` with calibrated confidence
79
+ per source. Three independent layers contribute:
80
+ - **folder-conventions** — frequency of frontmatter keys in sibling notes (same folder
81
+ prefix). Walks up one level when sibling count <3. Confidence = prevalence.
82
+ - **neighbor-inference** — frontmatter aggregate across wikilink-linked neighbors
83
+ (forward + backlink, deduped). Confidence = prevalence × 0.6 (dampened, since
84
+ indirect).
85
+ - **content-heuristics** — vault-agnostic title/body regex matchers for Email, Meeting,
86
+ Person, Clipping, Fact, and date-prefix patterns. Confidence fixed per rule.
87
+ Conflicts surface when sources disagree on a value. Existing-vs-suggested mismatches
88
+ are also flagged. No LLM, no embeddings.
53
89
 
54
- By default with multiple vaults configured — `search_*` tools fan out across all of them and merge via RRF. Two new mechanisms scope this:
90
+ ### Claude Code skills
55
91
 
56
- **`VAULT_MEMORY_ACTIVE_VAULT` env var** — set per consumer (in `.mcp.json`'s `env` block) to default search to one vault. Explicit `vaults: [...]` in the request still overrides; cross-vault stays opt-in.
92
+ Five skills bundled in `skills/`, installable into any vault with one curl-pipe:
57
93
 
58
- ```json
59
- {
60
- "mcpServers": {
61
- "vault-memory": {
62
- "type": "stdio",
63
- "command": "vault-memory",
64
- "args": ["serve"],
65
- "env": { "VAULT_MEMORY_ACTIVE_VAULT": "myvault" }
66
- }
67
- }
68
- }
69
- ```
94
+ | Skill | What it does | When to invoke |
95
+ |---|---|---|
96
+ | **`install-vault-memory/`** | The complete installer — 8 idempotent checkpoints from Homebrew through MCP smoketest. Defaults to autonomous mode with a `why:` line on every install prompt. Re-running on a working setup verifies state in under 5 seconds and exits. | First-time setup of a vault, or repairing a broken state. `/install-vault-memory` |
97
+ | **`add-vault/`** | Wraps `vault-memory add-vault` CLI with a confirmation flow — appends to `config.toml`, writes `.mcp.json`, builds the initial index. Atomic and idempotent. | Adding a *second or third* vault after vault-memory is already installed. `/add-vault` |
98
+ | **`audit-vault-health/`** | Read-only vault health audit — overview stats, broken wikilinks, tag drift (case/separator variants), frontmatter schema drift, indexing freshness. Pure read, never modifies notes. | Quarterly check, before relying on search after bulk import. `/audit-vault-health` |
99
+ | **`find-stale-notes/`** | Discovers notes >6 mo old with 0 backlinks. Presents candidates as a sortable table, walks through each one with per-note actions (Archive / Update / Delete / Skip / Keep). Hash-protected deletes; never bulk-acts. | Vault cleanup, after import-bursts. `/find-stale-notes` |
100
+ | **`triage-inbox/`** | Walks through recent inbox-stage notes (sparse frontmatter, few tags, recent mtime). Per note: suggests target folder, tags, frontmatter, related wikilinks — based on semantic search against the rest of the vault. User accepts / edits / skips per note. | After a capture-burst (voice memos, web clippings, meeting transcripts). `/triage-inbox` |
70
101
 
71
- **Mid-index skip** — vaults with an unfinished `index_runs` row (i.e. an index is still embedding chunks) are excluded from the implicit candidate set so half-indexed chunks don't pollute results. Skipped vaults are listed in a `note` field on the response. Explicit `vaults: ["…"]` still passes through if you want to query a mid-indexing vault on purpose.
102
+ ## Requirements
72
103
 
73
- ## Adding a vault
104
+ Tested on macOS. Linux should work; Windows untested.
74
105
 
75
- For the first vault, follow [Install (recommended)](#install-recommended) below.
76
- For every additional vault — one command:
106
+ | What | Why | How |
107
+ |---|---|---|
108
+ | **Node.js ≥ 22** | Runtime for the MCP server. | `brew install node@22` |
109
+ | **[Ollama](https://ollama.com)** running on `localhost:11434` | Local embedding model host. No cloud API. | `brew install ollama && brew services start ollama` |
110
+ | **An embedding model** — default `bge-m3` (≈1.1 GB) | Generates the vectors that power semantic search. | `ollama pull bge-m3` |
111
+ | **Disk space** — ~1.2 GB for the embedding model, ~1× your vault size for the SQLite index | Models and the per-vault DB under `~/.vault-memory/`. | — |
112
+ | **(Optional) ONNX reranker** — `bge-reranker-v2-m3` (≈570 MB) | Cross-encoder reranking for `search_hybrid` when `rerank: true`. Lazy-loaded — zero cost if you never use it. | `bash scripts/download-reranker.sh` |
113
+ | **An MCP-aware client** — Claude Code, Claude desktop, ChatGPT Custom Connector, etc. | The agent that consumes the MCP tools. | — |
114
+ | **One or more Obsidian vaults** | What you're actually indexing. | — |
77
115
 
78
- ```bash
79
- vault-memory add-vault "/path/to/another/obsidian/vault"
80
- ```
116
+ ### Embedding-model recommendation
81
117
 
82
- This appends a `[[vaults]]` block to `~/.vault-memory/config.toml`, writes a `.mcp.json` into the vault root (so Claude Code auto-spawns the MCP server when you open it), and runs the initial index. Idempotent — re-running on a known path only fills in whatever is missing.
118
+ Eval-v2 (May 2026) compared two multilingual Ollama-hosted embedding models on a
119
+ 187-note real-world German+English vault:
83
120
 
84
- Flags: `--name <slug>` to override the auto-slugified basename, `--write` to enable MCP writes (default read-only), `--no-index` to skip the initial index. Inside Claude Code you can also use the `/add-vault` skill which wraps the same CLI with confirmation prompts.
121
+ | Model | Size | Dim | Verdict |
122
+ |---|---|---|---|
123
+ | **`bge-m3`** ⭐ | 1.1 GB | 1024 | **Recommended default.** Materially better at concept-paraphrase queries; finds the right note where qwen3 returns generic tool pages. MIT-licensed. |
124
+ | `qwen3-embedding:0.6b` | 600 MB | 1024 | Low-RAM fallback. OK for direct keyword matches, weak on conceptual queries. Apache 2.0. |
125
+ | `embeddinggemma:300m` | 600 MB | 768 | Not benchmarked yet — promising for laptops with <8 GB free RAM. Gemma 3 license. |
126
+
127
+ See `vault-memory-eval-v2-results.md` for the full per-query benchmark table.
128
+
129
+ ## Install
85
130
 
86
- ## Install (recommended)
131
+ ### Recommended — npm
87
132
 
88
133
  ```bash
89
134
  # 1) Homebrew (system-level)
@@ -105,13 +150,29 @@ npm install -g @owrede/vault-memory
105
150
  vault-memory add-vault "/Users/you/Documents/Obsidian Vaults/My Vault"
106
151
  ```
107
152
 
108
- The MCP-host config (`.mcp.json` in the consuming vault) calls the `vault-memory` binary, so any shell with it on `$PATH` will work. Future upgrades: `npm install -g @owrede/vault-memory@latest`.
153
+ The MCP-host config (`.mcp.json` in the consuming vault) calls the `vault-memory`
154
+ binary, so any shell with it on `$PATH` works. Future upgrades:
155
+
156
+ ```bash
157
+ npm install -g @owrede/vault-memory@latest
158
+ ```
159
+
160
+ ### Guided install from inside Claude Code
161
+
162
+ If you'd rather not run the steps by hand, install the skills first and let
163
+ `/install-vault-memory` walk you through it:
164
+
165
+ ```bash
166
+ curl -fsSL https://raw.githubusercontent.com/owrede/vault-memory/main/scripts/install-skills.sh \
167
+ | bash -s -- "/path/to/your/obsidian/vault"
168
+ ```
109
169
 
110
- For a guided install from inside Claude Code, see the `skills/` directory in this repo they bundle the install, vault registration, and end-to-end smoketest behind a single command.
170
+ Open the vault in Claude Code, then run `/install-vault-memory` — it executes the
171
+ same 6 steps above as 8 idempotent checkpoints, with a `why:` line on every prompt.
111
172
 
112
173
  ### Install from source (developer mode)
113
174
 
114
- Only needed if you want to modify vault-memory itself. Otherwise use the npm install above.
175
+ Only needed if you want to modify vault-memory itself.
115
176
 
116
177
  ```bash
117
178
  cd ~/Documents/GitHub
@@ -120,14 +181,22 @@ cd vault-memory
120
181
  npm install && npm run build && npm link # creates the global `vault-memory` binary
121
182
  ```
122
183
 
123
- ## Skills (Claude Code integration)
184
+ ## Adding a second (or third…) vault
124
185
 
125
- The `skills/` directory contains two Claude Code skills you can drop into any vault's `.claude/skills/` folder. They are the user-facing way to install and operate vault-memory without remembering CLI flags.
186
+ One command:
126
187
 
127
- | Skill | What it does | When to invoke |
128
- |---|---|---|
129
- | **`install-vault-memory/`** | The complete installer — 8 idempotent checkpoints from Homebrew through MCP smoketest. Defaults to autonomous mode with a `why:` line on every install prompt. Re-running on a working setup verifies state in under 5 seconds and exits. | First-time setup of a vault, or repairing a broken state. `/install-vault-memory` |
130
- | **`add-vault/`** | Wraps `vault-memory add-vault` CLI with a confirmation flow — appends to `config.toml`, writes `.mcp.json`, builds the initial index. Atomic and idempotent. | Adding a *second or third* vault after vault-memory is already installed. `/add-vault` |
188
+ ```bash
189
+ vault-memory add-vault "/path/to/another/obsidian/vault"
190
+ ```
191
+
192
+ This appends a `[[vaults]]` block to `~/.vault-memory/config.toml`, writes a `.mcp.json`
193
+ into the vault root (so Claude Code auto-spawns the MCP server when you open it), and
194
+ runs the initial index. Idempotent — re-running on a known path only fills in whatever
195
+ is missing.
196
+
197
+ Flags: `--name <slug>` to override the auto-slugified basename, `--write` to enable
198
+ MCP writes (default read-only), `--no-index` to skip the initial index. Inside Claude
199
+ Code, the `/add-vault` skill wraps the same CLI with confirmation prompts.
131
200
 
132
201
  ### Installing the skills in a vault
133
202
 
@@ -144,19 +213,91 @@ Or, from inside the vault's root directory:
144
213
  curl -fsSL https://raw.githubusercontent.com/owrede/vault-memory/main/scripts/install-skills.sh | bash
145
214
  ```
146
215
 
147
- The script is idempotent — re-running it fetches the latest skill versions from `main` and overwrites the local copies. Use it to update your skills whenever vault-memory ships a new release.
216
+ The script is idempotent — re-running it fetches the latest skill versions from
217
+ `main` and overwrites the local copies. Use it to update your skills whenever
218
+ vault-memory ships a new release.
148
219
 
149
220
  If you cloned the source repo, you can also copy directly:
150
221
 
151
222
  ```bash
152
- cp -R ~/Documents/GitHub/vault-memory/skills/{install-vault-memory,add-vault} .claude/skills/
223
+ cp -R ~/Documents/GitHub/vault-memory/skills/{install-vault-memory,add-vault,audit-vault-health,find-stale-notes,triage-inbox} .claude/skills/
153
224
  ```
154
225
 
155
- After Claude Code restarts, `/install-vault-memory` and `/add-vault` are available as slash commands in that vault.
156
-
157
226
  ### Autonomous mode
158
227
 
159
- `VAULT_MEMORY_AUTO=1` switches `install-vault-memory/setup.sh` to non-interactive mode: every non-destructive `confirm()` prompt auto-answers yes, with a `why:` line explaining what is being installed and why vault-memory needs it. Destructive operations (overwriting an existing multi-vault `config.toml`, rebuilding a clone with uncommitted changes) still prompt. This is the default when the skill is invoked via `/install-vault-memory`; direct invocation of `setup.sh` defaults to fully-interactive mode.
228
+ `VAULT_MEMORY_AUTO=1` switches `install-vault-memory/setup.sh` to non-interactive
229
+ mode: every non-destructive `confirm()` prompt auto-answers yes, with a `why:` line
230
+ explaining what is being installed and why vault-memory needs it. Destructive
231
+ operations (overwriting an existing multi-vault `config.toml`, rebuilding a clone with
232
+ uncommitted changes) still prompt. This is the default when the skill is invoked via
233
+ `/install-vault-memory`; direct invocation of `setup.sh` defaults to fully-interactive
234
+ mode.
235
+
236
+ ## Architecture in one paragraph
237
+
238
+ One SQLite database per vault under `~/.vault-memory/vaults/<name>.db`. Three storage
239
+ layers: **raw** (notes, chunks — permanent, model-agnostic), **derived** (embeddings
240
+ via sqlite-vec, FTS5, wikilinks — regenerable from raw), **audit** (index runs, write
241
+ history). Embeddings via Ollama HTTP. Cross-vault search via Reciprocal Rank Fusion in
242
+ the query layer. Per-model `embeddings_m<id>_d<dim>` vec0 tables let multiple embedding
243
+ models coexist for shadow-indexing and seamless model upgrades.
244
+
245
+ ## Reranker — real ONNX cross-encoder
246
+
247
+ A real cross-encoder forward pass over **BAAI/bge-reranker-v2-m3** (ONNX INT8,
248
+ ≈570 MB) via `onnxruntime-node` + `@huggingface/tokenizers`. Sigmoid-of-logit gives a
249
+ true `[0, 1]` relevance score per `(query, chunk)` pair, matching the `Reranker`
250
+ contract directly.
251
+
252
+ Setup (one-time):
253
+
254
+ ```bash
255
+ bash scripts/download-reranker.sh # ≈590 MB into ~/.vault-memory/models/bge-reranker-v2-m3/
256
+ ```
257
+
258
+ Then in `~/.vault-memory/config.toml`:
259
+
260
+ ```toml
261
+ [server]
262
+ reranker_model = "bge-reranker-v2-m3"
263
+ reranker_backend = "onnx" # default when reranker_model is set
264
+ # reranker_model_dir = "..." # optional override; defaults to ~/.vault-memory/models/bge-reranker-v2-m3
265
+ ```
266
+
267
+ Reranking remains **opt-in per query** via `rerank: true` in `search_hybrid`. The ONNX
268
+ session loads lazily on the first reranked query, so users who never set
269
+ `rerank: true` pay zero startup cost.
270
+
271
+ The legacy `OllamaReranker` (L2-norm proxy) stays available via
272
+ `reranker_backend = "ollama"` for back-compat, but is no longer recommended.
273
+
274
+ ## Search scope
275
+
276
+ By default — with multiple vaults configured — `search_*` tools fan out across all of
277
+ them and merge via RRF. Two mechanisms scope this:
278
+
279
+ **`VAULT_MEMORY_ACTIVE_VAULT` env var** — set per consumer (in `.mcp.json`'s `env`
280
+ block) to default search to one vault. Explicit `vaults: [...]` in the request still
281
+ overrides; cross-vault stays opt-in.
282
+
283
+ ```json
284
+ {
285
+ "mcpServers": {
286
+ "vault-memory": {
287
+ "type": "stdio",
288
+ "command": "vault-memory",
289
+ "args": ["serve"],
290
+ "env": { "VAULT_MEMORY_ACTIVE_VAULT": "myvault" }
291
+ }
292
+ }
293
+ }
294
+ ```
295
+
296
+ **Mid-index skip** — vaults with an unfinished `index_runs` row (i.e. an index is
297
+ still embedding chunks) are excluded from the implicit candidate set so half-indexed
298
+ chunks don't pollute results. Skipped vaults are listed in a `note` field on the
299
+ response. Explicit `vaults: ["…"]` still passes through if you want to query a
300
+ mid-indexing vault on purpose.
160
301
 
161
302
  ## Configuration
162
303
 
@@ -166,9 +307,9 @@ After Claude Code restarts, `/install-vault-memory` and `/add-vault` are availab
166
307
  [server]
167
308
  log_level = "info"
168
309
  ollama_endpoint = "http://localhost:11434"
169
- default_embedding_model = "bge-m3" # recommended default since v0.7.3
310
+ default_embedding_model = "bge-m3"
170
311
 
171
- # Optional: cross-encoder reranker (Phase 8). Run scripts/download-reranker.sh
312
+ # Optional: cross-encoder reranker. Run scripts/download-reranker.sh
172
313
  # first to fetch the ONNX model. See the "Reranker" section above for details.
173
314
  # reranker_model = "bge-reranker-v2-m3"
174
315
  # reranker_backend = "onnx" # default when reranker_model is set
@@ -185,42 +326,46 @@ exclude_globs = [".obsidian/**", ".trash/**", "_research/**", ".claude/**"]
185
326
  # secondary_embedding_model = "qwen3-embedding:0.6b"
186
327
  ```
187
328
 
188
- ## MCP tools (22)
189
-
190
- **Discovery & Read:** `list_vaults`, `read_note`
191
- **Search:** `search_semantic`, `search_text`, `search_hybrid` — all support optional `exclude_paths` (glob) and an explicit `vaults` filter; responses include a `note` field when vaults were skipped (e.g. mid-indexing)
192
- **Graph:** `list_backlinks`, `list_forward_links`, `find_broken_links`
193
- **Frontmatter:** `query_frontmatter`
194
- **Write:** `write_note`, `update_frontmatter`, `delete_note` (all hash-protected, atomic)
195
- **Audit:** `audit_log`, `index_runs`
196
- **Model management (Phase 7c):** `list_models`, `start_shadow_index`, `switch_active_model`
197
- **Maintenance (v0.7.3):** `vacuum_embeddings` — drop orphaned embedding rows whose chunk_id no longer exists
198
- **Agent-Compatibility (v0.9.0):** `search`, `fetch` — OB1-compatible flat-shape adapters for ChatGPT Custom Connectors, Claude.ai, and Deep-Research modes. Backed by the hybrid (semantic+BM25+RRF) retrieval pipeline, so connector users get vault-memory's full search quality through the standardized interface.
199
- **Agent self-orientation (v0.9.0):** `vault_stats`, `recent_notes` — vault overview (note count, top tags, top frontmatter keys, last index run) and recently-modified notes (mtime DESC). Use these on first connect to brief an agent on what's in the vault and what the user has been working on.
200
-
201
- ### Connector compatibility (v0.9.0)
329
+ ## Connector compatibility
202
330
 
203
- `search`/`fetch` follow the flat-shape spec used by OB1 and adopted by ChatGPT Custom Connectors / Claude.ai / Deep-Research:
331
+ `search` / `fetch` follow the flat-shape spec used by OB1 and adopted by ChatGPT
332
+ Custom Connectors / Claude.ai / Deep-Research:
204
333
 
205
334
  ```
206
335
  search({query, limit}) → { results: [{ id, title, url, snippet }] }
207
336
  fetch({id}) → { id, title, text, url, metadata }
208
337
  ```
209
338
 
210
- `id` is the opaque format `<vault>:<vault-relative-path>`. `url` is an `obsidian://open?…` URL — connectors render it as a clickable link that opens the note locally. Use the richer `search_hybrid` / `read_note` tools when working with a vault-memory-aware client (Claude Code's MCP integration); use `search` / `fetch` when integrating with a connector ecosystem that expects the standard shape.
339
+ `id` is the opaque format `<vault>:<vault-relative-path>`. `url` is an
340
+ `obsidian://open?…` URL — connectors render it as a clickable link that opens the
341
+ note locally. Use the richer `search_hybrid` / `read_note` tools when working with a
342
+ vault-memory-aware client (Claude Code's MCP integration); use `search` / `fetch`
343
+ when integrating with a connector ecosystem that expects the standard shape.
211
344
 
212
345
  ## Development
213
346
 
214
347
  ```bash
215
348
  npm install
216
349
  npm run dev # MCP server on stdio with hot reload
217
- npm test # 324 tests across 35 files (v0.9.1)
350
+ npm test # 324 tests across 35 files
218
351
  npm run build
219
352
  ```
220
353
 
221
- After a code change: `npm run build && git add dist/` — the bundle is tracked in git so users can `git pull && npm link` without needing devDependencies on every machine.
354
+ After a code change: `npm run build && git add dist/` — the bundle is tracked in git
355
+ so users can `git pull && npm link` without needing devDependencies on every machine.
356
+
357
+ The indexer is robust against malformed notes: gray-matter parse errors on a single
358
+ file (invalid YAML frontmatter, duplicate mapping keys, etc.) are logged and skipped,
359
+ not fatal to the whole vault run. The `IndexRunResult.notesSkipped` field surfaces the
360
+ count.
361
+
362
+ When shipping a user-visible change, **update `## [Unreleased]` in
363
+ [CHANGELOG.md](./CHANGELOG.md) in the same PR.** Release tags get cut from that
364
+ section — see the bottom of the changelog for the recipe.
365
+
366
+ ## Comparison to other memory systems
222
367
 
223
- The indexer is robust against malformed notes: gray-matter parse errors on a single file (invalid YAML frontmatter, duplicate mapping keys, etc.) are logged and skipped, not fatal to the whole vault run. The `IndexRunResult.notesSkipped` field surfaces the count.
368
+ _Coming soon._
224
369
 
225
370
  ## License
226
371