nexusmem 0.1.2 → 0.2.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 +126 -0
- package/README.md +302 -254
- package/dist/cli/index.js +989 -229
- package/dist/cli/index.js.map +1 -1
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -1,254 +1,302 @@
|
|
|
1
|
-
# NexusMem
|
|
2
|
-
|
|
3
|
-
[](https://www.npmjs.com/package/nexusmem)
|
|
4
|
-
[](LICENSE)
|
|
5
|
-

|
|
6
|
-
|
|
7
|
-
Your coding agent can read `git log`. It cannot read the four things you tried last Tuesday that
|
|
8
|
-
didn't work.
|
|
9
|
-
|
|
10
|
-
NexusMem records what actually happened on your machine (shell commands and their exit codes, git
|
|
11
|
-
history, project docs, optionally your assistant transcripts)
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
npx nexusmem
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
"
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
|
156
|
-
|
|
|
157
|
-
|
|
|
158
|
-
|
|
|
159
|
-
|
|
|
160
|
-
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
- **
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
##
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
1
|
+
# NexusMem
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/nexusmem)
|
|
4
|
+
[](LICENSE)
|
|
5
|
+

|
|
6
|
+
|
|
7
|
+
Your coding agent can read `git log`. It cannot read the four things you tried last Tuesday that
|
|
8
|
+
didn't work.
|
|
9
|
+
|
|
10
|
+
NexusMem records what actually happened on your machine (shell commands and their exit codes, git
|
|
11
|
+
history down to the patch of each changed file, project docs, optionally your assistant transcripts)
|
|
12
|
+
into a local SQLite database, and
|
|
13
|
+
serves back a ranked, token-budgeted slice of it on demand. Everything stays on disk. No account, no
|
|
14
|
+
cloud, no telemetry.
|
|
15
|
+
|
|
16
|
+
The shell history is the part worth caring about. Git tells an agent what shipped. Shell history
|
|
17
|
+
tells it what was attempted, in what order, and which commands exited non-zero. That information
|
|
18
|
+
exists nowhere else, and it disappears when your terminal scrollback rolls over.
|
|
19
|
+
|
|
20
|
+
## Try it
|
|
21
|
+
|
|
22
|
+
From inside any git repository:
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
npx nexusmem init
|
|
26
|
+
npx nexusmem sync
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Then ask it something. Real output from this repository, top 2 of 5 hits:
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
$ nexusmem query "windows spawn failure"
|
|
33
|
+
|
|
34
|
+
Relevant history for: windows spawn failure
|
|
35
|
+
|
|
36
|
+
- 2026-08-09 fix: distinguish a failed git spawn from "not a git repository"
|
|
37
|
+
readRepoInfo collapsed three unrelated failures into one error: git running and reporting
|
|
38
|
+
the path is not a work tree, git not being installed, and the process failing to spawn at
|
|
39
|
+
all. Dogfooding hit the third case in two separate sessions...
|
|
40
|
+
- 2026-08-09 README.md — Before a tagged release
|
|
41
|
+
- [ ] Retry on transient process-spawn failures on Windows
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
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.
|
|
46
|
+
|
|
47
|
+
For a sense of what actually accumulates, here is `nexusmem status` on this repo after two days:
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
527 node(s) 2026-08-08 .. 2026-08-09
|
|
51
|
+
321 shell_command
|
|
52
|
+
130 conversation_turn
|
|
53
|
+
60 doc_section
|
|
54
|
+
16 git_commit
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Sixteen commits. Three hundred and twenty-one shell commands. The commits were already retrievable
|
|
58
|
+
by any agent with a terminal. The rest was not.
|
|
59
|
+
|
|
60
|
+
That `conversation_turn` row only appears because this corpus was synced with `--conversation`.
|
|
61
|
+
Assistant transcripts are the one source that is off by default and stays off until you opt in, since
|
|
62
|
+
they are the likeliest place for a pasted credential to be sitting. A default install indexes git
|
|
63
|
+
commits, their diffs, shell and docs.
|
|
64
|
+
|
|
65
|
+
Requirements: Node 22 or newer, and git. Node 20 will not work, because `better-sqlite3` ships no
|
|
66
|
+
prebuilt binary for it and Node 20 went end-of-life in April 2026. Ollama is optional and only
|
|
67
|
+
affects semantic search (see below).
|
|
68
|
+
|
|
69
|
+
## How retrieval works
|
|
70
|
+
|
|
71
|
+
Every source normalizes to the same `MemoryNode` shape, so a commit, a shell command and a docs
|
|
72
|
+
section compete on equal terms. Retrieval runs BM25 over FTS5 and, if an embedding model is
|
|
73
|
+
reachable, a vector search over `sqlite-vec`, then fuses the two with Reciprocal Rank Fusion.
|
|
74
|
+
|
|
75
|
+
RRF fuses on rank *position* only, never on raw scores. That is the entire reason it is safe here: a
|
|
76
|
+
BM25 cost and a vector distance live on unrelated, unbounded scales, and position is the only thing
|
|
77
|
+
they agree on. No hand-tuned normalization constant sits between them.
|
|
78
|
+
|
|
79
|
+
Ranking then multiplies three factors:
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
score = relevance × signal^0.431 × recency^0.576
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
`relevance` comes from the query. `signal` (a `fix:` commit outranks a `chore:`; a command that
|
|
86
|
+
exited non-zero outranks one that succeeded) and `recency` are priors that hold before any query
|
|
87
|
+
exists. Each factor is floored into `[floor, 1]` rather than `[0, 1]`, so one weak dimension cannot
|
|
88
|
+
zero out a strong match.
|
|
89
|
+
|
|
90
|
+
Those exponents are derived, not tuned. Priors kept overturning the query: on one real query a `fix:`
|
|
91
|
+
commit took rank 1 from a better-matching docs section on a 44% signal edge against a 15% relevance
|
|
92
|
+
deficit. So each prior is raised to the power that caps its entire range at overturning a 2× relevance
|
|
93
|
+
gap, by solving `span^exponent = 2`. Priors still order equally-relevant hits exactly as before, since
|
|
94
|
+
the transform is monotonic. They just cannot outvote the question anymore.
|
|
95
|
+
|
|
96
|
+
Without Ollama, vector search is skipped and you get BM25 only. That path is fully supported, not a
|
|
97
|
+
degraded error state; `sync` and `query` both succeed and simply do less.
|
|
98
|
+
|
|
99
|
+
## Use it from an agent
|
|
100
|
+
|
|
101
|
+
```json
|
|
102
|
+
{
|
|
103
|
+
"mcpServers": {
|
|
104
|
+
"nexusmem": {
|
|
105
|
+
"command": "npx",
|
|
106
|
+
"args": ["-y", "nexusmem", "mcp"]
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Three tools over stdio: `search_memory` returns the packed context block, `sync_project` ingests, and
|
|
113
|
+
`get_status` reports what is currently remembered. Each takes an explicit `projectRoot`, because an
|
|
114
|
+
MCP tool call carries no shell working directory. `sync_project` runs `init` for you if the
|
|
115
|
+
repository has not been set up.
|
|
116
|
+
|
|
117
|
+
## Optional: exact shell capture
|
|
118
|
+
|
|
119
|
+
Scraped history files (PSReadLine, `.bash_history`, `.zsh_history`) give you command text and not
|
|
120
|
+
much else. The hook gives you working directory, exit code and a real timestamp:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
nexusmem hook install
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
It wraps your existing PowerShell prompt rather than replacing it, is idempotent, and
|
|
127
|
+
`nexusmem hook remove` undoes it cleanly.
|
|
128
|
+
|
|
129
|
+
Exit codes are what make this worth installing. A failed command is a stronger signal than a
|
|
130
|
+
successful one, and without the hook there is no way to tell them apart.
|
|
131
|
+
|
|
132
|
+
## What it costs you
|
|
133
|
+
|
|
134
|
+
Two numbers get conflated in tools like this, so they are kept apart here.
|
|
135
|
+
|
|
136
|
+
**Packer efficiency** is how much the ranker trims from its own candidate set. On this repository's
|
|
137
|
+
corpus it runs 81–84%. It is useful for tuning the ranker and useless as a claim about your bill,
|
|
138
|
+
because the baseline is hypothetical: without NexusMem those candidates were never going into your
|
|
139
|
+
context window in the first place.
|
|
140
|
+
|
|
141
|
+
**End-to-end saving** compares packed context against reading the equivalent files in full. Measured
|
|
142
|
+
at **~40%** on design queries against this codebase, hand-tallied from one real session rather than
|
|
143
|
+
instrumented. Treat it as an order of magnitude.
|
|
144
|
+
|
|
145
|
+
The long-term target is >70%, and this repository cannot demonstrate it. That figure describes repos
|
|
146
|
+
with thousands of commits, where the win comes from omitting hundreds of unrelated items rather than
|
|
147
|
+
shaving a handful. A benchmark at that size is still outstanding, and until it exists the honest
|
|
148
|
+
number is 40%.
|
|
149
|
+
|
|
150
|
+
One thing that is not a percentage: shell commands and conversation turns have no cheap `grep`
|
|
151
|
+
equivalent. Without something recording them, they are gone, not merely more expensive to find.
|
|
152
|
+
|
|
153
|
+
Latency on a ~530-node corpus, warm, p50 over 10 runs:
|
|
154
|
+
|
|
155
|
+
| Operation | |
|
|
156
|
+
| --- | --- |
|
|
157
|
+
| BM25 retrieval (FTS5) | ~1.1 ms |
|
|
158
|
+
| Vector KNN (`sqlite-vec`) | ~3.2 ms |
|
|
159
|
+
| Fuse, rank, pack | ~0.6 ms |
|
|
160
|
+
| Query embedding (local Ollama) | ~55–77 ms |
|
|
161
|
+
| **End-to-end hybrid** | **~56 ms** |
|
|
162
|
+
|
|
163
|
+
All the SQLite work totals about 5 ms. The embedding call is the only thing on this path worth
|
|
164
|
+
optimizing, and it is somebody else's process.
|
|
165
|
+
|
|
166
|
+
## Where it breaks
|
|
167
|
+
|
|
168
|
+
- **Shell history without the hook is unscoped.** Scraped history has no directory context, so it is
|
|
169
|
+
attributed to whichever repository you ran `sync` from. Bounded to a tail window, and an
|
|
170
|
+
approximation rather than a guarantee.
|
|
171
|
+
- **Japanese and Chinese depend on the vector pass.** FTS5's `unicode61` tokenizer splits on
|
|
172
|
+
whitespace, so languages without space boundaries get no useful BM25 recall.
|
|
173
|
+
- **Rebasing strands nodes.** Rewritten history leaves nodes for unreachable commits. They describe
|
|
174
|
+
real events so they are not wrong, but a targeted prune does not exist yet. `sync --rebuild`
|
|
175
|
+
forces a clean re-scan.
|
|
176
|
+
- **Multi-line PowerShell input is read as separate commands.** A function typed across several lines
|
|
177
|
+
at the prompt is not reconstructed.
|
|
178
|
+
- **Scrape-fallback ids drift** if the history file is trimmed from the front between syncs.
|
|
179
|
+
Installing the hook fixes this.
|
|
180
|
+
- **The embedding pass is capped per `sync`**, so a large corpus needs a few runs to embed fully.
|
|
181
|
+
- **Diff indexing is bounded, and deliberately lossy.** A first sync indexes the patches of the most
|
|
182
|
+
recent 200 commits (later syncs only walk `cursor..HEAD`); merge commits contribute none, since
|
|
183
|
+
their patch exists only in a combined format this parser does not read; and binaries, lockfiles and
|
|
184
|
+
build output are skipped so a dependency bump cannot bury the corpus. All of it is still recorded
|
|
185
|
+
as a `git_commit` node. A patch longer than `limits.maxBodyChars` is truncated, so the tail of a
|
|
186
|
+
very large change is not indexed. The caps live under `sources.diff` in `config.json`.
|
|
187
|
+
- **Cross-project recall favours breadth.** Each repository's hits are fused by rank, so a project
|
|
188
|
+
whose best match is mediocre still contributes a rank-1 item, and rank 1 is worth the same in
|
|
189
|
+
every list. Adding a repository that has little to say about your question still pushes a few of
|
|
190
|
+
its results into the budget. Signal, recency and the budget are what hold that in check; there is
|
|
191
|
+
no per-project quality weight.
|
|
192
|
+
- **The project registry is an index, not a source of truth.** It can point at a database that has
|
|
193
|
+
moved or been deleted; those are reported and skipped, never silently pruned, because an
|
|
194
|
+
unmounted drive is not a deleted project.
|
|
195
|
+
- **Conversation chunking is unevaluated.** Splitting long replies at heading boundaries measurably
|
|
196
|
+
helped, but it has never been tested systematically.
|
|
197
|
+
- **A burst of recent, high-signal commits crowds unrelated queries.** Each prior is individually
|
|
198
|
+
capped at overturning a 2× relevance gap, but the caps are per-prior, not joint, so a node that is
|
|
199
|
+
both very fresh and highly scored can overturn roughly 4×. Found by dogfooding: a query about the
|
|
200
|
+
PowerShell hook returned two same-day `fix:` commits with nothing to do with it at ranks 3 and 4,
|
|
201
|
+
while the section that actually answered the question sat at rank 6. Gets worse on days with a lot
|
|
202
|
+
of commits, which are exactly the days you have most to remember.
|
|
203
|
+
|
|
204
|
+
## Commands
|
|
205
|
+
|
|
206
|
+
`init`, `sync`, `query <text>`, `status`, `projects`, `mcp`, and `hook install|remove|status`.
|
|
207
|
+
|
|
208
|
+
There are also five dry-run previews (`scan-git`, `scan-diff`, `scan-shell`, `scan-docs`,
|
|
209
|
+
`scan-conversation`)
|
|
210
|
+
that write nothing and print the nodes ingestion *would* create along with their signal scores. That
|
|
211
|
+
is the intended way to tune scoring against a real repository before committing to a change. Add
|
|
212
|
+
`--json` to pipe them somewhere.
|
|
213
|
+
|
|
214
|
+
Every command takes `-C <path>` to target another repository. On `sync`, `--conversation` opts the
|
|
215
|
+
transcript source in for one run without persisting it, `--no-embed` skips the vector pass, and
|
|
216
|
+
`--rebuild` drops the project's nodes and re-ingests from scratch.
|
|
217
|
+
|
|
218
|
+
## Recall across projects
|
|
219
|
+
|
|
220
|
+
`query --all-projects` searches every repository you have run NexusMem in, not just the current one,
|
|
221
|
+
and tags each result with the repository it came from:
|
|
222
|
+
|
|
223
|
+
```
|
|
224
|
+
$ nexusmem query --all-projects "why was the retry budget raised"
|
|
225
|
+
scope 2 project(s): NexusMem, uploader
|
|
226
|
+
|
|
227
|
+
- 2026-08-12 [uploader] fix: raise the retry budget after the S3 upload timeouts
|
|
228
|
+
- 2026-08-12 [uploader] retry.ts @ 8d0f98b — fix: raise the retry budget after the S3 upload timeouts
|
|
229
|
+
@@ -1 +1 @@
|
|
230
|
+
-export const RETRY_BUDGET = 3;
|
|
231
|
+
+export const RETRY_BUDGET = 5;
|
|
232
|
+
- 2026-08-09 [NexusMem] fix(git): retry a transient failure to spawn git
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
Databases stay per-repository — there is no shared global store, and deleting one repo's
|
|
236
|
+
`.nexusmem/` still removes exactly that repo's memory. What makes the others findable is a plain
|
|
237
|
+
index at `~/.nexusmem/projects.json`, written by `init` and refreshed by every `sync`. `nexusmem
|
|
238
|
+
projects` shows what is in it, and `--prune` forgets entries whose database is gone.
|
|
239
|
+
|
|
240
|
+
Ranking across repositories uses reciprocal rank fusion per project rather than raw BM25, because a
|
|
241
|
+
BM25 cost is computed against its own corpus and means different things in a 50-node and a
|
|
242
|
+
50,000-node database. The trade is stated in *Where it breaks*.
|
|
243
|
+
|
|
244
|
+
The MCP `search_memory` tool takes the same switch as `allProjects: true`.
|
|
245
|
+
|
|
246
|
+
## On disk
|
|
247
|
+
|
|
248
|
+
```
|
|
249
|
+
<repo>/.nexusmem/
|
|
250
|
+
.gitignore '*' — the workspace ignores itself, so init never edits a file it doesn't own
|
|
251
|
+
config.json validated on read; a corrupt config fails loudly rather than silently
|
|
252
|
+
memory.db SQLite in WAL mode
|
|
253
|
+
|
|
254
|
+
~/.nexusmem/
|
|
255
|
+
projects.json which repositories exist, for cross-project recall; a corrupt one reads as empty
|
|
256
|
+
shell-history.jsonl the hook's log, if you installed it
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
`NEXUSMEM_HOME` overrides the user-scoped directory.
|
|
260
|
+
|
|
261
|
+
Node ids are content-addressed from `sha256(projectId + kind + naturalKey)`, so running `sync` twice
|
|
262
|
+
cannot produce duplicates and ingestion stays correct even if a cursor is lost. Project identity
|
|
263
|
+
comes from the normalized origin URL when there is one, falling back to the absolute path, so two
|
|
264
|
+
clones of the same repo share one memory namespace.
|
|
265
|
+
|
|
266
|
+
Deleting `.nexusmem/` loses nothing that `sync` cannot rebuild.
|
|
267
|
+
|
|
268
|
+
## Status
|
|
269
|
+
|
|
270
|
+
Ingestion, hybrid retrieval, budgeted packing and the MCP server all work and are covered by 265
|
|
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`.
|
|
275
|
+
|
|
276
|
+
## Development
|
|
277
|
+
|
|
278
|
+
```bash
|
|
279
|
+
npm install
|
|
280
|
+
npm run typecheck
|
|
281
|
+
npm test
|
|
282
|
+
npm run build
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
Tests are behavioral rather than snapshot-based, and several are regressions tied to specific
|
|
286
|
+
observed failures. `tests/git-errors.test.ts` injects a fake `spawn` to exercise the Windows
|
|
287
|
+
process-spawn faults, which cannot be provoked on demand.
|
|
288
|
+
|
|
289
|
+
## On how this was built
|
|
290
|
+
|
|
291
|
+
This started as an experiment in whether a local context-memory engine for coding agents was viable,
|
|
292
|
+
prototyped with Claude Code. The code was written through AI-assisted workflows; the architecture,
|
|
293
|
+
the design decisions and the specifications were human-directed.
|
|
294
|
+
|
|
295
|
+
That is worth stating plainly because it should change how you read the code, not whether you trust
|
|
296
|
+
it. Audits, corrections and PRs are genuinely welcome, and the commit history is deliberately
|
|
297
|
+
detailed about *why* things are the way they are, including the times an earlier assumption turned
|
|
298
|
+
out to be wrong.
|
|
299
|
+
|
|
300
|
+
## License
|
|
301
|
+
|
|
302
|
+
MIT
|