@owrede/vault-memory 0.9.2 → 1.0.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,91 +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.2** Vault-hygiene skill pack: three new Claude Code skills (`audit-vault-health`, `find-stale-notes`, `triage-inbox`) that compose the existing MCP tools into guided maintenance workflows. Pure-Markdown release no code changes in the server. Distributed via the existing `install-skills.sh` one-liner.
14
+ > See [CHANGELOG.md](./CHANGELOG.md) for release history. Latest: **v1.0.0**stable API; SemVer-locked.
10
15
 
11
- Previous releases:
12
- - **v0.9.1** — Body-hash short-circuit (migration 006): frontmatter-only edits no longer trigger chunk + embedding regeneration.
13
- - **v0.9.0** — Agent-Compatibility & Self-Orientation: OB1-compatible `search`/`fetch` tools, plus `vault_stats` and `recent_notes` for agent first-connect orientation.
16
+ ## What is vault-memory?
14
17
 
15
- ## 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:
16
23
 
17
- 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.
18
35
 
19
- ## Embedding model recommendation
36
+ ## What it provides
20
37
 
21
- Eval-v2 (May 2026) compared two multilingual Ollama-hosted embedding models on a 187-note real-world German+English vault:
38
+ ### MCP tools (23)
22
39
 
23
- | Model | Size | Dim | Verdict |
24
- |---|---|---|---|
25
- | **`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. |
26
- | `qwen3-embedding:0.6b` | 600 MB | 1024 | Low-RAM fallback. OK for direct keyword matches, weak on conceptual queries. Apache 2.0. |
27
- | `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`
28
42
 
29
- 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).
30
47
 
31
- ## Reranker — real ONNX cross-encoder (Phase 8)
48
+ **Graph**
49
+ - `list_backlinks`, `list_forward_links`, `find_broken_links`
32
50
 
33
- 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
34
53
 
35
- Setup (one-time):
54
+ **Write (hash-protected, atomic)**
55
+ - `write_note`, `update_frontmatter`, `delete_note`
36
56
 
37
- ```bash
38
- bash scripts/download-reranker.sh # ≈590 MB into ~/.vault-memory/models/bge-reranker-v2-m3/
39
- ```
57
+ **Audit**
58
+ - `audit_log`, `index_runs`
40
59
 
41
- Then in `~/.vault-memory/config.toml`:
60
+ **Model management**
61
+ - `list_models`, `start_shadow_index`, `switch_active_model`
42
62
 
43
- ```toml
44
- [server]
45
- reranker_model = "bge-reranker-v2-m3"
46
- reranker_backend = "onnx" # default when reranker_model is set
47
- # reranker_model_dir = "..." # optional override; defaults to ~/.vault-memory/models/bge-reranker-v2-m3
48
- ```
63
+ **Maintenance**
64
+ - `vacuum_embeddings` — drop orphaned embedding rows whose `chunk_id` no longer exists
49
65
 
50
- 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.
51
70
 
52
- 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.
53
75
 
54
- ## 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.
55
89
 
56
- 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
57
91
 
58
- **`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:
59
93
 
60
- ```json
61
- {
62
- "mcpServers": {
63
- "vault-memory": {
64
- "type": "stdio",
65
- "command": "vault-memory",
66
- "args": ["serve"],
67
- "env": { "VAULT_MEMORY_ACTIVE_VAULT": "myvault" }
68
- }
69
- }
70
- }
71
- ```
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` |
72
101
 
73
- **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
74
103
 
75
- ## Adding a vault
104
+ Tested on macOS. Linux should work; Windows untested.
76
105
 
77
- For the first vault, follow [Install (recommended)](#install-recommended) below.
78
- 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. | — |
79
115
 
80
- ```bash
81
- vault-memory add-vault "/path/to/another/obsidian/vault"
82
- ```
116
+ ### Embedding-model recommendation
83
117
 
84
- 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:
85
120
 
86
- 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.
87
128
 
88
- ## Install (recommended)
129
+ ## Install
130
+
131
+ ### Recommended — npm
89
132
 
90
133
  ```bash
91
134
  # 1) Homebrew (system-level)
@@ -107,13 +150,29 @@ npm install -g @owrede/vault-memory
107
150
  vault-memory add-vault "/Users/you/Documents/Obsidian Vaults/My Vault"
108
151
  ```
109
152
 
110
- 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
+ ```
111
169
 
112
- 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.
113
172
 
114
173
  ### Install from source (developer mode)
115
174
 
116
- 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.
117
176
 
118
177
  ```bash
119
178
  cd ~/Documents/GitHub
@@ -122,17 +181,22 @@ cd vault-memory
122
181
  npm install && npm run build && npm link # creates the global `vault-memory` binary
123
182
  ```
124
183
 
125
- ## Skills (Claude Code integration)
184
+ ## Adding a second (or third…) vault
126
185
 
127
- The `skills/` directory contains five 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:
128
187
 
129
- | Skill | What it does | When to invoke |
130
- |---|---|---|
131
- | **`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` |
132
- | **`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` |
133
- | **`audit-vault-health/`** (v0.9.2) | 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` |
134
- | **`find-stale-notes/`** (v0.9.2) | Discovers notes >6mo 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` |
135
- | **`triage-inbox/`** (v0.9.2) | 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` |
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. Idempotentre-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.
136
200
 
137
201
  ### Installing the skills in a vault
138
202
 
@@ -149,7 +213,9 @@ Or, from inside the vault's root directory:
149
213
  curl -fsSL https://raw.githubusercontent.com/owrede/vault-memory/main/scripts/install-skills.sh | bash
150
214
  ```
