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.
- cogvault-0.11.1/.gitignore +16 -0
- cogvault-0.11.1/CHANGELOG.md +351 -0
- cogvault-0.11.1/LICENSE +21 -0
- cogvault-0.11.1/PKG-INFO +326 -0
- cogvault-0.11.1/README.md +296 -0
- cogvault-0.11.1/pyproject.toml +49 -0
- cogvault-0.11.1/server.json +61 -0
- cogvault-0.11.1/src/cogvault/__init__.py +5 -0
- cogvault-0.11.1/src/cogvault/cli.py +404 -0
- cogvault-0.11.1/src/cogvault/core.py +1464 -0
- cogvault-0.11.1/src/cogvault/mcp_server.py +255 -0
- cogvault-0.11.1/src/cogvault/obs.py +120 -0
- cogvault-0.11.1/tests/conftest.py +16 -0
- cogvault-0.11.1/tests/test_core.py +1273 -0
|
@@ -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`.
|
cogvault-0.11.1/LICENSE
ADDED
|
@@ -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.
|