@owrede/vault-memory 0.10.0 → 2.0.0-rc.1

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.
Files changed (4) hide show
  1. package/README.md +192 -338
  2. package/dist/cli.js +14971 -5260
  3. package/dist/cli.js.map +1 -1
  4. package/package.json +19 -4
package/README.md CHANGED
@@ -1,284 +1,23 @@
1
1
  # vault-memory
2
2
 
3
- **Local-first semantic memory for Obsidian vaults, exposed to AI agents over MCP.**
3
+ **Local-first, source-agnostic-ready agentic knowledge layer over your Obsidian notes,
4
+ exposed to any MCP-aware agent.**
4
5
 
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
+ > See [CHANGELOG.md](./CHANGELOG.md) for release history. Latest: **v2.0.0** additive
7
+ > over v1.x; the 23 v1 tool names + input schemas are preserved byte-identical.
11
8
 
12
- Nothing leaves your machine. No cloud sync, no API keys, no telemetry.
13
-
14
- > See [CHANGELOG.md](./CHANGELOG.md) for release history. Latest: **v0.10.0**.
15
-
16
- ## What is vault-memory?
17
-
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:
23
-
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.
35
-
36
- ## What it provides
37
-
38
- ### MCP tools (23)
39
-
40
- **Discovery & read**
41
- - `list_vaults`, `read_note`
42
-
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).
47
-
48
- **Graph**
49
- - `list_backlinks`, `list_forward_links`, `find_broken_links`
50
-
51
- **Frontmatter**
52
- - `query_frontmatter` — safe JSON-path DSL
53
-
54
- **Write (hash-protected, atomic)**
55
- - `write_note`, `update_frontmatter`, `delete_note`
56
-
57
- **Audit**
58
- - `audit_log`, `index_runs`
59
-
60
- **Model management**
61
- - `list_models`, `start_shadow_index`, `switch_active_model`
62
-
63
- **Maintenance**
64
- - `vacuum_embeddings` — drop orphaned embedding rows whose `chunk_id` no longer exists
65
-
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.
70
-
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.
75
-
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.
89
-
90
- ### Claude Code skills
91
-
92
- Five skills bundled in `skills/`, installable into any vault with one curl-pipe:
93
-
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` |
101
-
102
- ## Requirements
103
-
104
- Tested on macOS. Linux should work; Windows untested.
105
-
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. | — |
115
-
116
- ### Embedding-model recommendation
117
-
118
- Eval-v2 (May 2026) compared two multilingual Ollama-hosted embedding models on a
119
- 187-note real-world German+English vault:
120
-
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.
9
+ ## 30-second example
128
10
 
129
- ## Install
130
-
131
- ### Recommended — npm
11
+ Install the CLI from npm, register a vault, and start the MCP server:
132
12
 
133
13
  ```bash
134
- # 1) Homebrew (system-level)
135
- /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
136
-
137
- # 2) Node 22+
138
- brew install node@22
139
-
140
- # 3) Ollama + service
141
- brew install ollama && brew services start ollama
142
-
143
- # 4) Embedding model (~1.1 GB)
144
- ollama pull bge-m3
145
-
146
- # 5) Install vault-memory from npm (public registry, no auth)
147
14
  npm install -g @owrede/vault-memory