151
215
 
152
- 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.
153
219
 
154
220
  If you cloned the source repo, you can also copy directly:
155
221
 
@@ -157,11 +223,81 @@ If you cloned the source repo, you can also copy directly:
157
223
  cp -R ~/Documents/GitHub/vault-memory/skills/{install-vault-memory,add-vault,audit-vault-health,find-stale-notes,triage-inbox} .claude/skills/
158
224
  ```
159
225
 
160
- After Claude Code restarts, `/install-vault-memory` and `/add-vault` are available as slash commands in that vault.
161
-
162
226
  ### Autonomous mode
163
227
 
164
- `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.
165
301
 
166
302
  ## Configuration
167
303
 
@@ -171,9 +307,9 @@ After Claude Code restarts, `/install-vault-memory` and `/add-vault` are availab
171
307
  [server]
172
308
  log_level = "info"
173
309
  ollama_endpoint = "http://localhost:11434"
174
- default_embedding_model = "bge-m3" # recommended default since v0.7.3
310
+ default_embedding_model = "bge-m3"
175
311
 
176
- # Optional: cross-encoder reranker (Phase 8). Run scripts/download-reranker.sh
312
+ # Optional: cross-encoder reranker. Run scripts/download-reranker.sh
177
313
  # first to fetch the ONNX model. See the "Reranker" section above for details.
178
314
  # reranker_model = "bge-reranker-v2-m3"
179
315
  # reranker_backend = "onnx" # default when reranker_model is set
@@ -190,42 +326,79 @@ exclude_globs = [".obsidian/**", ".trash/**", "_research/**", ".claude/**"]
190
326
  # secondary_embedding_model = "qwen3-embedding:0.6b"
191
327
  ```
192
328
 
193
- ## MCP tools (22)
194
-
195
- **Discovery & Read:** `list_vaults`, `read_note`
196
- **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)
197
- **Graph:** `list_backlinks`, `list_forward_links`, `find_broken_links`
198
- **Frontmatter:** `query_frontmatter`
199
- **Write:** `write_note`, `update_frontmatter`, `delete_note` (all hash-protected, atomic)
200
- **Audit:** `audit_log`, `index_runs`
201
- **Model management (Phase 7c):** `list_models`, `start_shadow_index`, `switch_active_model`
202
- **Maintenance (v0.7.3):** `vacuum_embeddings` — drop orphaned embedding rows whose chunk_id no longer exists
203
- **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.
204
- **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.
329
+ ## Connector compatibility
205
330
 
206
- ### Connector compatibility (v0.9.0)
207
-
208
- `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:
209
333
 
210
334
  ```
211
335
  search({query, limit}) → { results: [{ id, title, url, snippet }] }
212
336
  fetch({id}) → { id, title, text, url, metadata }
213
337
  ```
214
338
 
215
- `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.
216
344
 
217
345
  ## Development
218
346
 
219
347
  ```bash
220
348
  npm install
221
349
  npm run dev # MCP server on stdio with hot reload
222
- npm test # 324 tests across 35 files (v0.9.1)
350
+ npm test # 324 tests across 35 files
223
351
  npm run build
224
352
  ```
225
353
 
226
- 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
367
+
368
+ _Coming soon._
369
+
370
+ ## Filing issues
371
+
372
+ Bug reports and feature requests are welcome. Open one via the
373
+ [Issues tab](https://github.com/owrede/vault-memory/issues/new/choose) —
374
+ two structured templates are available:
375
+
376
+ - **Bug report** — for things that are broken or misbehave. Include repro
377
+ steps, your `vault-memory` version, and a one-line severity assessment.
378
+ - **Feature request** — for new tools, behaviours, or skills. Describe the
379
+ use case and a concrete proposed shape.
380
+
381
+ Both templates auto-label the issue (`bug` / `enhancement`) and route into
382
+ the area-labels documented below. Anyone with a GitHub account can open
383
+ issues; the maintainer triages and labels.
384
+
385
+ ### Area labels
386
+
387
+ Issues are organised by which part of vault-memory they touch:
388
+
389
+ | Label | Scope |
390
+ |---|---|
391
+ | `area:search` | search_hybrid, search_semantic, search_text, search, fetch |
392
+ | `area:indexer` | catchup, watcher, body-hash short-circuit |
393
+ | `area:schema-inference` | suggest_frontmatter + folder/neighbor/content layers |
394
+ | `area:skills` | Claude Code skills bundled in `skills/` |
395
+ | `area:cli` | `vault-memory` CLI (serve, add-vault, index) |
396
+ | `area:graph` | wikilinks, backlinks, broken-link detection |
397
+ | `area:reranker` | ONNX cross-encoder reranker |
398
+ | `area:db-migration` | SQLite schema migrations, sqlite-vec |
227
399
 
228
- 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.
400
+ Plus the functional labels `eval`, `performance`, `breaking-change`,
401
+ `needs-repro`, `good-first-fix`.
229
402
 
230
403
  ## License
231
404