@owrede/vault-memory 0.8.2
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/LICENSE +21 -0
- package/README.md +190 -0
- package/dist/cli.js +5697 -0
- package/dist/cli.js.map +1 -0
- package/package.json +51 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Oliver Wrede
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
# vault-memory
|
|
2
|
+
|
|
3
|
+
Local-first semantic memory MCP server for Obsidian vaults.
|
|
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.
|
|
6
|
+
|
|
7
|
+
## Status
|
|
8
|
+
|
|
9
|
+
**v0.8.1** — Phase 8 (real ONNX cross-encoder reranker) + search-quality fixes. See `_research/vault-memory-spec.md` in a consuming vault for the design contract, `_research/vault-memory-eval-v2-results.md` for retrieval-quality benchmarks, and `_research/vault-memory-eval-v3-spec.md` for the planned reranker eval.
|
|
10
|
+
|
|
11
|
+
## Architecture in one paragraph
|
|
12
|
+
|
|
13
|
+
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.
|
|
14
|
+
|
|
15
|
+
## Embedding model recommendation
|
|
16
|
+
|
|
17
|
+
Eval-v2 (May 2026) compared two multilingual Ollama-hosted embedding models on a 187-note real-world German+English vault:
|
|
18
|
+
|
|
19
|
+
| Model | Size | Dim | Verdict |
|
|
20
|
+
|---|---|---|---|
|
|
21
|
+
| **`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. |
|
|
22
|
+
| `qwen3-embedding:0.6b` | 600 MB | 1024 | Low-RAM fallback. OK for direct keyword matches, weak on conceptual queries. Apache 2.0. |
|
|
23
|
+
| `embeddinggemma:300m` | 600 MB | 768 | Not benchmarked yet — promising for laptops with <8 GB free RAM. Gemma 3 license. |
|
|
24
|
+
|
|
25
|
+
See `vault-memory-eval-v2-results.md` for the full per-query benchmark table.
|
|
26
|
+
|
|
27
|
+
## Reranker — real ONNX cross-encoder (Phase 8)
|
|
28
|
+
|
|
29
|
+
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.
|
|
30
|
+
|
|
31
|
+
Setup (one-time):
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
bash scripts/download-reranker.sh # ≈590 MB into ~/.vault-memory/models/bge-reranker-v2-m3/
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Then in `~/.vault-memory/config.toml`:
|
|
38
|
+
|
|
39
|
+
```toml
|
|
40
|
+
[server]
|
|
41
|
+
reranker_model = "bge-reranker-v2-m3"
|
|
42
|
+
reranker_backend = "onnx" # default when reranker_model is set
|
|
43
|
+
# reranker_model_dir = "..." # optional override; defaults to ~/.vault-memory/models/bge-reranker-v2-m3
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
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.
|
|
47
|
+
|
|
48
|
+
The legacy `OllamaReranker` (L2-norm proxy) stays available via `reranker_backend = "ollama"` for back-compat, but is no longer recommended.
|
|
49
|
+
|
|
50
|
+
## Search scope (v0.8.1)
|
|
51
|
+
|
|
52
|
+
By default — with multiple vaults configured — `search_*` tools fan out across all of them and merge via RRF. Two new mechanisms scope this:
|
|
53
|
+
|
|
54
|
+
**`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.
|
|
55
|
+
|
|
56
|
+
```json
|
|
57
|
+
{
|
|
58
|
+
"mcpServers": {
|
|
59
|
+
"vault-memory": {
|
|
60
|
+
"type": "stdio",
|
|
61
|
+
"command": "vault-memory",
|
|
62
|
+
"args": ["serve"],
|
|
63
|
+
"env": { "VAULT_MEMORY_ACTIVE_VAULT": "myvault" }
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
**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.
|
|
70
|
+
|
|
71
|
+
## Adding a vault
|
|
72
|
+
|
|
73
|
+
For the first vault, follow [Install (recommended)](#install-recommended) below.
|
|
74
|
+
For every additional vault — one command:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
vault-memory add-vault "/path/to/another/obsidian/vault"
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
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.
|
|
81
|
+
|
|
82
|
+
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.
|
|
83
|
+
|
|
84
|
+
## Install (recommended)
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
# 1) Homebrew (system-level)
|
|
88
|
+
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
|
89
|
+
|
|
90
|
+
# 2) Node 22+
|
|
91
|
+
brew install node@22
|
|
92
|
+
|
|
93
|
+
# 3) Ollama + service
|
|
94
|
+
brew install ollama && brew services start ollama
|
|
95
|
+
|
|
96
|
+
# 4) Embedding model (~1.1 GB)
|
|
97
|
+
ollama pull bge-m3
|
|
98
|
+
|
|
99
|
+
# 5) Clone, build, link
|
|
100
|
+
cd ~/Documents/GitHub
|
|
101
|
+
gh repo clone owrede/vault-memory
|
|
102
|
+
cd vault-memory
|
|
103
|
+
npm install && npm run build && npm link # creates the global `vault-memory` binary
|
|
104
|
+
|
|
105
|
+
# 6) Register your first vault (creates config + .mcp.json + initial index)
|
|
106
|
+
vault-memory add-vault "/Users/you/Documents/Obsidian Vaults/My Vault"
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
The MCP-host config (`.mcp.json` in the consuming vault) calls the `vault-memory` binary, so any shell with it on `$PATH` will work.
|
|
110
|
+
|
|
111
|
+
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.
|
|
112
|
+
|
|
113
|
+
## Skills (Claude Code integration)
|
|
114
|
+
|
|
115
|
+
The `skills/` directory contains three 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.
|
|
116
|
+
|
|
117
|
+
| Skill | What it does | When to invoke |
|
|
118
|
+
|---|---|---|
|
|
119
|
+
| **`memory/`** | One-call orchestrator. Detects current state (system install? vault registered? index built? MCP server responding?) and autonomously runs the minimal set of steps to reach a working state. Asks the user only for destructive steps. | First-time setup, or repairing a broken state. `/memory` |
|
|
120
|
+
| **`setup-memory-system/`** | System-level install via 7 idempotent checkpoints: GitHub auth precheck, Homebrew, Node 22+, Ollama + service, embedding model (`bge-m3` default), `vault-memory` binary, end-to-end MCP smoketest. Honors `VAULT_MEMORY_AUTO=1` for non-interactive runs and includes a "why is this needed" reason for every install prompt. | Direct invocation when you only want the system layer. `/setup-memory-system` |
|
|
121
|
+
| **`add-vault/`** | Wraps `vault-memory add-vault` with a confirmation flow — appends to `config.toml`, writes `.mcp.json`, builds the initial index. Atomic and idempotent. | Adding an additional vault after the system is installed. `/add-vault` |
|
|
122
|
+
|
|
123
|
+
### Installing the skills in a vault
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
# From the consuming vault's root:
|
|
127
|
+
mkdir -p .claude/skills
|
|
128
|
+
cp -R ~/Documents/GitHub/vault-memory/skills/{memory,setup-memory-system,add-vault} .claude/skills/
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
After Claude Code restarts, `/memory`, `/setup-memory-system`, and `/add-vault` are available as slash commands in that vault.
|
|
132
|
+
|
|
133
|
+
### Autonomous mode
|
|
134
|
+
|
|
135
|
+
`VAULT_MEMORY_AUTO=1` switches `setup-memory-system/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 what the `memory/` orchestrator uses under the hood.
|
|
136
|
+
|
|
137
|
+
## Configuration
|
|
138
|
+
|
|
139
|
+
`~/.vault-memory/config.toml`:
|
|
140
|
+
|
|
141
|
+
```toml
|
|
142
|
+
[server]
|
|
143
|
+
log_level = "info"
|
|
144
|
+
ollama_endpoint = "http://localhost:11434"
|
|
145
|
+
default_embedding_model = "bge-m3" # recommended default since v0.7.3
|
|
146
|
+
|
|
147
|
+
# Optional: cross-encoder reranker (Phase 8). Run scripts/download-reranker.sh
|
|
148
|
+
# first to fetch the ONNX model. See the "Reranker" section above for details.
|
|
149
|
+
# reranker_model = "bge-reranker-v2-m3"
|
|
150
|
+
# reranker_backend = "onnx" # default when reranker_model is set
|
|
151
|
+
|
|
152
|
+
[[vaults]]
|
|
153
|
+
name = "myvault"
|
|
154
|
+
path = "/Users/me/Documents/Obsidian Vaults/My Vault"
|
|
155
|
+
write_enabled = true
|
|
156
|
+
exclude_globs = [".obsidian/**", ".trash/**", "_research/**", ".claude/**"]
|
|
157
|
+
|
|
158
|
+
# Optional: secondary model for shadow-indexing. The indexer embeds new
|
|
159
|
+
# chunks under BOTH models. Use `switch_active_model` once you're ready
|
|
160
|
+
# to promote.
|
|
161
|
+
# secondary_embedding_model = "qwen3-embedding:0.6b"
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## MCP tools (18)
|
|
165
|
+
|
|
166
|
+
**Discovery & Read:** `list_vaults`, `read_note`
|
|
167
|
+
**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)
|
|
168
|
+
**Graph:** `list_backlinks`, `list_forward_links`, `find_broken_links`
|
|
169
|
+
**Frontmatter:** `query_frontmatter`
|
|
170
|
+
**Write:** `write_note`, `update_frontmatter`, `delete_note` (all hash-protected, atomic)
|
|
171
|
+
**Audit:** `audit_log`, `index_runs`
|
|
172
|
+
**Model management (Phase 7c):** `list_models`, `start_shadow_index`, `switch_active_model`
|
|
173
|
+
**Maintenance (v0.7.3):** `vacuum_embeddings` — drop orphaned embedding rows whose chunk_id no longer exists
|
|
174
|
+
|
|
175
|
+
## Development
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
npm install
|
|
179
|
+
npm run dev # MCP server on stdio with hot reload
|
|
180
|
+
npm test # 278 tests across 33 files (v0.8.1)
|
|
181
|
+
npm run build
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
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.
|
|
185
|
+
|
|
186
|
+
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.
|
|
187
|
+
|
|
188
|
+
## License
|
|
189
|
+
|
|
190
|
+
MIT.
|