nexusmem 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +57 -1
- package/README.md +62 -17
- package/dist/cli/index.js +668 -92
- package/dist/cli/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -9,6 +9,61 @@ built from, matched by publish timestamp: `v0.1.0` → `67a4776`, `v0.1.1` → `
|
|
|
9
9
|
|
|
10
10
|
## [Unreleased]
|
|
11
11
|
|
|
12
|
+
## [0.3.0] — 2026-08-13
|
|
13
|
+
|
|
14
|
+
**Upgrade note.** The first `sync` after upgrading drops every stored embedding and rebuilds it.
|
|
15
|
+
This is not optional and it is not a bug: embeddings now come from Ollama's `/api/embed`, which
|
|
16
|
+
returns L2-normalised vectors, while the previous `/api/embeddings` did not — measured norms of 1.0
|
|
17
|
+
and 20.7 for the same input. `nodes_vec` ranks by Euclidean distance and records no per-row
|
|
18
|
+
provenance, so a corpus holding both would separate by scale rather than by meaning. `sync` says
|
|
19
|
+
what it dropped, nodes are untouched, and BM25 keeps working while the rebuild runs. On this repo
|
|
20
|
+
the rebuild was 833 nodes in one pass, inside a 9-second sync.
|
|
21
|
+
|
|
22
|
+
### Added
|
|
23
|
+
|
|
24
|
+
- **Session summaries via a local model** (`sources.session`, opt-in, off by default). Each
|
|
25
|
+
finished session becomes one distilled `session_summary` node — decisions and their reasons —
|
|
26
|
+
alongside the raw exchanges. Runs a local Ollama chat model (`qwen2.5:3b` by default); nothing is
|
|
27
|
+
downloaded automatically and no transcript leaves the machine. New `scan-session` command, with
|
|
28
|
+
`--dry-run` to print the exact prompt a session would produce without calling the model.
|
|
29
|
+
Bounded three ways: a session must be quiet for `settleMinutes` (default 30) before it is
|
|
30
|
+
eligible, the prompt is hashed so an unchanged session never reaches the model again, and
|
|
31
|
+
`maxSessions` caps how many are summarized per sync. Every exchange is redacted before the model
|
|
32
|
+
sees it, and the model's own output is redacted again before it is stored.
|
|
33
|
+
- **`sync --embed-limit <n>`** to cap the embedding pass, for when draining the whole backlog is not
|
|
34
|
+
wanted.
|
|
35
|
+
|
|
36
|
+
### Changed
|
|
37
|
+
|
|
38
|
+
- **The embedding pass drains the backlog in one `sync`** instead of stopping after 200 nodes, and
|
|
39
|
+
sends texts to Ollama in batches of 32 — measured at 4.21x the throughput of one call per node
|
|
40
|
+
(20.3ms → 4.8ms per node, over 96 real nodes from this repo). Leaving it uncapped is safe because
|
|
41
|
+
paging walks rowids monotonically, so a node the provider failed on is passed over rather than
|
|
42
|
+
retried forever, and because three consecutive dead requests end the pass: an Ollama that is not
|
|
43
|
+
running now costs three requests rather than one timeout per node.
|
|
44
|
+
- **Embeddings carry a provider identity.** Changing the embedding model, or upgrading from a
|
|
45
|
+
release that recorded no identity, drops the vectors and re-embeds rather than ranking across a
|
|
46
|
+
mixture.
|
|
47
|
+
- **Ranking priors now share one budget instead of getting one each.** `signal` and `recency` are
|
|
48
|
+
query-independent, and each was separately capped at overturning a 2× relevance gap. The score
|
|
49
|
+
multiplies them, so together they could overturn 4× — which is not a corner case but a description
|
|
50
|
+
of every commit made during an active working day, fresh and high-signal at once. A query about the
|
|
51
|
+
PowerShell hook returned two unrelated same-day `fix:` commits at ranks 3 and 4 while the section
|
|
52
|
+
that answered it sat at rank 6. The 2× budget is now the bound on the priors *jointly*, split
|
|
53
|
+
between them (`signal^0.215 × recency^0.288`, down from `^0.431` and `^0.576`), and a third prior
|
|
54
|
+
would re-divide the same budget rather than enlarge it. Measured on four real queries against this
|
|
55
|
+
repository's memory: the answering section rose in three of them — the rationale for "why BM25
|
|
56
|
+
before vector search" went from rank 4 to rank 1 — and no query's correct top hit was displaced.
|
|
57
|
+
|
|
58
|
+
### Known limitation
|
|
59
|
+
|
|
60
|
+
- Session-summary *titles* depend on the model following a fixed output format, and a 3B model often
|
|
61
|
+
does not. Measured over 14 real sessions, roughly a third came back usable; the rest were
|
|
62
|
+
conversational preambles, stray bullets, or a bare "Summary of the Session". Those are rejected
|
|
63
|
+
and the title falls back to the first line of the question that opened the session — always
|
|
64
|
+
specific, not always elegant. Compliance was worst on long sessions and on transcripts not in
|
|
65
|
+
English. `sources.session.model` takes a larger model if it matters.
|
|
66
|
+
|
|
12
67
|
## [0.2.0] — 2026-08-12
|
|
13
68
|
|
|
14
69
|
**Upgrade note.** Both new sources are on by default, so the first `sync` after upgrading an
|
|
@@ -119,7 +174,8 @@ First public release.
|
|
|
119
174
|
there is no local-model summarization pass, and the conversation collector has never been audited
|
|
120
175
|
for the stale-node bug that was found and fixed in the docs collector.
|
|
121
176
|
|
|
122
|
-
[Unreleased]: https://github.com/yaminbakoh4-dot/NexusMem/compare/v0.
|
|
177
|
+
[Unreleased]: https://github.com/yaminbakoh4-dot/NexusMem/compare/v0.3.0...HEAD
|
|
178
|
+
[0.3.0]: https://github.com/yaminbakoh4-dot/NexusMem/compare/v0.2.0...v0.3.0
|
|
123
179
|
[0.2.0]: https://github.com/yaminbakoh4-dot/NexusMem/compare/v0.1.2...v0.2.0
|
|
124
180
|
[0.1.2]: https://github.com/yaminbakoh4-dot/NexusMem/compare/v0.1.1...v0.1.2
|
|
125
181
|
[0.1.1]: https://github.com/yaminbakoh4-dot/NexusMem/compare/v0.1.0...v0.1.1
|
package/README.md
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
[](LICENSE)
|
|
5
5
|

|
|
6
6
|
|
|
7
|
+

|
|
8
|
+
|
|
7
9
|
Your coding agent can read `git log`. It cannot read the four things you tried last Tuesday that
|
|
8
10
|
didn't work.
|
|
9
11
|
|
|
@@ -42,7 +44,9 @@ Relevant history for: windows spawn failure
|
|
|
42
44
|
```
|
|
43
45
|
|
|
44
46
|
A commit and a docs section, ranked against each other, inside whatever token budget you gave it.
|
|
45
|
-
Nothing was summarized by a model on the way out; the ranker just decided what not to send.
|
|
47
|
+
Nothing was summarized by a model on the way out; the ranker just decided what not to send. (One
|
|
48
|
+
optional source, session summaries, does run a local model — but at ingest time, never on the way
|
|
49
|
+
out. What you query is always stored text.)
|
|
46
50
|
|
|
47
51
|
For a sense of what actually accumulates, here is `nexusmem status` on this repo after two days:
|
|
48
52
|
|
|
@@ -79,7 +83,7 @@ they agree on. No hand-tuned normalization constant sits between them.
|
|
|
79
83
|
Ranking then multiplies three factors:
|
|
80
84
|
|
|
81
85
|
```
|
|
82
|
-
score = relevance × signal^0.
|
|
86
|
+
score = relevance × signal^0.215 × recency^0.288
|
|
83
87
|
```
|
|
84
88
|
|
|
85
89
|
`relevance` comes from the query. `signal` (a `fix:` commit outranks a `chore:`; a command that
|
|
@@ -89,13 +93,50 @@ zero out a strong match.
|
|
|
89
93
|
|
|
90
94
|
Those exponents are derived, not tuned. Priors kept overturning the query: on one real query a `fix:`
|
|
91
95
|
commit took rank 1 from a better-matching docs section on a 44% signal edge against a 15% relevance
|
|
92
|
-
deficit. So
|
|
93
|
-
gap
|
|
94
|
-
|
|
96
|
+
deficit. So the priors get a **shared** budget — across their whole range they may overturn at most a
|
|
97
|
+
2× relevance gap — split evenly between them, and each is raised to the power that makes its own span
|
|
98
|
+
worth exactly its share (`span^exponent = √2`). Priors still order equally-relevant hits exactly as
|
|
99
|
+
before, since the transform is monotonic. They just cannot outvote the question anymore.
|
|
100
|
+
|
|
101
|
+
The budget is shared rather than per-prior for a reason found by dogfooding, not by reading the
|
|
102
|
+
arithmetic: the score *multiplies* the priors, so capping each at 2× separately left the pair free to
|
|
103
|
+
overturn 4×. That describes every commit made during an active working day — fresh and high-signal at
|
|
104
|
+
once — so the failure landed on precisely the days with the most worth remembering. A query about the
|
|
105
|
+
PowerShell hook returned two unrelated same-day `fix:` commits at ranks 3 and 4 while the section that
|
|
106
|
+
answered it sat at rank 6. Adding a third prior now re-divides the same budget instead of enlarging it.
|
|
95
107
|
|
|
96
108
|
Without Ollama, vector search is skipped and you get BM25 only. That path is fully supported, not a
|
|
97
109
|
degraded error state; `sync` and `query` both succeed and simply do less.
|
|
98
110
|
|
|
111
|
+
## Session summaries (optional, local model)
|
|
112
|
+
|
|
113
|
+
With `sources.session.enabled`, each finished session becomes one distilled node next to the raw
|
|
114
|
+
exchanges — what was decided and why, rather than forty individual turns. It runs a local Ollama
|
|
115
|
+
chat model (`qwen2.5:3b` by default); nothing is downloaded automatically and nothing leaves the
|
|
116
|
+
machine.
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
nexusmem scan-session --dry-run
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
That prints the exact prompt a session would produce, after redaction and budget trimming, without
|
|
123
|
+
calling the model.
|
|
124
|
+
|
|
125
|
+
Three things bound the cost. A session is only summarized once it has been quiet for
|
|
126
|
+
`settleMinutes` (default 30), so a session in progress is not re-summarized on every sync. The
|
|
127
|
+
prompt is hashed, and an unchanged hash skips the model entirely — on this repo a steady-state sync
|
|
128
|
+
of 14 summarized sessions takes 0.25s and makes no model calls. And `maxSessions` (default 10) caps
|
|
129
|
+
how many reach the model per run; the rest are reported as queued and picked up next sync.
|
|
130
|
+
|
|
131
|
+
**What it is actually like, measured on 14 real sessions with `qwen2.5:3b`.** The summaries
|
|
132
|
+
themselves are good: decisions with their reasons, in the shape the prompt asks for. Titles are less
|
|
133
|
+
reliable — the model returned a usable one about a third of the time, and otherwise produced a
|
|
134
|
+
conversational preamble, a stray bullet, or a bare "Summary of the Session". Those are rejected and
|
|
135
|
+
the title falls back to the first line of the question that opened the session, which is always
|
|
136
|
+
specific even when it is not elegant. Compliance was worst on long sessions and on transcripts not
|
|
137
|
+
in English. A larger model (`qwen2.5:7b`) is the lever if the titles matter to you; set
|
|
138
|
+
`sources.session.model`.
|
|
139
|
+
|
|
99
140
|
## Use it from an agent
|
|
100
141
|
|
|
101
142
|
```json
|
|
@@ -177,7 +218,13 @@ optimizing, and it is somebody else's process.
|
|
|
177
218
|
at the prompt is not reconstructed.
|
|
178
219
|
- **Scrape-fallback ids drift** if the history file is trimmed from the front between syncs.
|
|
179
220
|
Installing the hook fixes this.
|
|
180
|
-
- **
|
|
221
|
+
- **Session-summary titles depend on the model following instructions**, and a 3B model often does
|
|
222
|
+
not. The fallback keeps them specific rather than generic, but see the section above for what to
|
|
223
|
+
expect.
|
|
224
|
+
- **Changing the embedding model re-embeds everything.** Vectors from two models are not comparable
|
|
225
|
+
and `nodes_vec` records no per-row provenance, so `sync` drops the lot and rebuilds rather than
|
|
226
|
+
ranking across a mixture. It says so when it happens. Nodes are untouched and BM25 keeps working
|
|
227
|
+
throughout.
|
|
181
228
|
- **Diff indexing is bounded, and deliberately lossy.** A first sync indexes the patches of the most
|
|
182
229
|
recent 200 commits (later syncs only walk `cursor..HEAD`); merge commits contribute none, since
|
|
183
230
|
their patch exists only in a combined format this parser does not read; and binaries, lockfiles and
|
|
@@ -194,12 +241,13 @@ optimizing, and it is somebody else's process.
|
|
|
194
241
|
unmounted drive is not a deleted project.
|
|
195
242
|
- **Conversation chunking is unevaluated.** Splitting long replies at heading boundaries measurably
|
|
196
243
|
helped, but it has never been tested systematically.
|
|
197
|
-
- **
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
244
|
+
- **The size of the prior budget is a judgement call, not a measured optimum.** Priors are now
|
|
245
|
+
bounded jointly rather than one at a time, which closed a real 4× hole (see the ranking section),
|
|
246
|
+
but the 2× budget itself has never been tuned against a labelled relevance set — there isn't one.
|
|
247
|
+
It is a defensible constant, not a result. What is measured is the direction: on four real queries
|
|
248
|
+
against this repo's own memory, switching to the joint cap moved the section that answered the
|
|
249
|
+
question up in three of them (the rationale section for "why BM25 before vector search" went from
|
|
250
|
+
rank 4 to rank 1) and displaced no query's correct top hit.
|
|
203
251
|
|
|
204
252
|
## Commands
|
|
205
253
|
|
|
@@ -267,11 +315,8 @@ Deleting `.nexusmem/` loses nothing that `sync` cannot rebuild.
|
|
|
267
315
|
|
|
268
316
|
## Status
|
|
269
317
|
|
|
270
|
-
Ingestion, hybrid retrieval, budgeted packing and the MCP server all work and are covered by
|
|
271
|
-
tests running on Linux and Windows across Node 22 and 24.
|
|
272
|
-
|
|
273
|
-
Not done yet: there is no local-model summarization pass, and the embedding pass is still capped per
|
|
274
|
-
`sync`.
|
|
318
|
+
Ingestion, hybrid retrieval, budgeted packing and the MCP server all work and are covered by 315
|
|
319
|
+
tests running on Linux and Windows across Node 22 and 24. Phase 3 is complete.
|
|
275
320
|
|
|
276
321
|
## Development
|
|
277
322
|
|