cogvault 0.11.1__tar.gz

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.
@@ -0,0 +1,16 @@
1
+ # python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ dist/
6
+ build/
7
+ .venv/
8
+ .pytest_cache/
9
+
10
+ # cogvault derived index (never commit — rebuildable from markdown)
11
+ .cogvault.db
12
+ .cogvault.db-*
13
+
14
+ # local test artifacts
15
+ _test_tenant/
16
+ tenants/
@@ -0,0 +1,351 @@
1
+ # Changelog
2
+
3
+ ## 0.11.1 — 2026-10-05 — on PyPI and the MCP Registry
4
+
5
+ - **Published to PyPI** (`pip install cogvault`, `uvx cogvault mcp --tenant DIR`) and
6
+ listed in the official MCP Registry as `io.github.NBibikov/cogvault` (`server.json`).
7
+ - Releases are built, tested and published by `.github/workflows/publish.yml` on a
8
+ `v*` tag: PyPI via trusted publishing (no stored token), the registry via GitHub OIDC.
9
+ - README images and links are absolute, so the PyPI project page renders them.
10
+ - No code changes.
11
+
12
+ ## 0.11.0 — 2026-10-05 — judged on real queries
13
+
14
+ - **`cogvault eval`** scores recall against `<tenant>/.cogvault-golden.jsonl`
15
+ (`{query, relevant:[file,...]}`; empty `relevant` = a known memory gap). The
16
+ set lives with the tenant, never in this repo — it is made of private queries.
17
+ - **What the real-query set showed.** 65 queries sampled from the query log,
18
+ judged against the actual cards (answers searched outside the result pool too).
19
+ The 0.10 synthetic gain (hit@1 +0.2) did NOT reproduce: every configuration
20
+ landed within noise (paired bootstrap 95% CIs on ΔMRR all span zero). Real
21
+ agent queries read like card titles, which the old 128-token truncation
22
+ happened to serve well. e5-small + token-window chunks stays — it is what
23
+ makes facts deep inside long cards reachable at all — and:
24
+ - **Card summary chunk** (`summary_chunk`, on by default): frontmatter
25
+ `name — description` indexed as its own chunk. hit@5 0.877 → 0.923 on the real
26
+ set (better on 7 queries, worse on 3), found 4 answers the pre-0.10 index
27
+ never returned. Part of the `chunker` stamp, so tenants rebuild once.
28
+ - **Older processes never rebuild a newer index.** Indexes record the cogvault
29
+ version that rebuilt them (`writer`). A long-lived MCP server still running old
30
+ code now skips the rebuild with a warning instead of reverting the index to
31
+ its own model/chunker — the flapping seen during the 0.10 rollout.
32
+ - `fts_stem` (prefix-stemming Cyrillic terms in BM25) added as an experiment,
33
+ **off**: on the real set it was neutral-to-worse (hit@1 0.569 → 0.554).
34
+
35
+ ## 0.10.0 — 2026-10-05 — the vector channel could only see a third of memory
36
+
37
+ - **Chunks are fitted to the model's token window.** `paraphrase-multilingual-MiniLM`
38
+ truncates input at **128 tokens**; chunks were packed to 1500 characters
39
+ (~400-500 tokens of Ukrainian). On every multilingual tenant 91-94% of chunks
40
+ were over the limit and only ~35% of stored text was visible to the vector
41
+ channel — the rest was reachable by exact-keyword BM25 alone. Chunks are now
42
+ split (lines → sentences → words) until each fits the window minus the doc
43
+ prefix. Indexes stamp `chunker` in `meta`; a missing or different stamp
44
+ triggers one automatic full rebuild.
45
+ - **Embeddings are batched per file** instead of one ONNX run per chunk.
46
+ - **`intfloat/multilingual-e5-small` supported** (registered as a fastembed
47
+ custom model; 384-d, 512-token window), with automatic `query: `/`passage: `
48
+ prefixes for the e5 family (`query_prefix`/`doc_prefix` override them).
49
+ End-to-end hybrid eval over three live tenants, description and card-tail
50
+ queries, hit@1 averaged: old 0.655 → MiniLM+fit 0.796 → **e5-small, 700-char
51
+ chunks 0.855** (hit@5 ~0.86 → ~0.975).
52
+ - **Temporal decay uses the file's live age.** `chunks.age_days` froze at index
53
+ time, so cards untouched since the last rebuild decayed on a different clock
54
+ from freshly indexed ones (18 days of skew fleet-wide).
55
+ - **Migration backfills are no longer logged as card edits.** The v3 backfill
56
+ logged 1572 phantom `update` events — 88% of all edits the log had recorded.
57
+ - **Recalls carry a `cold` flag**; `analyze` splits model-load latency (~530 ms
58
+ p50) from warm search latency (~15 ms).
59
+ - **MCP server warms the index in a background thread**, so a full rebuild on
60
+ boot no longer blocks `initialize` past the client's timeout.
61
+ - **Write-path hardening:** an unclosed leading `---` no longer crashes
62
+ `cogvault_record`; frontmatter `name:` is slugified before becoming a filename
63
+ (`../` could escape the tenant); cards are created with `O_EXCL`, so concurrent
64
+ same-title records cannot overwrite each other; `cogvault_recall` validates
65
+ `query` and clamps `limit`.
66
+ - **Long paragraphs are split at whitespace**, not mid-word.
67
+ - **One result per card.** Smaller chunks let one long card fill top-k with its
68
+ own fragments; each file now contributes its best-ranked chunk only.
69
+ - **`cogvault repair`** — fixes the mechanical doctor findings (see README).
70
+ Fleet run on 2026-10-05: 51 cards repaired, legacy names 31 → 0, nested
71
+ frontmatter 12 → 0, untyped 21 → 0.
72
+ - **Link resolution accepts a missing type prefix** (`[[build-means-x]]` →
73
+ `feedback_build_means_x.md`), for recall's `Related:` line and for `doctor`.
74
+ `doctor` also stops flagging links inside code, paths to external files, and
75
+ targets that exist but are excluded from the index. Fleet ghost links: 195 → 104,
76
+ the remainder being cards that were never written.
77
+
78
+ ## 0.9.0 — 2026-09-01 — embedding-backend drift, honest metrics
79
+
80
+ The headline bug: **recall on every multilingual tenant had been silently
81
+ degrading for weeks**, and none of the existing metrics could show it.
82
+
83
+ - **Pinned the fastembed model cache.** `TextEmbedding` was constructed without
84
+ `cache_dir`, so fastembed unpacked its ONNX weights into `$TMPDIR`
85
+ (`/var/folders/...` on macOS). When the OS purged that, indexing and recall
86
+ died with `NoSuchFile: [ONNXRuntimeError] Load model from /var/folders/...` —
87
+ four such failures were sitting in the query log on two tenants.
88
+ Weights now live under `~/.cache/fastembed` (override:
89
+ `$FASTEMBED_CACHE_PATH`), next to the indexes they belong to.
90
+ - **Detect embedding-BACKEND drift, not just model drift.** `_model_mismatch()`
91
+ compared `model` + `dim`, which cannot catch a library that changes what a
92
+ model *outputs*. fastembed 0.6 switched MiniLM to mean pooling and stopped
93
+ L2-normalizing the multilingual model: same name, same 384 dims, different
94
+ vector space. A fleet audit found **35-50% of stored vectors on every
95
+ multilingual tenant diverging from freshly embedded text** (cos as low as
96
+ 0.198), with stored norms spanning 2.07-3.06 *within one database* while fresh
97
+ queries came out at norm ~5.3. vec0 ranks by L2, so those queries were ranked
98
+ largely by magnitude rather than meaning. Indexes now stamp
99
+ `backend = fastembed/<version>` into `meta` and treat a change as a mismatch.
100
+ A missing key means "pre-0.9.0, unknown" and does not trigger a surprise
101
+ re-embed — rebuild such tenants once with `reindex(full=True)` after clearing
102
+ `emb_cache`.
103
+ - **`dist` on every search result.** The RRF `score` is a rank reciprocal capped
104
+ at `2/rrf_k`: across 616 logged recalls its entire range was 0.016-0.033,
105
+ identical for a correct hit and for gibberish. Results (and the query log's
106
+ `top_dist` / `dists`) now carry the raw vector distance — the only logged value
107
+ that tracks relevance. It is comparable only *within* one tenant+backend.
108
+ - **`analyze` stops reporting two misleading numbers.** "avg top score" (an
109
+ average of rank reciprocals) is replaced by per-tenant `dist` p50/p90 plus a
110
+ **weakest-hits** list — each tenant's own worst decile, i.e. the queries that
111
+ returned something but probably not the right thing. "no-hit rate" is relabeled
112
+ "empty results" and annotated: a hybrid search returns the top-k of its
113
+ candidate pool, so it is ~always 0 and never meant "recall is healthy".
114
+ - **`cogvault_record` validates `content`.** A missing or blank field raised
115
+ `KeyError` deep inside `_write_card`, surfacing as an opaque `-32000
116
+ "'content'"` — the agent believed it had saved a memory that was never
117
+ written (one silent loss on a production tenant). Now a `-32602` naming the field.
118
+ - **Write-side telemetry now covers the path agents actually use.** `log_record`
119
+ fired only from the MCP `cogvault_record` tool, but almost nobody writes that
120
+ way: agents and the `/remember` skill write markdown files and then run
121
+ `cogvault index`. The log therefore showed 616 recalls against 24 records and
122
+ reported five busy tenants as read-only. `reindex()` — the one place that sees
123
+ both paths — now logs a `record` event per touched card with
124
+ `op` = `create` / `update` / `delete`. Three details keep the metric honest:
125
+ events are emitted only AFTER the COMMIT (a rollback must not claim writes
126
+ that never landed), a `full=True` re-embed logs nothing (otherwise a 572-card
127
+ tenant reports 572 fresh facts), and the MCP path no longer logs separately
128
+ (its own reindex covers it — logging both double-counted every tool write).
129
+ `analyze` splits `new cards` (creates, per tenant) from `card edits`, so a
130
+ tenant rewriting `project_state.md` daily can't drown out the real signal.
131
+ - **Model weights no longer live under `$XDG_CACHE_HOME`.** That variable is
132
+ redirected per test run and per sandbox to isolate *indexes*; tying the ~300 MB
133
+ ONNX download to it made every isolated run re-fetch the weights. Three
134
+ concurrent test processes each spent 25s+ downloading the same files, which is
135
+ what had been intermittently blowing the concurrency test's timeout. Indexes
136
+ belong to a tenant, weights belong to the machine. Suite: 35s and flaky → 2.9s
137
+ stable.
138
+ - **Silenced fastembed's mean-pooling warning** after verifying (post-rebuild)
139
+ that stored and fresh vectors match exactly; it fired on every CLI call and
140
+ buried real output in subagent scrollback.
141
+
142
+ ## 0.8.2 — 2026-07-28 — failure visibility & evergreen standing rules
143
+
144
+ - **`error` events in the query log.** Until now the log recorded only what
145
+ succeeded, so a broken tenant was indistinguishable from a forgetful agent:
146
+ an MCP recall that raised returned a JSON-RPC error to the caller and left no
147
+ trace, and a CLI recall died with a traceback into a subagent's scrollback.
148
+ Both paths now append one `{"event": "error", tenant, op, error, message}`
149
+ line via `obs.log_error()` before propagating. Failures are never swallowed —
150
+ the CLI still re-raises, the MCP server still answers `-32000`.
151
+ - **`analyze` surfaces failures.** An `errors` line (with a per-exception-type
152
+ breakdown and the last five failures) prints above the no-hit list, and
153
+ `errors` / `errors_by_type` appear in `--json`. Errors rank above no-hits
154
+ because a no-hit is a memory gap while an error is broken plumbing.
155
+ - **`feedback_*` cards are decay-exempt.** The default `evergreen_re` covered
156
+ `MEMORY`/`INDEX`/`reference_`/`architecture` but not `feedback_` — so on a
157
+ tenant with `half_life_days` set, standing rules ("never build unasked", "no
158
+ Android commits") sank below fresh session notes purely because nobody had
159
+ edited the file in months. On the largest tenant this exempted 200 more
160
+ chunks. Rebuild the index to recompute the flag on existing tenants.
161
+
162
+ ## 0.8.1 — 2026-07-08 — write-side telemetry & log hygiene
163
+
164
+ - **`record` events in the query log.** `cogvault_record` (MCP) now logs one
165
+ `{"event": "record", tenant, file, chars}` line next to recalls; `analyze`
166
+ prints a `records` line with a per-tenant breakdown (and `records` /
167
+ `records_by_tenant` in `--json`). Read-only tenants — agents that recall but
168
+ never record — are now visible at a glance.
169
+ - **No-hit nudge.** An empty recall is the exact moment an agent knows a memory
170
+ card is missing, so both the MCP "No matching memories found." response and
171
+ the CLI (stderr, keeping `--json` stdout clean) now suggest recording a card
172
+ after solving.
173
+ - **Query-log rotation.** The append-only log rotates to `.1` past 5 MB (one
174
+ generation kept) instead of growing unbounded across the fleet's lifetime.
175
+
176
+ ## 0.8.0 — 2026-07-02 — card types, wiki-links, schema v2
177
+
178
+ - **Card-type filter.** The YAML frontmatter `type` of each card (both the flat
179
+ `type: reference` and the nested `metadata:\n type: reference` shapes) is parsed
180
+ at index time — no YAML dependency, same minimal-parser philosophy as the TOML
181
+ reader — and stored per chunk. Filter recall with CLI `search --type <t>`, MCP
182
+ `cogvault_recall` `type` param, or `Vault.search(card_type=...)`. Every hit now
183
+ carries a `type` field (None for cards without frontmatter — legacy cards degrade
184
+ gracefully). Filtering post-filters 4×-deepened candidate pools (vec0 `MATCH`
185
+ can't take a joined WHERE); a very rare type buried below that depth can be
186
+ missed — documented limitation.
187
+ - **Wiki-link awareness.** `[[slug]]` / `[[slug|alias]]` / `[[slug#section]]`
188
+ targets are indexed into a `links` table; the TOP search result gains a
189
+ `related` list of linked card filenames that actually exist in the index
190
+ (ghost links dropped; exact stem match — case-variant links won't resolve).
191
+ CLI prints a `related:` line; MCP appends a `Related:` line to the first block.
192
+ - **Schema v2 with cheap automatic migration.** Existing v1 index DBs are upgraded
193
+ in place on first connect (race-safe `BEGIN IMMEDIATE` + re-check): `type`
194
+ column + `links` table added, and every `files` mtime is invalidated (keys kept
195
+ — deletion tracking must survive the migration, or files removed between the
196
+ last v1 index and the backfill would linger as searchable orphans) so the next
197
+ reindex backfills both — every embedding comes from `emb_cache`, so
198
+ **no re-embed**. Until that reindex runs, types are NULL (the MCP server
199
+ reindexes on boot).
200
+ - Query log records the `type` filter when used; regression test added for the
201
+ 0.7.1 `parent/basename` tenant label fix.
202
+ - Changelog repaired: entries for 0.5.0, 0.6.0 and 0.7.1 below were missing, and
203
+ ordering is now strictly descending.
204
+
205
+ ## 0.7.1 — 2026-07-02 — correctness & concurrency fixes
206
+
207
+ - **Per-(process, model) embedder registry.** A single global embedder silently
208
+ embedded other-model tenants with the wrong model and persisted poisoned vectors
209
+ into `emb_cache` — permanent silent recall degradation.
210
+ - **Model-mismatch wipe order.** FTS5 `delete-all` now runs BEFORE the content table
211
+ is cleared (the old order left stale postings misattributed to reused rowids);
212
+ a full rebuild clears ALL derived rows, not just paths known to `files`;
213
+ `emb_cache` survives the wipe (it is model-keyed, switching back stays cheap).
214
+ - **Reads don't stall behind reindex.** Embeddings are computed OUTSIDE the write
215
+ transaction; schema DDL + `user_version` stamp happen only on db creation, so the
216
+ read path takes no write lock.
217
+ - **Single-flight heal** per db + `Vault.join_heal()`; CLI search waits out a
218
+ triggered heal and retries once instead of leaving a broken index behind.
219
+ - **Loud stderr warnings**: unparsable/unusable `.cogvault.toml`, model mismatch on
220
+ reindex (full re-embed) and on search (unreliable vector ranking).
221
+ - **Tenant db key**: path realpath'd + casefolded on macOS/Windows — case-variant
222
+ spellings of one dir no longer maintain two flapping indexes.
223
+ - **Query-log tenant label** is now `parent/basename` (fleet tenants all named
224
+ `memory` were indistinguishable); `analyze` matches legacy labels too.
225
+ - **MCP**: `serverInfo` reports the real version, JSON-RPC notifications are not
226
+ answered, `ping` supported; `record` cards get frontmatter and collision-safe
227
+ filenames.
228
+ - Oversized paragraphs hard-split at `chunk_chars` so their tails stay visible to
229
+ the vector channel; minimal-TOML parser respects `#` inside quotes.
230
+ - Tests: `conftest` isolates the cache dir and query log from the real `~/.cache`
231
+ (tests had leaked 249 MB of dbs); regressions for the embedder registry, FTS wipe
232
+ order, and orphan purge.
233
+
234
+ ## 0.7.0 — 2026-06-28 — per-tenant config
235
+
236
+ - **`.cogvault.toml` per-tenant config.** A tenant can now declare its embedding
237
+ model (and other `Config` fields) in a `.cogvault.toml` at the tenant root, so the
238
+ model travels WITH the data instead of relying on every caller exporting
239
+ `COGVAULT_MODEL`. A bare `cogvault search --tenant <dir>` now picks up the right
240
+ model automatically. Without this, omitting the env var silently fell back to the
241
+ multilingual default, and the model mismatch triggered a full re-embed wipe that
242
+ flapped against the MCP tool's index.
243
+ - Precedence: explicit `Config(...)` / `--model` / `$COGVAULT_MODEL` > `.cogvault.toml` > defaults.
244
+ - Allowlisted keys only (model, dim, chunk/pool sizes, decay, mmr, recursive,
245
+ strip_frontmatter, ignore_globs); `db_dir` is intentionally NOT settable from the file.
246
+ - TOML via stdlib `tomllib` (3.11+) with a minimal flat-key fallback for 3.10.
247
+ - cogvault never *writes* the file — read-only if present.
248
+ - New `--model` CLI flag for one-off overrides. New public `apply_tenant_config()`.
249
+
250
+ ## 0.6.0 — 2026-06-28 — index folder trees (Obsidian vaults & knowledge bases)
251
+
252
+ Opt-in multi-source support: a tenant can be a nested vault, not just a flat
253
+ directory. Flat agent-memory tenants are unaffected (all new options default off).
254
+
255
+ - `Config`: `recursive`, `strip_frontmatter`, `ignore_globs`.
256
+ - Recursive walk keys files by path RELATIVE to the tenant, so same-named notes in
257
+ different folders no longer collide on basename.
258
+ - `strip_frontmatter` drops a leading YAML `--- … ---` block before chunking so its
259
+ keys don't pollute embeddings; `ignore_globs` skips paths (e.g. `.obsidian/*`,
260
+ `Templates/*`); the recursive walk prunes dotfile dirs.
261
+ - CLI: `--recursive` / `--strip-frontmatter` / `--ignore` on `index|search|mcp`.
262
+ - Validated on a real ~3,500-note Obsidian vault: 9,544 chunks, first index ~216 s,
263
+ warm recall 9-10 ms.
264
+
265
+ ## 0.5.0 — 2026-06-28 — first public release
266
+
267
+ Fleet-grade local memory over plain Markdown, published to GitHub (MIT).
268
+
269
+ - Atomic model-mismatch guard + rebuild inside one transaction (no more malformed
270
+ vec0 shadow tables after a crash mid-rebuild).
271
+ - Resilient self-healing search: a corrupt index returns empty and triggers one
272
+ background rebuild instead of raising into the agent.
273
+ - Packaging for fleet install (`pip install -e`), entry point `cogvault`.
274
+
275
+ ## 0.4.0 — 2026-06-27 — observability
276
+
277
+ - **Query log.** Every `recall` appends one JSONL line to
278
+ `~/.cache/cogvault/query-log.jsonl` (`COGVAULT_LOG` to relocate, `off` to disable):
279
+ timestamp, tenant, query, result count, top score, scores, latency, empty flag.
280
+ Best-effort — never breaks a recall.
281
+ - **`cogvault analyze`.** Reads the log into an effectiveness report: recall count,
282
+ no-hit rate, latency p50/p95, average top score, per-tenant breakdown, and recent
283
+ no-hit queries (the actionable "memory is missing this" signal). `--json` for scripts,
284
+ `--tenant` to scope.
285
+
286
+ ## 0.3.1 — 2026-06-27 — concurrency fix (runtime stress test)
287
+
288
+ A runtime stress test (8 parallel processes hammering one tenant) caught a bug that
289
+ two static audits missed:
290
+
291
+ - **Reindex is now atomic** (`BEGIN IMMEDIATE`). Two processes reindexing the *same*
292
+ tenant concurrently previously raced into a `vec_chunks` rowid UNIQUE-constraint
293
+ crash; they now serialize cleanly via the busy-timeout. Verified: 3 writers +
294
+ 5 readers, 0 lock errors, 0 empty reads. Regression-locked by
295
+ `test_concurrent_writers_no_collision`.
296
+ - Verified at scale: 419 files / 445 chunks index in ~3 s, search p50 ≈ 5 ms,
297
+ recall holds among 400 distractors. Empty / 1 MB / binary files don't crash.
298
+
299
+ ## 0.3.0 — 2026-06-27 — pre-release contract hardening
300
+
301
+ Fixing one-way-door decisions before any adoption locks them in.
302
+
303
+ - **Multilingual by default.** `DEFAULT_MODEL` is now
304
+ `paraphrase-multilingual-MiniLM-L12-v2` (384-d). `bge-small-en-v1.5` returns a
305
+ *negative* relevance margin on Cyrillic queries — broken for non-English memory.
306
+ The new default works for mixed-language fleets; pick your model via
307
+ `COGVAULT_MODEL` / `Config(model=...)` — see the table in the README. (Documented
308
+ trade-off: the multilingual default is less sharp on English; English-only fleets
309
+ should set `bge-small-en-v1.5`.)
310
+ - **Schema version + dim guard.** `PRAGMA user_version` and the embedding model **and
311
+ dimension** are recorded in `meta`; a mismatch auto-rebuilds the derived tables
312
+ instead of crashing or silently mixing dimensions.
313
+ - **Stable chunk ids.** `search()` now returns a deterministic `id` = `sha(path|hash)`
314
+ that survives reindexes, so external systems can reference a memory safely.
315
+ - **Index moved out of the markdown dir.** The `.db` now lives under
316
+ `~/.cache/cogvault/` (override with `Config(db_dir=...)`), so it can never be
317
+ accidentally git-committed next to your notes.
318
+
319
+ ## 0.2.0 — 2026-06-27 — fleet-hardening
320
+
321
+ Production-correctness pass before fleet rollout (audited with an adversarial review).
322
+
323
+ - **Incremental indexing.** `reindex()` now only re-reads files whose `mtime`
324
+ changed; unchanged files are skipped, deleted files are purged. `reindex(full=True)`
325
+ forces a clean rebuild.
326
+ - **Concurrency-safe.** WAL journal mode + `busy_timeout` — concurrent agents can
327
+ read while another writes. No more full-wipe: a reader during a reindex never sees
328
+ an empty database. (Covered by `test_concurrent_read_during_reindex`.)
329
+ - **Correct provenance.** `UNIQUE(path, hash)` — an identical chunk in two files keeps
330
+ both file paths instead of collapsing to the first.
331
+ - **FTS5 hardening.** Each query term is double-quoted (FTS keywords like `OR`/`NEAR`
332
+ and punctuation can't break parsing) and English stopwords are dropped — fixing
333
+ silent crashes and BM25 noise. **Recall improved: hit@1 87% → 93%, MRR 0.883 → 0.933.**
334
+ - **Full chunks returned** (`text`), not truncated to 280 chars — agents get the
335
+ context they need. `Config.snippet_chars` controls the short preview.
336
+ - **Model/dimension guard.** The index records its embedding model; switching models
337
+ auto-wipes incompatible cached vectors instead of crashing.
338
+
339
+ ## 0.1.0 — 2026-06-27
340
+
341
+ Initial release.
342
+
343
+ - Markdown-as-source-of-truth memory over a rebuildable SQLite index.
344
+ - Hybrid retrieval: `sqlite-vec` (semantic) + FTS5 (BM25), fused with RRF.
345
+ - In-process embeddings via FastEmbed (`bge-small-en-v1.5`, 384-d) — no server,
346
+ no API key, no cloud.
347
+ - Content-hash embedding cache: re-indexing only re-embeds changed chunks.
348
+ - Optional temporal decay (evergreen files exempt) and MMR diversity.
349
+ - Multi-tenant: one process serves many isolated memory namespaces by directory.
350
+ - stdio MCP server exposing `cogvault_recall` and `cogvault_record`.
351
+ - CLI: `index`, `search`, `mcp`, `stats`.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Nick Bibikov
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.