148
-
149
- # 6) Register your first vault (creates config + .mcp.json + initial index)
150
- vault-memory add-vault "/Users/you/Documents/Obsidian Vaults/My Vault"
151
- ```
152
-
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
- ```
169
-
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.
172
-
173
- ### Install from source (developer mode)
174
-
175
- Only needed if you want to modify vault-memory itself.
176
-
177
- ```bash
178
- cd ~/Documents/GitHub
179
- gh repo clone owrede/vault-memory
180
- cd vault-memory
181
- npm install && npm run build && npm link # creates the global `vault-memory` binary
182
- ```
183
-
184
- ## Adding a second (or third…) vault
185
-
186
- One command:
187
-
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.
200
-
201
- ### Installing the skills in a vault
202
-
203
- One-liner — works from anywhere, installs into the specified vault:
204
-
205
- ```bash
206
- curl -fsSL https://raw.githubusercontent.com/owrede/vault-memory/main/scripts/install-skills.sh \
207
- | bash -s -- "/path/to/your/obsidian/vault"
208
- ```
209
-
210
- Or, from inside the vault's root directory:
211
-
212
- ```bash
213
- curl -fsSL https://raw.githubusercontent.com/owrede/vault-memory/main/scripts/install-skills.sh | bash
214
- ```
215
-
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.
219
-
220
- If you cloned the source repo, you can also copy directly:
221
-
222
- ```bash
223
- cp -R ~/Documents/GitHub/vault-memory/skills/{install-vault-memory,add-vault,audit-vault-health,find-stale-notes,triage-inbox} .claude/skills/
224
- ```
225
-
226
- ### Autonomous mode
227
-
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/
15
+ vault-memory add-vault "/path/to/your/obsidian/vault" --name notes
16
+ vault-memory serve
256
17
  ```
257
18
 
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.
19
+ Point an MCP-aware client at the `vault-memory` binary. For Claude Desktop, drop this
20
+ into `~/Library/Application Support/Claude/claude_desktop_config.json`:
282
21
 
283
22
  ```json
284
23
  {
@@ -286,86 +25,201 @@ overrides; cross-vault stays opt-in.
286
25
  "vault-memory": {
287
26
  "type": "stdio",
288
27
  "command": "vault-memory",
289
- "args": ["serve"],
290
- "env": { "VAULT_MEMORY_ACTIVE_VAULT": "myvault" }
28
+ "args": ["serve"]
291
29
  }
292
30
  }
293
31
  }
294
32
  ```
295
33
 
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.
301
-
302
- ## Configuration
303
-
304
- `~/.vault-memory/config.toml`:
305
-
306
- ```toml
307
- [server]
308
- log_level = "info"
309
- ollama_endpoint = "http://localhost:11434"
310
- default_embedding_model = "bge-m3"
311
-
312
- # Optional: cross-encoder reranker. Run scripts/download-reranker.sh
313
- # first to fetch the ONNX model. See the "Reranker" section above for details.
314
- # reranker_model = "bge-reranker-v2-m3"
315
- # reranker_backend = "onnx" # default when reranker_model is set
316
-
317
- [[vaults]]
318
- name = "myvault"
319
- path = "/Users/me/Documents/Obsidian Vaults/My Vault"
320
- write_enabled = true
321
- exclude_globs = [".obsidian/**", ".trash/**", "_research/**", ".claude/**"]
322
-
323
- # Optional: secondary model for shadow-indexing. The indexer embeds new
324
- # chunks under BOTH models. Use `switch_active_model` once you're ready
325
- # to promote.
326
- # secondary_embedding_model = "qwen3-embedding:0.6b"
327
- ```
328
-
329
- ## Connector compatibility
34
+ Restart the client. Ask the agent something like: *"Pull me a brief for tomorrow's
35
+ 1:1 with Alice."* The agent discovers the bundled `meeting-prep` task contract via
36
+ `describe_contract`, instantiates it with `instantiate_contract`, and the result
37
+ attendees, recent shared notes, last decisions, open action items is written into
38
+ your vault's `_memory/_briefs/` folder with full provenance. The brief is a regular
39
+ note; you can read it, edit it, link to it, or delete it.
40
+
41
+ That is the full agentic-knowledge-layer loop: discover a contract, instantiate it,
42
+ get a cited document back. Memory writes are labeled and provenance-tracked; user
43
+ notes are never modified silently.
44
+
45
+ ## What this is
46
+
47
+ vault-memory turns one or more Obsidian vaults into a queryable, agent-native
48
+ knowledge layer running entirely on your machine. It indexes your notes with local
49
+ embeddings (via Ollama), keeps the index live as you edit, and exposes the result to
50
+ **any MCP-aware agent** Claude Code, Claude Desktop, ChatGPT Custom Connectors,
51
+ the MCP Inspector, or any other client speaking the
52
+ [Model Context Protocol](https://modelcontextprotocol.io).
53
+
54
+ v1.0.0 was a strong **retrieval substrate**: hybrid search (semantic + BM25 + RRF,
55
+ optional cross-encoder rerank), live indexing, multi-vault, hash-protected writes.
56
+ v2.0.0 evolves it into a full **agentic knowledge layer** — memory namespace with
57
+ provenance, document-tree assembly (bundles, outlines, dossiers), graph-as-retrieval
58
+ (typed edges, expand, cluster), a compiled-brief layer with a staleness daemon, and
59
+ a task-contract DSL that any MCP-aware agent can discover and instantiate.
60
+
61
+ Obsidian is the v2 source connector; the same MCP tool surface backs any future
62
+ adapter (Notion, Logseq, ...) via the `SourceConnector` / `DeliveryAdapter` /
63
+ `ChangeFeed` seams introduced in Phase 1. The memory namespace is a non-negotiable
64
+ safety invariant: agents never write silently into user notes; every agent-authored
65
+ document carries provenance properties and lives in a labeled `MemorySink`.
330
66
 
331
- `search` / `fetch` follow the flat-shape spec used by OB1 and adopted by ChatGPT
332
- Custom Connectors / Claude.ai / Deep-Research:
67
+ Nothing leaves your machine. No cloud sync, no API keys, no telemetry.
333
68
 
69
+ ## Architecture
70
+
71
+ One SQLite database per vault under `~/.vault-memory/vaults/<name>.db`. Layers L0
72
+ through L4 sit on top of an Adapter tier that abstracts the source-of-truth. v2.0.0
73
+ ships exactly one adapter implementation (`obsidian-fs`); v3.0.0 adds `notion-api`
74
+ without touching the layers above the seam.
75
+
76
+ ```text
77
+ +-----------------------------------------------------------------------------+
78
+ | L4 Compiled briefs + Task contracts (Phases 5, 6) |
79
+ | compile_brief . get_brief . instantiate_contract . staleness daemon |
80
+ +-----------------------------------------------------------------------------+
81
+ | L3 Assembly (bundles, outlines, dossiers, authority + staleness) |
82
+ | get_document_bundle . get_outline . search_sections . |
83
+ | assemble_dossier . authority + staleness signals (Phases 3, 4) |
84
+ +-----------------------------------------------------------------------------+
85
+ | L2 Memory namespace + provenance (Phase 2) |
86
+ | record_observation . recall . supersede . MemoryContract |
87
+ +-----------------------------------------------------------------------------+
88
+ | L1 Graph as retrieval (Phase 4) |
89
+ | typed edges . expand . cluster . backlink walks |
90
+ +-----------------------------------------------------------------------------+
91
+ | L0 Retrieval substrate (v1, behavior unchanged) |
92
+ | hybrid search (semantic + BM25 + RRF + rerank) . chunker |
93
+ +-----------------------------------------------------------------------------+
94
+ | Adapter tier (Phase 1) |
95
+ | SourceConnector . DeliveryAdapter . ChangeFeed . Registry |
96
+ +-----------------------------------------------------------------------------+
97
+ | Implementations |
98
+ | obsidian-fs (v2.0.0) | notion-api (v3, Phase 10) |
99
+ +-----------------------------------------------------------------------------+
334
100
  ```
335
- search({query, limit}) → { results: [{ id, title, url, snippet }] }
336
- fetch({id}) → { id, title, text, url, metadata }
337
- ```
338
-
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.
344
101
 
345
- ## Development
102
+ The Adapter tier is the only horizontal seam in the stack. Every layer above it
103
+ consumes canonical `Document` objects resolved through the registry; no upper layer
104
+ holds a reference to a concrete adapter module. L0 keeps direct database access
105
+ because it is substrate, not a consumer of `Document`s. See
106
+ [docs/v2/ARCHITECTURE.md](docs/v2/ARCHITECTURE.md) for the full layer model, the
107
+ adapter conformance suite, and the read/write data-flow diagrams.
108
+
109
+ ## What's new in v2
110
+
111
+ - **Phase 2 — Memory namespace + provenance.** Three new tools
112
+ (`record_observation`, `recall`, `supersede`); labeled `MemorySink` write guard;
113
+ default folder sink at `_memory/`; superseded-doc handling. See
114
+ [docs/v2/MEMORY_CONTRACT.md](docs/v2/MEMORY_CONTRACT.md).
115
+ - **Phase 3 — Assembly + authority/staleness.** Four new tools (`get_outline`,
116
+ `search_sections`, `get_document_bundle`, `assemble_dossier`); citation packets
117
+ on every result; recency/authority rescore params on `search_hybrid`;
118
+ superseded-doc filtering at SQL level. See
119
+ [docs/v2/PHASE-3-SIGN-OFF.md](docs/v2/PHASE-3-SIGN-OFF.md).
120
+ - **Phase 4 — Graph-as-retrieval.** Two new tools (`expand`, `cluster`); typed edges
121
+ table (`wikilink`, `mention`, `frontmatter-ref`, `hyperlink`); `search_hybrid`
122
+ gains an additive `expand` param attaching the typed-edge neighborhood to each
123
+ hit. See [docs/v2/PHASE-4-SIGN-OFF.md](docs/v2/PHASE-4-SIGN-OFF.md).
124
+ - **Phase 5 — Compiled brief layer + staleness daemon.** `compile_brief`,
125
+ `get_brief`, and `list_briefs`; per-brief `source_hashes` map; daemon marks
126
+ briefs stale when any source's hash drifts. See
127
+ [docs/v2/PHASE-5-SIGN-OFF.md](docs/v2/PHASE-5-SIGN-OFF.md).
128
+ - **Phase 6 — Task contract DSL + reference contracts.** Declarative YAML contracts
129
+ under `_contracts/<name>.yaml`; three new tools (`describe_contract`,
130
+ `instantiate_contract`, `register_contracts_as_tools`); three reference contracts
131
+ (`meeting-prep`, `project-status`, `code-review-brief`). See
132
+ [docs/v2/PHASE-6-SIGN-OFF.md](docs/v2/PHASE-6-SIGN-OFF.md).
133
+ - **Phase 7 — Obsidian plugin (default OFF).** Variant-C visual contract editor,
134
+ settings tab, secrets via OS keyring, manual reindex + stats panel, peer-MCP
135
+ connectors. Adds 6 gated tools when enabled. See
136
+ [docs/v2/plugin/README.md](docs/v2/plugin/README.md).
137
+ - **Tool surface delta.** 23 v1 tools become 32 canonical tools + 5 DEPRECATED
138
+ entries in `tools/list` (the 5 promoted list-style tools remain callable through
139
+ v2.x with a `DEPRECATED` notice in their `description`; removal scheduled for
140
+ v3.0.0). The raw `tools/list` therefore returns 37 entries; canonical
141
+ (non-deprecated) count = 32. Plugin OFF is the baseline; +6 gated tools when
142
+ enabled.
143
+ - **Resources delta.** 5 MCP Resources become 10 MCP Resources in v2.0.0
144
+ (`vaults`, `models`, `recent`, `stats`, `backlinks` added alongside the
145
+ pre-existing memory/brief/contract resources).
146
+
147
+ ## Roadmap
148
+
149
+ **Phase 9 — Pre-Phase-10 premise check (hard gate).** Before any v3 code is
150
+ written, a dedicated phase verifies that the architectural premise for the v3
151
+ multi-source line still holds: all Phase 1 CI greps (no `chokidar`, no
152
+ `gray-matter`, no raw paths, no `Claude` leak, no `obsidian://` literal outside
153
+ adapters) return zero hits on `main`; an adversarial-review sub-agent confirms
154
+ ADRs 001-004 remain unviolated by code shipped in Phases 2-8; the stub-adapter
155
+ conformance suite is green; capability-descriptor test coverage meets the
156
+ plugin-architecture threshold; the maintainer signs off explicitly. Without that
157
+ sign-off, no v3 code is written.
158
+
159
+ **v3.0.0 — Notion connector + multi-source proof.** Ship the first non-Obsidian
160
+ source/delivery/change-feed adapter (Notion), promoting the adapter seams from
161
+ "interfaces with one implementation" to a real plugin architecture. Resolve the
162
+ 14 open ADRs (005-01x) covering identity stability, link resolution, property
163
+ equivalence, granularity, write semantics, auth, watch, rate limits, embedding
164
+ strategy, cross-source memory, caching, sync, Notion sinks, and capability
165
+ discovery. Tracked requirements: NOT-01 through NOT-07; DMN-01 through DMN-03
166
+ (MCP daemon mode, v2.1.x or v3); TPC-01 through TPC-03 (third-party connectors,
167
+ post-v3). Status: deferred — gated by Phase 9 sign-off.
168
+
169
+ **Beyond v3 (ideas, not commitments).** A v3.x `postgres-fs` storage adapter is
170
+ sketched in the roadmap for users whose vaults outgrow local SQLite, with explicit
171
+ non-goals: still single-user-runtime, not a managed service, not pgvector
172
+ evangelism. A v4.0.0 multi-user direction is anticipated in the roadmap so v2's
173
+ opaque DocIds, adapter seams, content-stable ChunkIds, and provenance-on-every-
174
+ agent-write read as deliberate choices in service of that path. Neither is
175
+ committed work. See [.planning/ROADMAP.md](.planning/ROADMAP.md) for the full
176
+ phase plan and the v3/v4 deferred sections.
177
+
178
+ ## Install and docs
179
+
180
+ ### Prerequisites
181
+
182
+ - **Node.js >= 22** — runtime for the MCP server (`brew install node@22`).
183
+ - **[Ollama](https://ollama.com)** on `localhost:11434` — local embedding host
184
+ (`brew install ollama && brew services start ollama`).
185
+ - **`bge-m3`** embedding model (~1.1 GB) — vectors for semantic search
186
+ (`ollama pull bge-m3`).
187
+ - One or more Obsidian vaults — what you index.
188
+ - An MCP-aware client — the agent that consumes the tools.
189
+
190
+ Tested on macOS. Linux should work; Windows untested. Optional ONNX reranker
191
+ (`bge-reranker-v2-m3`, ~570 MB) via `bash scripts/download-reranker.sh`.
192
+
193
+ ### Install
346
194
 
347
195
  ```bash
348
- npm install
349
- npm run dev # MCP server on stdio with hot reload
350
- npm test # 324 tests across 35 files
351
- npm run build
196
+ npm install -g @owrede/vault-memory
197
+ vault-memory add-vault "/path/to/your/obsidian/vault"
198
+ vault-memory serve
352
199
  ```
353
200
 
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._
201
+ The `add-vault` command appends a `[[vaults]]` block to
202
+ `~/.vault-memory/config.toml`, writes a `.mcp.json` into the vault root, and runs
203
+ the initial index. Idempotent — re-running on a known path fills in whatever is
204
+ missing. Flags: `--name <slug>`, `--write` (enable MCP writes; default read-only),
205
+ `--no-index` (skip the initial index).
206
+
207
+ ### Documentation
208
+
209
+ - **Plugin install** [docs/v2/plugin/INSTALL.md](docs/v2/plugin/INSTALL.md)
210
+ - **Plugin README** — [docs/v2/plugin/README.md](docs/v2/plugin/README.md)
211
+ - **Migration v1 to v2** [docs/v2/MIGRATION-V1-TO-V2.md](docs/v2/MIGRATION-V1-TO-V2.md)
212
+ - **Architecture deep-dive** — [docs/v2/ARCHITECTURE.md](docs/v2/ARCHITECTURE.md)
213
+ - **Memory contract** [docs/v2/MEMORY_CONTRACT.md](docs/v2/MEMORY_CONTRACT.md)
214
+ - **Agent-agnostic statement** — [docs/v2/AGENT_AGNOSTIC.md](docs/v2/AGENT_AGNOSTIC.md)
215
+ - **ADR index** — [docs/v2/adr/README.md](docs/v2/adr/README.md)
216
+ - **Changelog** — [CHANGELOG.md](./CHANGELOG.md)
217
+
218
+ SemVer-locked tool API per the v1.0.0 declaration. v2.0.0 is additive: the 23 v1
219
+ tool names + input schemas are preserved byte-identical, and the 5 list-style
220
+ tools promoted to MCP Resources remain callable through v2.x with a `DEPRECATED`
221
+ notice in their tool description (removal scheduled for v3.0.0). See
222
+ [CHANGELOG.md](./CHANGELOG.md) for full history.
369
223
 
370
224
  ## License
371
225