minnimemory 1.0.0-beta.1 → 1.0.0-beta.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/README.md +352 -249
- package/dist/bench.d.ts +0 -67
- package/dist/bench.js +0 -31
- package/dist/benchReport.d.ts +0 -8
- package/dist/benchReport.js +0 -8
- package/dist/bounds.d.ts +0 -24
- package/dist/bounds.js +0 -19
- package/dist/cli.d.ts +3 -12
- package/dist/cli.js +184 -71
- package/dist/compile.d.ts +0 -97
- package/dist/compile.js +0 -127
- package/dist/discover.d.ts +0 -103
- package/dist/discover.js +0 -121
- package/dist/doctor.d.ts +0 -5
- package/dist/doctor.js +0 -7
- package/dist/episodic.d.ts +0 -29
- package/dist/episodic.js +0 -26
- package/dist/hook.d.ts +0 -32
- package/dist/hook.js +0 -35
- package/dist/index.d.ts +0 -5
- package/dist/index.js +0 -5
- package/dist/init.d.ts +39 -47
- package/dist/init.js +88 -70
- package/dist/install.d.ts +40 -0
- package/dist/install.js +101 -0
- package/dist/instructions.d.ts +1 -45
- package/dist/instructions.js +0 -90
- package/dist/mcpServer.d.ts +2 -121
- package/dist/mcpServer.js +243 -537
- package/dist/paths.d.ts +0 -21
- package/dist/paths.js +0 -21
- package/dist/recall.d.ts +0 -71
- package/dist/recall.js +1 -94
- package/dist/recallDir.d.ts +0 -33
- package/dist/recallDir.js +0 -49
- package/dist/reorganize.d.ts +0 -31
- package/dist/reorganize.js +0 -66
- package/dist/report.d.ts +0 -7
- package/dist/report.js +2 -21
- package/dist/router.d.ts +0 -85
- package/dist/router.js +0 -87
- package/dist/rules.d.ts +0 -17
- package/dist/rules.js +1 -137
- package/dist/scan.d.ts +0 -35
- package/dist/scan.js +1 -39
- package/dist/text.d.ts +0 -110
- package/dist/text.js +0 -117
- package/dist/tokenizer.d.ts +0 -23
- package/dist/tokenizer.js +0 -30
- package/dist/types.d.ts +2 -78
- package/dist/types.js +0 -4
- package/dist/version.d.ts +1 -7
- package/dist/version.js +1 -7
- package/dist/writeProtocol.d.ts +0 -14
- package/dist/writeProtocol.js +0 -14
- package/package.json +53 -52
package/README.md
CHANGED
|
@@ -1,13 +1,23 @@
|
|
|
1
1
|
# MinniMemoryMCP
|
|
2
2
|
|
|
3
3
|
**Curated memory for AI agents, served over MCP.** Your AI coding agent re-reads its entire
|
|
4
|
-
project memory file on every turn. MinniMemoryMCP
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
project memory file on every turn. MinniMemoryMCP audits that file, compiles it into a small
|
|
5
|
+
AlwaysOnMemory body plus OnDemandMemory files loaded only when relevant, and can undo the
|
|
6
|
+
whole thing in one step. Four verbs, the same in Claude Code and in the terminal: `doctor`,
|
|
7
|
+
`init`, `apply`, `undo`. No model, no key, no network; the MCP server never writes your disk.
|
|
8
8
|
|
|
9
9
|
Built by MinniAI.
|
|
10
10
|
|
|
11
|
+
**Quick start**
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npx -y minnimemory install # registers the MCP server for Claude Code, once per machine
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Restart Claude Code, open your project, and say "run doctor on my memory file", then "apply
|
|
18
|
+
it". Or from a terminal in the project: `npx -y minnimemory doctor`, then `npx -y minnimemory
|
|
19
|
+
apply`. Full steps under [Install](#install) and [Use it](#use-it).
|
|
20
|
+
|
|
11
21
|
```
|
|
12
22
|
BEFORE AFTER
|
|
13
23
|
CLAUDE.md 689 tokens CLAUDE.md 282 tokens <- every turn
|
|
@@ -17,28 +27,22 @@ CLAUDE.md 689 tokens CLAUDE.md 282 tokens <- every tur
|
|
|
17
27
|
|
|
18
28
|
Those are real numbers from `examples/CLAUDE.md` in this package, default settings, offline
|
|
19
29
|
tokenizer (`approx-v2`, calibrated against a real BPE encoder, see
|
|
20
|
-
[Measurement policy](#measurement-policy)).
|
|
21
|
-
|
|
30
|
+
[Measurement policy](#measurement-policy)). See them for your own file with
|
|
31
|
+
`npx -y minnimemory init` in your project; it prints the plan and writes nothing.
|
|
22
32
|
|
|
23
33
|
The classifier was validated on 23 real `CLAUDE.md` and `AGENTS.md` files from public
|
|
24
34
|
repositories on 2026-09-02: every one compiled losslessly, and every one landed inside the
|
|
25
35
|
2,000-token always-loaded budget afterwards.
|
|
26
36
|
|
|
27
|
-
Deterministic, lossless, offline. No LLM, no API key, no network.
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
> **Status: 1.0.0-beta.1
|
|
31
|
-
>
|
|
32
|
-
>
|
|
33
|
-
>
|
|
34
|
-
> `
|
|
35
|
-
>
|
|
36
|
-
> outside this project's own test corpus. The original nine tools stay
|
|
37
|
-
> available, unchanged, under `--profile full` for maintainers and for an agent driving a folder
|
|
38
|
-
> reorganization directly. `bench` reports exact session bounds and, given a workload, an
|
|
39
|
-
> explicitly-labelled model of a session; it does not measure a live agent by itself, though a
|
|
40
|
-
> separate internal harness has now measured the memory layer live on two real project files (see
|
|
41
|
-
> [Measurement policy](#measurement-policy)). See [Roadmap](#roadmap).
|
|
37
|
+
Deterministic, lossless, offline. No LLM, no API key, no network. The four verbs have no
|
|
38
|
+
runtime dependencies; only `mcp` pulls in the MCP SDK.
|
|
39
|
+
|
|
40
|
+
> **Status: public beta.** `1.0.0-beta.1` has been on npm since 2026-09-17; `1.0.0-beta.2`
|
|
41
|
+
> (this README) is on `main` and publishes next. The four verbs are tested from the CLI and
|
|
42
|
+
> over MCP in Claude Code; other hosts are supported by the standard config below but have not
|
|
43
|
+
> been exercised by us yet. Maintainers get nine more tools, `recall` included, under
|
|
44
|
+
> `--profile full` ([Profiles](#profiles)); `recall` joins the public surface once the
|
|
45
|
+
> converter has proven itself ([Roadmap](#roadmap)).
|
|
42
46
|
|
|
43
47
|
---
|
|
44
48
|
|
|
@@ -95,14 +99,20 @@ three copies of the test command, and a changelog nobody reads.
|
|
|
95
99
|
|
|
96
100
|
## What it does
|
|
97
101
|
|
|
98
|
-
|
|
102
|
+
Four commands do the work, the same four in the terminal and over MCP.
|
|
99
103
|
|
|
100
104
|
**`doctor`** audits your current setup and tells you what it is costing. It changes nothing, needs
|
|
101
105
|
no install, and takes about a second.
|
|
102
106
|
|
|
103
|
-
**`init`**
|
|
107
|
+
**`init`** shows what a compile would do: which sections stay always-on, which become
|
|
108
|
+
OnDemandMemory files, and the prefix before and after. It never writes.
|
|
109
|
+
|
|
110
|
+
**`apply`** compiles your memory file into a small AlwaysOnMemory body plus OnDemandMemory files
|
|
104
111
|
the agent loads only when they are relevant, and rewrites your memory file as a compact stub.
|
|
105
|
-
Your original is backed up first, and every line of it survives into the output.
|
|
112
|
+
Your original is backed up first, and every line of it survives into the output. Run it again
|
|
113
|
+
after a hand edit and it re-applies, keeping the edit.
|
|
114
|
+
|
|
115
|
+
**`undo`** puts your original memory file back and removes `.minnimemory/`.
|
|
106
116
|
|
|
107
117
|
Splitting is by **how often content is needed** and **how often it changes**:
|
|
108
118
|
|
|
@@ -113,27 +123,28 @@ Splitting is by **how often content is needed** and **how often it changes**:
|
|
|
113
123
|
|
|
114
124
|
## Install
|
|
115
125
|
|
|
116
|
-
Requires Node 18 or later
|
|
117
|
-
|
|
118
|
-
**Claude Code**, from inside the repo whose memory you want served (read-only: `check` until
|
|
119
|
-
the memory is compiled, `recall` once it is):
|
|
126
|
+
One line. Requires Node 18 or later and the `claude` CLI on `PATH`. Nothing is downloaded
|
|
127
|
+
except the npm package, and the server never writes your disk.
|
|
120
128
|
|
|
121
129
|
```bash
|
|
122
|
-
|
|
130
|
+
npx -y minnimemory install
|
|
123
131
|
```
|
|
124
132
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
133
|
+
That registers the MCP server for every project on this machine (it runs
|
|
134
|
+
`claude mcp add minnimemory -s user -- npx -y minnimemory mcp` and prints exactly that line).
|
|
135
|
+
Restart Claude Code. Done. Running it again is safe: it tells you it is already registered.
|
|
128
136
|
|
|
129
|
-
|
|
130
|
-
claude mcp add minnimemory -- npx -y minnimemory mcp --allow-write --include-auto-memory
|
|
131
|
-
```
|
|
137
|
+
Useful variants:
|
|
132
138
|
|
|
133
|
-
|
|
134
|
-
|
|
139
|
+
| you want | run |
|
|
140
|
+
|---|---|
|
|
141
|
+
| this repo only, not every project | `npx -y minnimemory install --scope project` |
|
|
142
|
+
| see the command without running it | `npx -y minnimemory install --dry-run` |
|
|
143
|
+
| re-register over an existing entry | `npx -y minnimemory install --force` |
|
|
144
|
+
| the config snippet for Cursor, Windsurf or another host | `npx -y minnimemory install --host cursor` (or `windsurf`, `json`) |
|
|
135
145
|
|
|
136
|
-
**Any other MCP host** (Cursor, Windsurf, Claude Desktop, an SDK client)
|
|
146
|
+
**Any other MCP host** (Cursor, Windsurf, Claude Desktop, an SDK client): put this in its MCP
|
|
147
|
+
config. The path is optional; without it the server uses its working directory.
|
|
137
148
|
|
|
138
149
|
```json
|
|
139
150
|
{
|
|
@@ -146,23 +157,48 @@ Code, then ask it to run `check`.
|
|
|
146
157
|
}
|
|
147
158
|
```
|
|
148
159
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
itself clone the repo, `npm ci && npm run build`, and run `node dist/cli.js` in place of `npx
|
|
154
|
-
minnimemory`.
|
|
160
|
+
**No MCP at all**: every verb below also runs from a terminal as `npx -y minnimemory <verb>`,
|
|
161
|
+
with nothing installed. `npm install -g minnimemory` gives you a `minnimemory` binary if you
|
|
162
|
+
prefer. Maintainers working on the compiler itself clone the repo, `npm ci && npm run build`,
|
|
163
|
+
and run `node dist/cli.js` in place of `npx minnimemory`.
|
|
155
164
|
|
|
156
165
|
## Use it
|
|
157
166
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
167
|
+
Four verbs, the same four whether your agent calls them or you type them:
|
|
168
|
+
|
|
169
|
+
| verb | what it does | writes anything? |
|
|
170
|
+
|---|---|---|
|
|
171
|
+
| `doctor` | audits your memory file: findings, how many tokens load every turn, drift since the last apply | no |
|
|
172
|
+
| `init` | shows the plan: what stays always-on, what becomes an OnDemandMemory file, the prefix before and after | no |
|
|
173
|
+
| `apply` | compiles (or re-applies after you edit a file), original backed up first | terminal: yes, to disk. MCP: returns the files and your agent writes them |
|
|
174
|
+
| `undo` | puts your original memory file back and removes `.minnimemory/` | terminal: yes. MCP: returns the original and what to delete |
|
|
175
|
+
|
|
176
|
+
The order is always the same: `doctor`, `init`, `apply`, then `doctor` again whenever you edit
|
|
177
|
+
a memory file by hand (it reports drift and `apply` brings it current). `undo` at any time.
|
|
161
178
|
|
|
162
|
-
###
|
|
179
|
+
### In Claude Code (agentic)
|
|
180
|
+
|
|
181
|
+
After the install, open Claude Code in your project and say what you want in plain words. The
|
|
182
|
+
server tells the agent the loop on connect, so these four requests are all it takes:
|
|
183
|
+
|
|
184
|
+
| you say | the agent calls | what you see |
|
|
185
|
+
|---|---|---|
|
|
186
|
+
| "run doctor on my memory" | `doctor` | the findings and the always-loaded token count |
|
|
187
|
+
| "show me the plan" | `init` | the split and the before/after, nothing written |
|
|
188
|
+
| "apply it" | `apply` | the files to write; the agent writes each one and Claude Code shows it to you as a diff to approve. Your original is the first file written, to `.minnimemory/original/` |
|
|
189
|
+
| "undo the memory compile" | `undo` | the original file written back and `.minnimemory/` removed, again as approved writes |
|
|
190
|
+
|
|
191
|
+
Every write goes through your own tool's approval prompt. The MCP server itself only reads.
|
|
192
|
+
|
|
193
|
+
### In the terminal
|
|
194
|
+
|
|
195
|
+
Every block below is the real output against `examples/CLAUDE.md`, a 75-line memory file for
|
|
196
|
+
a fictional bookkeeping API, shipped in this package.
|
|
197
|
+
|
|
198
|
+
**1. `doctor`: what is it costing?**
|
|
163
199
|
|
|
164
200
|
```
|
|
165
|
-
$ npx minnimemory doctor
|
|
201
|
+
$ npx -y minnimemory doctor
|
|
166
202
|
|
|
167
203
|
MM003 "Current status" (lines 6-11) holds a status heading and high
|
|
168
204
|
dated entries and status language in the always-loaded
|
|
@@ -190,15 +226,13 @@ $ npx minnimemory doctor
|
|
|
190
226
|
|
|
191
227
|
Every finding names a rule id, a file, a line range, and what to do about it. Nothing is changed.
|
|
192
228
|
|
|
193
|
-
|
|
229
|
+
**2. `init`: what would a compile do?**
|
|
194
230
|
|
|
195
|
-
`init`
|
|
196
|
-
|
|
197
|
-
findings `init` will not act on. If the verdict is "leave this file as it is", `--write` refuses
|
|
198
|
-
unless you pass `--force`: the tool will not quietly make a file more expensive.
|
|
231
|
+
`init` never writes; that is `apply`'s job. If the verdict is "leave this file as it is",
|
|
232
|
+
`apply` refuses unless you pass `--force`: the tool will not quietly make a file more expensive.
|
|
199
233
|
|
|
200
234
|
```
|
|
201
|
-
$ npx minnimemory init
|
|
235
|
+
$ npx -y minnimemory init
|
|
202
236
|
|
|
203
237
|
source: CLAUDE.md (689 tokens)
|
|
204
238
|
|
|
@@ -236,30 +270,55 @@ $ npx minnimemory init
|
|
|
236
270
|
create .minnimemory/OnDemandMemory/memory_write_protocol.md
|
|
237
271
|
overwrite CLAUDE.md
|
|
238
272
|
|
|
239
|
-
dry run, nothing written.
|
|
273
|
+
dry run, nothing written. Run "minnimemory apply" to compile.
|
|
240
274
|
```
|
|
241
275
|
|
|
242
|
-
|
|
276
|
+
**3. `apply`: do it**
|
|
243
277
|
|
|
244
|
-
```bash
|
|
245
|
-
npx minnimemory init --write
|
|
246
278
|
```
|
|
279
|
+
$ npx -y minnimemory apply
|
|
247
280
|
|
|
248
|
-
|
|
281
|
+
...the same file list as the plan, written...
|
|
282
|
+
create .minnimemory/OnDemandMemory/memory_write_protocol.md
|
|
283
|
+
overwrite CLAUDE.md
|
|
284
|
+
```
|
|
249
285
|
|
|
250
|
-
|
|
286
|
+
Your original is copied verbatim to `.minnimemory/original/CLAUDE.md.bak` before anything
|
|
287
|
+
else is touched. Run `doctor` again and it says "no drift since init".
|
|
251
288
|
|
|
252
|
-
|
|
253
|
-
|
|
289
|
+
**4. After a hand edit: `doctor`, then `apply` again**
|
|
290
|
+
|
|
291
|
+
Edit any file under `.minnimemory/OnDemandMemory/` or the stub freely. `doctor` reports what
|
|
292
|
+
moved; `apply` re-applies and keeps your edit.
|
|
293
|
+
|
|
294
|
+
```
|
|
295
|
+
$ npx -y minnimemory doctor
|
|
296
|
+
MM010 .minnimemory/OnDemandMemory/changelog.md was edited since med
|
|
297
|
+
drift: 1 file changed since init (MM010). Re-apply with: minnimemory apply
|
|
298
|
+
|
|
299
|
+
$ npx -y minnimemory apply
|
|
300
|
+
overwrite .minnimemory/manifest.json
|
|
301
|
+
overwrite CLAUDE.md
|
|
254
302
|
```
|
|
255
303
|
|
|
256
|
-
|
|
304
|
+
**5. `undo`: back to where you started**
|
|
305
|
+
|
|
306
|
+
```
|
|
307
|
+
$ npx -y minnimemory undo
|
|
308
|
+
|
|
309
|
+
restored CLAUDE.md from .minnimemory/original/CLAUDE.md.bak
|
|
310
|
+
deleted: .minnimemory
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
The result is byte-identical to the file you started with.
|
|
314
|
+
|
|
315
|
+
### Keep it honest in CI
|
|
257
316
|
|
|
258
317
|
`doctor` exits non-zero when findings reach the threshold, so memory bloat fails the build the
|
|
259
318
|
same way a lint error does.
|
|
260
319
|
|
|
261
320
|
```yaml
|
|
262
|
-
- run: npx minnimemory doctor --ci --fail-on med
|
|
321
|
+
- run: npx -y minnimemory doctor --ci --fail-on med
|
|
263
322
|
```
|
|
264
323
|
|
|
265
324
|
Exit codes: `0` clean, `1` findings at or above `--fail-on`, `2` execution error.
|
|
@@ -322,28 +381,54 @@ Audits. Never modifies anything. Works on a repo, a directory of memory files, o
|
|
|
322
381
|
|
|
323
382
|
### `minnimemory init [path]`
|
|
324
383
|
|
|
325
|
-
|
|
384
|
+
Previews. **Never writes** - `init` and `apply` are the same four-verb loop (`doctor`, `init`,
|
|
385
|
+
`apply`, `undo`) the MCP basic profile uses, and the CLI's only difference from MCP is who
|
|
386
|
+
writes: the CLI writes to disk itself, from `apply`; the MCP tools return the files for the
|
|
387
|
+
agent to write. Passing `--write` or `--update` to `init` prints one line ("init never writes;
|
|
388
|
+
use apply") and exits.
|
|
326
389
|
|
|
327
390
|
| flag | effect |
|
|
328
391
|
|---|---|
|
|
329
|
-
| `--
|
|
330
|
-
| `--force` | overwrite an existing `.minnimemory/`, and compile a file the plan's verdict says to leave alone |
|
|
331
|
-
| `--update` | recompile a compiled workspace from its stub and the OnDemandMemory files on disk, keeping hand edits. See [Keeping it current](#keeping-it-current) |
|
|
392
|
+
| `--force` | on a compiled workspace with no drift, preview the re-apply plan anyway; also previews compiling a file the plan's verdict says to leave alone |
|
|
332
393
|
| `--budget <n>` | always-loaded token budget AlwaysOnMemory must fit. AlwaysOnMemory-like sections that do not fit are routed to OnDemandMemory and listed in the plan. Default 2000 |
|
|
333
394
|
| `--profile <name>` | how much guidance to embed: `auto`, `none`, `routing`, `full`. Default `auto`: `none` when the source is under the budget, `routing` at or over it |
|
|
334
|
-
| `--allow-secrets` |
|
|
395
|
+
| `--allow-secrets` | preview as if a credential-shaped source were allowed through |
|
|
335
396
|
|
|
336
|
-
|
|
337
|
-
|
|
397
|
+
### `minnimemory apply [path]`
|
|
398
|
+
|
|
399
|
+
Writes. Looks at the workspace and does the right thing: an uncompiled compilable file gets a
|
|
400
|
+
fresh compile; a compiled workspace with drift gets re-applied, keeping every hand edit; a
|
|
401
|
+
compiled workspace with no drift prints "nothing to apply" and changes nothing. Same backups
|
|
402
|
+
(`.minnimemory/original/`, `.minnimemory/previous/`), refusals and flags as the old `init
|
|
403
|
+
--write`/`init --update --write` had:
|
|
404
|
+
|
|
405
|
+
| flag | effect |
|
|
406
|
+
|---|---|
|
|
407
|
+
| `--force` | compile a file the plan's verdict says to leave alone |
|
|
408
|
+
| `--budget <n>` | always-loaded token budget AlwaysOnMemory must fit. Default 2000 |
|
|
409
|
+
| `--profile <name>` | how much guidance to embed: `auto`, `none`, `routing`, `full`. Default `auto` |
|
|
410
|
+
| `--allow-secrets` | compile even when the source holds a credential-shaped string. Without it, `apply` refuses |
|
|
411
|
+
|
|
412
|
+
`init`/`apply` follow a pointer: if `CLAUDE.md` is only `@AGENTS.md` or "See `AGENTS.md`", they
|
|
413
|
+
compile `AGENTS.md`. Neither follows a symlink, in either direction.
|
|
414
|
+
|
|
415
|
+
### `minnimemory undo [path]`
|
|
416
|
+
|
|
417
|
+
Restores. Writes the host memory file back from `.minnimemory/original/<name>.bak` and removes
|
|
418
|
+
`.minnimemory/` (only after confirming it still holds a `manifest.json` - a cheap check that
|
|
419
|
+
this is really a minnimemory workspace). Restores the original always: the file as it was
|
|
420
|
+
before the first `apply`, whatever re-applies happened since. "nothing to undo" when not
|
|
421
|
+
compiled; a clear error when the original copy is missing (`doctor` reports that as a finding
|
|
422
|
+
before it matters). No flags.
|
|
338
423
|
|
|
339
424
|
### `minnimemory mcp [path]`
|
|
340
425
|
|
|
341
|
-
Starts an MCP server, `--profile basic` (four verbs,
|
|
342
|
-
OnDemandMemory list in their own prefix or that have no memory
|
|
343
|
-
picks the tool surface (`basic`/`full`); it is a different
|
|
344
|
-
(`auto`/`none`/`routing`/`full`, [below](#profiles)), which
|
|
345
|
-
gets embedded in a compile - same word, two unrelated knobs
|
|
346
|
-
it with your agent rather than running it by hand:
|
|
426
|
+
Starts an MCP server, `--profile basic` (the same four verbs, always registered) by default,
|
|
427
|
+
for hosts that cannot hold the OnDemandMemory list in their own prefix or that have no memory
|
|
428
|
+
file at all. `mcp`'s `--profile` picks the tool surface (`basic`/`full`); it is a different
|
|
429
|
+
flag from `init`'s `--profile` (`auto`/`none`/`routing`/`full`, [below](#profiles)), which
|
|
430
|
+
picks how much discipline guidance gets embedded in a compile - same word, two unrelated knobs
|
|
431
|
+
on two different commands. Register it with your agent rather than running it by hand:
|
|
347
432
|
|
|
348
433
|
```bash
|
|
349
434
|
claude mcp add minnimemory -- npx -y minnimemory mcp
|
|
@@ -351,66 +436,55 @@ claude mcp add minnimemory -- npx -y minnimemory mcp
|
|
|
351
436
|
|
|
352
437
|
Other hosts: see [Install](#install).
|
|
353
438
|
|
|
354
|
-
|
|
439
|
+
### `minnimemory install`
|
|
355
440
|
|
|
356
|
-
|
|
357
|
-
|
|
441
|
+
Registers minnimemory with the current host in one command instead of the manual `claude mcp
|
|
442
|
+
add` line above. With the `claude` CLI on PATH:
|
|
358
443
|
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
| compiled | `recall` | `recall`, `sync` |
|
|
363
|
-
| a memory directory (Layout B, no manifest) | `check`, `recall` | `check`, `recall`, `optimize` |
|
|
444
|
+
```bash
|
|
445
|
+
npx -y minnimemory install
|
|
446
|
+
```
|
|
364
447
|
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
448
|
+
| flag | effect |
|
|
449
|
+
|---|---|
|
|
450
|
+
| `--scope <name>` | `user`, `project`, or `local`, same meaning as `claude mcp add -s`. Default `user` |
|
|
451
|
+
| `--write` | append `--allow-write` to the served command |
|
|
452
|
+
| `--auto-memory` | append `--include-auto-memory` to the served command |
|
|
453
|
+
| `--dry-run` | print the command without running it, exit 0 |
|
|
454
|
+
| `--force` | remove an existing registration first, then re-add |
|
|
455
|
+
| `--host <name>` | `cursor`, `windsurf`, or `json`: print the `mcpServers` JSON snippet for that host and its usual config path, write nothing, exit 0 |
|
|
456
|
+
|
|
457
|
+
Idempotent: an existing registration is reported, with the command to change it, not duplicated.
|
|
458
|
+
Without the `claude` CLI on PATH it prints the manual line and the JSON snippet instead, and
|
|
459
|
+
exits 2. If `claude` itself errors, its stderr is printed and it exits 1.
|
|
460
|
+
|
|
461
|
+
Also the default when `minnimemory` runs with no subcommand and no terminal attached (see
|
|
462
|
+
[`mcp`](#minnimemory-mcp-path) above): a bare `minnimemory` prints this usage text at a real
|
|
463
|
+
terminal, and serves the MCP server otherwise, which is how a host that just spawned it always
|
|
464
|
+
looks.
|
|
465
|
+
|
|
466
|
+
#### The basic profile (default): `doctor`, `init`, `apply`, `undo` (DESIGN.md 6.7)
|
|
467
|
+
|
|
468
|
+
A one-time converter: four read-only tools, all always registered - no phase probe, no
|
|
469
|
+
`--allow-write` gate. The server never writes the user's disk on this profile: `apply` returns
|
|
470
|
+
the exact files a compile or re-apply would write, `undo` returns the original file to restore
|
|
471
|
+
and the paths to delete, and the calling agent writes them itself, through its own host's
|
|
472
|
+
diff-and-approve. `--allow-write` has no effect here (it still gates `full`'s three write
|
|
473
|
+
tools, below) and just prints one line saying so.
|
|
371
474
|
|
|
372
475
|
| tool | returns |
|
|
373
476
|
|---|---|
|
|
374
|
-
| `
|
|
375
|
-
| `
|
|
376
|
-
| `
|
|
377
|
-
| `
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
(needs `--include-auto-memory`), the same resolution `scan`/`reorganize` use in the full profile,
|
|
386
|
-
below. None of the four take `profile`, `episodicJson` or `allowSecrets` over MCP - the CLI keeps
|
|
387
|
-
those for maintainers; the MCP tools always compile with `profile: "auto"` and refuse rather than
|
|
388
|
-
override.
|
|
389
|
-
|
|
390
|
-
#### Memory folders without compiling (2026-09-16)
|
|
391
|
-
|
|
392
|
-
A third launch shape, alongside "not compiled" and "compiled" above: a memory directory an index
|
|
393
|
-
file (`MEMORY.md`, `index.md`, `INDEX.md`, or `README.md`) plus topic `.md` files, or a Claude
|
|
394
|
-
Code auto-memory folder, with no `.minnimemory/` at all. On that shape the server registers
|
|
395
|
-
`recall` alongside `check` (and `optimize` with `--allow-write`), backed by `recallDir` instead
|
|
396
|
-
of a manifest: it builds the same section-level units `recall` builds from a compiled workspace's
|
|
397
|
-
OnDemandMemory files, straight off the topic files on disk, and ranks them the same way (stemmed
|
|
398
|
-
BM25, `router.ts`). An index file's hook lines ("`- [Title](file.md) - hook text`") count as
|
|
399
|
-
triggers, the same way `Research/Pipeline/replay_ranker.mjs` already treats them for its own
|
|
400
|
-
offline replay. It is lexical and fully offline - no embeddings, no model call, no compile step -
|
|
401
|
-
so it works on a repo you have not run `init` against at all, and on Claude Code's own
|
|
402
|
-
OS-level auto-memory folder unmodified. `README.md` and any `archive/` subfolder are never
|
|
403
|
-
treated as topic files. The same command is available from the CLI:
|
|
404
|
-
|
|
405
|
-
```bash
|
|
406
|
-
minnimemory recall <path> <query...> # full section content, best first
|
|
407
|
-
minnimemory recall <path> <query...> --headings # just "file > heading path (n tokens)" lines
|
|
408
|
-
```
|
|
409
|
-
|
|
410
|
-
Real per-turn cost of the two tools together, `Research/TokenTest/tool_cost.mjs`
|
|
411
|
-
(`Research/docs/2026-09-16-tool-cost.md`; see the table under
|
|
412
|
-
[When the MCP route pays off](#when-the-mcp-route-pays-off)): 740 tokens read-only, 1,397 with
|
|
413
|
-
`--allow-write`.
|
|
477
|
+
| `doctor(target?, budget?, format?)` | audit findings, always-loaded token count against budget, and - for an already-compiled target - drift since the last `apply` (MM010), plus one finding when the original backup `undo` needs is missing |
|
|
478
|
+
| `init(target?, budget?, force?, format?)` | never writes: on an uncompiled compilable file, the compile plan - AlwaysOnMemory/OnDemandMemory split, session bounds, compile-or-leave verdict; on a compiled workspace, the re-apply plan when `doctor` would report drift, else "nothing to re-apply" (`force: true` previews it anyway); on a memory directory, the audit findings plus one line that folder reorganization is `--profile full`'s job (`scan` then `reorganize`) |
|
|
479
|
+
| `apply(target?, budget?, force?, format?)` | the files a compile or re-apply would write, as `{ path, content }` pairs, backup first, for the agent to write itself. First compile: `.minnimemory/original/<name>.bak`, then the stub, `AlwaysOnMemory.md`, every OnDemandMemory file, `manifest.json`, `original/.gitignore`. Drifted workspace: `.minnimemory/previous/<name>.bak`, then only the files whose content changed. No drift: "nothing to write", no files. Refused (no files) on a credential-shaped source (MM008, no override over MCP) or a leave-verdict compile unless `force: true`. `format: "json"` returns `{ files?, instructions? }` |
|
|
480
|
+
| `undo(target?, format?)` | the restore set: the dev's original memory file, from `.minnimemory/original/<name>.bak`, to write back over the stub, and the paths to delete (`.minnimemory/`), for the agent to write and delete itself. Restores the original always - the file as it was before the first `apply`, whatever re-applies happened since. No compiled workspace: "nothing to undo". Backup missing: says so and points at `doctor`. `format: "json"` returns `{ files?, delete?, instructions? }` |
|
|
481
|
+
|
|
482
|
+
`doctor` and `init` accept the literal `"auto-memory"` as `target` where it makes sense (needs
|
|
483
|
+
`--include-auto-memory`), the same resolution `scan`/`reorganize` use in the full profile,
|
|
484
|
+
below; `apply` and `undo` on a memory directory answer that reorganization lives under
|
|
485
|
+
`--profile full`. None of the four tools take `profile`, `episodicJson` or `allowSecrets` over
|
|
486
|
+
MCP - the CLI keeps those for maintainers; `apply` always compiles with `profile: "auto"` and
|
|
487
|
+
refuses rather than override.
|
|
414
488
|
|
|
415
489
|
#### Claude Code hook (experimental, 2026-09-16)
|
|
416
490
|
|
|
@@ -435,15 +509,15 @@ Cost: about the size of the printed block (600 tokens by default, `--headings` f
|
|
|
435
509
|
heading-path lines), added to the transcript on every turn the hook fires - not a one-time
|
|
436
510
|
`tools/list` charge like the MCP tools above, so start with `--headings` and widen only if the
|
|
437
511
|
heading line alone is not enough to decide whether to open the file. This is experimental until
|
|
438
|
-
|
|
439
|
-
it against a real session, not the offline unit tests in `tests/hook.test.ts`).
|
|
512
|
+
it has been measured in a live session, not only by its offline unit tests.
|
|
440
513
|
|
|
441
514
|
#### The full profile (`--profile full`): today's nine, for maintainers
|
|
442
515
|
|
|
443
516
|
`--profile full` registers the original nine tools, unchanged in name, schema and behaviour, so
|
|
444
517
|
anything already built against them keeps working. Use it for the session where you are
|
|
445
|
-
maintaining the compiler itself,
|
|
446
|
-
|
|
518
|
+
maintaining the compiler itself, for per-turn `recall` retrieval, or for driving a
|
|
519
|
+
memory-directory reorganization directly with `scan` and `reorganize` (basic profile only
|
|
520
|
+
audits a memory directory, via `doctor`/`init`).
|
|
447
521
|
|
|
448
522
|
| tool | returns |
|
|
449
523
|
|---|---|
|
|
@@ -453,111 +527,137 @@ through `optimize`'s facts-then-ops loop.
|
|
|
453
527
|
| `doctor(target?, budget?, only?, ignore?, format?)` | audit findings, always-loaded token count against budget, and (for a compiled target) drift since init. `format: "json"` returns the machine-readable report instead of text |
|
|
454
528
|
| `plan(target?, update?, budget?, format?)` | what compiling `target` would do - AlwaysOnMemory, OnDemandMemory, session bounds, the compile-versus-leave verdict - without writing anything. `format: "json"` returns a compact summary object instead of the rendered report |
|
|
455
529
|
| `scan(target?, detail?, files?)` | structured inventory of memory files: frontmatter, sections, volatility evidence, keywords, cross-file duplicates. `target` is a path, or the literal `"auto-memory"` (needs `--include-auto-memory`). `detail: "summary"` (default) returns per-file counts and rollups; `"full"` returns every section. `files` restricts to exact rel matches, with unmatched names in `unknownFiles`. |
|
|
456
|
-
| `apply(target?, budget?)` | compiles `target`, same as `
|
|
457
|
-
| `update(target?, budget?)` | recompiles an already-compiled `target` from its stub and OnDemandMemory files, same as `
|
|
530
|
+
| `apply(target?, budget?)` | compiles `target`, same as the CLI's `apply` on an uncompiled file. Refuses an already-compiled target - call `update()` instead - and a compile that would not shrink the prefix or holds a credential-shaped string, with no override over MCP. Needs `--allow-write` |
|
|
531
|
+
| `update(target?, budget?)` | recompiles an already-compiled `target` from its stub and OnDemandMemory files, same as the CLI's `apply` on a drifted workspace. Needs `--allow-write` |
|
|
458
532
|
| `reorganize(target?, ops)` | applies `write_file` / `delete_file` / `rename_file` operations to `target` (default: this server's root, or `"auto-memory"`, needs `--include-auto-memory`). Needs `--allow-write` |
|
|
459
533
|
|
|
460
534
|
`recall`/`modules`/`outline` need a compiled workspace. `doctor`/`plan`/`scan` do not: they work
|
|
461
|
-
on any target, compiled or not. `apply`/`update` are the single-file compile path (what the
|
|
462
|
-
`
|
|
535
|
+
on any target, compiled or not. `apply`/`update` are the single-file compile path (what the
|
|
536
|
+
CLI's `apply` does on an uncompiled file or a drifted workspace, respectively); `reorganize` is
|
|
537
|
+
the multi-file path.
|
|
538
|
+
|
|
539
|
+
A `recall()` query that matches nothing does not just say so: the response inlines the routing
|
|
540
|
+
list a query-less call returns, so the caller lands on the right `module` without a second
|
|
541
|
+
round trip, followed by "No file matched; pick from the list above and call recall() with
|
|
542
|
+
module set."
|
|
543
|
+
|
|
544
|
+
Recall over a memory folder with no `.minnimemory/` manifest at all - an index file (`MEMORY.md`,
|
|
545
|
+
`index.md`, `INDEX.md`, or `README.md`) plus topic `.md` files, or a Claude Code auto-memory
|
|
546
|
+
folder - is backed by `recallDir` instead: it builds the same section-level units `recall` builds
|
|
547
|
+
from a compiled workspace's OnDemandMemory files, straight off the topic files on disk, and ranks
|
|
548
|
+
them the same way (stemmed BM25, `router.ts`). An index file's hook lines
|
|
549
|
+
("`- [Title](file.md) - hook text`") count as triggers, the same way recall over a compiled
|
|
550
|
+
workspace treats manifest triggers. It is lexical and fully offline - no embeddings, no model
|
|
551
|
+
call, no compile step - so it works on a repo you have not run `init`/`apply` against at all,
|
|
552
|
+
and on Claude Code's own OS-level auto-memory folder unmodified. `README.md` and any `archive/`
|
|
553
|
+
subfolder are never treated as topic files. The same ranking is available from the CLI, with no
|
|
554
|
+
profile flag needed:
|
|
555
|
+
|
|
556
|
+
```bash
|
|
557
|
+
minnimemory recall <path> <query...> # full section content, best first
|
|
558
|
+
minnimemory recall <path> <query...> --headings # just "file > heading path (n tokens)" lines
|
|
559
|
+
```
|
|
463
560
|
|
|
464
561
|
#### The loop
|
|
465
562
|
|
|
466
|
-
Point a client at the basic profile and the intended flow is: **
|
|
467
|
-
|
|
563
|
+
Point a client at the basic profile and the intended flow is: **doctor, then init, then
|
|
564
|
+
apply**, with **doctor again** whenever a memory file changes, and **undo** to get the
|
|
565
|
+
original back.
|
|
468
566
|
|
|
469
567
|
```
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
568
|
+
doctor() - what does this file/directory cost right now?
|
|
569
|
+
- (show the person the result before doing anything)
|
|
570
|
+
init() - what would a compile (or, later, a re-apply) do? preview only
|
|
571
|
+
apply() - get the files a compile (or re-apply) would write
|
|
572
|
+
- (write them yourself, original first, through your own diff/approve)
|
|
573
|
+
doctor() - after someone hand-edits a memory file, this reports drift
|
|
574
|
+
apply() - get the re-apply files again
|
|
575
|
+
undo() - get the original memory file back, and what to delete
|
|
475
576
|
```
|
|
476
577
|
|
|
477
|
-
**
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
and what the number is: `Research/docs/2026-09-16-tool-cost.md`):
|
|
578
|
+
**All four tools are always registered, and every tool definition is charged to the client's
|
|
579
|
+
prefix on every turn, called or not.** Measured costs (`approx-v2` tokenizer, an offline
|
|
580
|
+
estimate, 2026-09-17):
|
|
481
581
|
|
|
482
|
-
| launch |
|
|
483
|
-
|
|
484
|
-
| `mcp` (default, basic
|
|
485
|
-
| `mcp --allow-write` (basic) |
|
|
486
|
-
| `mcp` (
|
|
487
|
-
| `mcp --allow-write`
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
"
|
|
496
|
-
its definition every turn.
|
|
497
|
-
|
|
498
|
-
Ranking (`recall`) is whole-word keyword overlap against the triggers `init` computed. No
|
|
499
|
-
embeddings, no model call, no network. A query that shares no vocabulary with an OnDemandMemory
|
|
500
|
-
file's triggers will not find it, and that is a deliberate trade for determinism, not a bug.
|
|
582
|
+
| launch | tools advertised | prefix cost |
|
|
583
|
+
|---|---|---|
|
|
584
|
+
| `mcp` (default, basic) | `doctor`, `init`, `apply`, `undo` | 812 tokens |
|
|
585
|
+
| `mcp --allow-write` (basic, no effect) | `doctor`, `init`, `apply`, `undo` | 812 tokens |
|
|
586
|
+
| `mcp --profile full` (read-only) | `recall`, `modules`, `outline`, `scan`, `doctor`, `plan` | 1,666 tokens |
|
|
587
|
+
| `mcp --profile full --allow-write` | + `apply`, `update`, `reorganize` | 2,670 tokens |
|
|
588
|
+
|
|
589
|
+
A tool that was not registered is absent from `tools/list` and answers "tool not found" if
|
|
590
|
+
called; nothing is present-and-refusing, because a refusing tool still costs its definition
|
|
591
|
+
every turn - the reason the basic profile stays at four tools rather than growing back toward
|
|
592
|
+
the full profile's nine. `recall` is not one of the four: with it gone, nothing runs per turn on
|
|
593
|
+
this profile, and the compiled stub's own OnDemandMemory list still routes the agent to the
|
|
594
|
+
right file in any host, no tool needed. `recall` returns to the basic profile as the "live
|
|
595
|
+
agent" once the converter is proven (DESIGN.md 6.7); for now it stays under `--profile full`.
|
|
501
596
|
|
|
502
597
|
#### When the MCP route pays off
|
|
503
598
|
|
|
504
|
-
The
|
|
505
|
-
compiled
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
- `
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
- `
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
#### Multi-file reorganization (
|
|
599
|
+
The basic profile's 812 tokens is a flat cost, paid every turn regardless of workspace state -
|
|
600
|
+
no setup/compiled split to average over, and no per-turn retrieval cost either, since `recall`
|
|
601
|
+
is not part of this profile. The shipped `examples/CLAUDE.md` breaks even at 407 tokens per turn
|
|
602
|
+
(see [Use it](#use-it)); the tool definitions alone sit above that, but `apply`/`undo` are a
|
|
603
|
+
one-time cost at compile and restore time, not paid every turn a session runs long. For per-turn
|
|
604
|
+
retrieval against a large memory (`--profile full`'s `recall`), the route pays off on a memory
|
|
605
|
+
whose always-loaded prefix sits well above the 2,000-token budget, where `recall` replaces an
|
|
606
|
+
agent reading the whole file on every task rather than a routed section. A small memory file is
|
|
607
|
+
cheaper served the way this README's own examples are: compiled once, read directly by the
|
|
608
|
+
agent, no server attached.
|
|
609
|
+
|
|
610
|
+
#### The lifecycle tools (`doctor`/`init`/`apply`/`undo` on basic, or `doctor` + `plan` + `apply` + `update` under `--profile full`)
|
|
611
|
+
|
|
612
|
+
The CLI's `doctor`/`init`/`apply`/`undo`, over MCP, so an agent applies the interface without
|
|
613
|
+
shelling out - except the write itself, which is the agent's, not the server's. `target` is a
|
|
614
|
+
path relative to the server's root (default: the root itself); it is confined to the root the
|
|
615
|
+
same way `reorganize`'s paths are - no absolute paths, no `..` segments, no escaping via a
|
|
616
|
+
symlink.
|
|
617
|
+
|
|
618
|
+
- `doctor` and `init` never write. `doctor` audits; `init` previews the compile plan on an
|
|
619
|
+
uncompiled file, or the re-apply plan on a drifted compiled workspace.
|
|
620
|
+
- `apply` returns the files a fresh compile, or a re-apply (only the files that changed), would
|
|
621
|
+
write, as `{ path, content }` pairs, for the agent to write itself - backed up first, original
|
|
622
|
+
before anything else, exactly as `applyPlan` orders them. Accepts `format: "json"` for a
|
|
623
|
+
machine-readable shape (`{ files?, instructions? }`) instead of the rendered report.
|
|
624
|
+
- `apply` is refused - no files, one line why - on a source holding a credential-shaped string
|
|
625
|
+
(MM008; no `allowSecrets` override over MCP, same as the full profile's `apply()`), and on a
|
|
626
|
+
compile that would not shrink the always-loaded prefix unless `force: true` is passed. Neither
|
|
627
|
+
refusal changes what `doctor`/`init` report: the findings and the verdict are always there.
|
|
628
|
+
- On an already-compiled workspace with no drift, `apply` returns `files: undefined` and the
|
|
629
|
+
response says "nothing to write".
|
|
630
|
+
- `undo` returns the dev's original file (from `.minnimemory/original/<name>.bak`) and the paths
|
|
631
|
+
to delete. No backup present: says so and points at `doctor`, which flags a missing backup as
|
|
632
|
+
a finding before it matters.
|
|
633
|
+
|
|
634
|
+
#### Multi-file reorganization (`--profile full`: `scan` + `reorganize`)
|
|
540
635
|
|
|
541
636
|
`init` compiles one host file. A Claude Code auto-memory folder is a different shape: an
|
|
542
637
|
OnDemandMemory-style list plus dozens of topic files, already multi-file, needing content moved
|
|
543
|
-
*between* files rather than split out of one.
|
|
544
|
-
the
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
638
|
+
*between* files rather than split out of one. LLM-authored reorganize ops on a folder like that
|
|
639
|
+
wait for the answer-quality harness (DESIGN.md 6.6, point 4), so this is a `--profile full`
|
|
640
|
+
capability for now, not part of the basic profile's `doctor`/`init`/`apply`/`undo` surface:
|
|
641
|
+
|
|
642
|
+
- **Facts first, and only facts.** `scan` returns structure: frontmatter
|
|
643
|
+
(`name`/`description`/`metadata.type`), section boundaries, which sections carry volatility
|
|
644
|
+
evidence and why, candidate routing keywords, and blocks duplicated across files. It never
|
|
645
|
+
classifies, merges, or decides on its own.
|
|
550
646
|
- **The calling agent makes the judgment.** Which sections are semantic vs episodic vs
|
|
551
647
|
procedural, what merges, what is stale, where content belongs under O1-O5. That reasoning is
|
|
552
|
-
the agent's, done in the agent's own session, from the facts `
|
|
553
|
-
- **Then `
|
|
554
|
-
|
|
648
|
+
the agent's, done in the agent's own session, from the facts `scan` just handed it.
|
|
649
|
+
- **Then `reorganize` executes** the explicit `write_file` / `delete_file` / `rename_file`
|
|
650
|
+
operations the agent proposed.
|
|
651
|
+
|
|
652
|
+
`doctor`/`init` on a memory directory still audit it and say, in one line, that reorganization
|
|
653
|
+
lives under `--profile full`.
|
|
555
654
|
|
|
556
|
-
Both take a `target`: a path relative to the server root (default: the
|
|
557
|
-
literal `"auto-memory"`, which resolves to the operator's OS-level Claude
|
|
558
|
-
for this root - a real directory outside the server root, so it only
|
|
559
|
-
launched with `--include-auto-memory`; without the flag,
|
|
560
|
-
error rather than silently falling back to the server
|
|
655
|
+
Both `scan` and `reorganize` take a `target`: a path relative to the server root (default: the
|
|
656
|
+
root itself), or the literal `"auto-memory"`, which resolves to the operator's OS-level Claude
|
|
657
|
+
Code auto-memory folder for this root - a real directory outside the server root, so it only
|
|
658
|
+
resolves when the server is launched with `--include-auto-memory`; without the flag,
|
|
659
|
+
`"auto-memory"` is refused with a clear error rather than silently falling back to the server
|
|
660
|
+
root.
|
|
561
661
|
|
|
562
662
|
No LLM is embedded in this package and none is called by it. `init`, `doctor` and `scan` stay
|
|
563
663
|
fully deterministic and offline. The intelligence is the agent already driving the tools, not an
|
|
@@ -576,13 +676,14 @@ Safety, non-negotiable and not skippable:
|
|
|
576
676
|
- **Every `write_file`/`delete_file`/`rename_file` path must end in `.md`.** Containment alone
|
|
577
677
|
still let a write land on an extensionless file like `.git/hooks/pre-commit` inside a confined
|
|
578
678
|
root; this operates on memory files, not arbitrary files a confined write could otherwise reach.
|
|
579
|
-
- **
|
|
580
|
-
|
|
581
|
-
|
|
679
|
+
- **The basic profile is read-only by construction.** The server never writes the user's disk on
|
|
680
|
+
it; the agent writes what `apply()`/`undo()` return, through its own host's diff-and-approve.
|
|
681
|
+
`apply`/`update`/`reorganize` (full profile only) are still gated behind `--allow-write` and are
|
|
682
|
+
not registered at all without it, so a client cannot call them.
|
|
582
683
|
|
|
583
684
|
In Claude Code the file-based route is usually enough, because the agent can read an
|
|
584
685
|
OnDemandMemory file directly. MCP tool definitions themselves cost prefix tokens on every turn, which is why the
|
|
585
|
-
server registers only the profile you launch it with; weigh even the default
|
|
686
|
+
server registers only the profile you launch it with; weigh even the default four-tool basic
|
|
586
687
|
profile before registering the server on a repo with only a few OnDemandMemory files.
|
|
587
688
|
|
|
588
689
|
### `minnimemory bench [path]`
|
|
@@ -676,8 +777,8 @@ OnDemandMemory files on disk. Edit either freely.
|
|
|
676
777
|
|
|
677
778
|
**Coming back to a memory you optimised earlier? Start with `doctor`.** On a compiled workspace
|
|
678
779
|
it reports whether anything has drifted from what `init` wrote, and names the command to fix it
|
|
679
|
-
(over MCP, `
|
|
680
|
-
|
|
780
|
+
(over MCP, `doctor` does the same on a compiled target, and also flags a compiled workspace
|
|
781
|
+
whose `.minnimemory/original/` backup is missing, so `undo` cannot restore it):
|
|
681
782
|
|
|
682
783
|
```
|
|
683
784
|
$ npx minnimemory doctor
|
|
@@ -685,14 +786,14 @@ $ npx minnimemory doctor
|
|
|
685
786
|
...findings...
|
|
686
787
|
|
|
687
788
|
compiled workspace: 4 OnDemandMemory files in .minnimemory/
|
|
688
|
-
drift: 1 file changed since init (MM010). Re-apply with: minnimemory
|
|
789
|
+
drift: 1 file changed since init (MM010). Re-apply with: minnimemory apply
|
|
689
790
|
```
|
|
690
791
|
|
|
691
792
|
When there is nothing to do it says so plainly ("no drift since init ... Nothing to re-apply"),
|
|
692
793
|
so a re-run costs you one second and no thinking. `doctor` never writes. To apply:
|
|
693
794
|
|
|
694
795
|
```bash
|
|
695
|
-
npx minnimemory
|
|
796
|
+
npx minnimemory apply
|
|
696
797
|
```
|
|
697
798
|
|
|
698
799
|
It strips the generated parts of the stub, routes anything you appended to it the same way a
|
|
@@ -721,19 +822,21 @@ body, so a `project` file that blends current state with a changelog compiles in
|
|
|
721
822
|
OnDemandMemory files, and an episodic section is never merged into a neighbour. `scan` reports the kind for every section
|
|
722
823
|
of a memory directory too.
|
|
723
824
|
|
|
724
|
-
With
|
|
725
|
-
`OnDemandMemory/<name>.json`: the heading, any preamble, and
|
|
726
|
-
continuation lines, all verbatim, so the markdown rebuilds
|
|
727
|
-
`bench`, `doctor
|
|
728
|
-
|
|
729
|
-
|
|
825
|
+
With **`--episodic-json`** (O3, opt in, on `init`'s preview and `apply`'s write), an episodic
|
|
826
|
+
OnDemandMemory file is written as `OnDemandMemory/<name>.json`: the heading, any preamble, and
|
|
827
|
+
one entry per dated bullet with its continuation lines, all verbatim, so the markdown rebuilds
|
|
828
|
+
byte for byte. `recall`, `outline`, `bench`, `doctor`, and a re-applied workspace, read JSON
|
|
829
|
+
OnDemandMemory files as the markdown they stand for. The point is Anthropic's documented
|
|
830
|
+
finding that a model is less likely to rewrite or summarize JSON it was only meant to append
|
|
831
|
+
to. Off by default until it has run in a second host.
|
|
730
832
|
|
|
731
|
-
`init` also
|
|
833
|
+
`init`/`apply` also plan/emit one OnDemandMemory file the source did not contain:
|
|
732
834
|
**`OnDemandMemory/memory_write_protocol.md`**, the eleven-item memory write protocol (O9),
|
|
733
835
|
routed by the OnDemandMemory list under `memory, remember, save, write, note, changelog`, so the
|
|
734
|
-
agent opens it when a task is about saving memory and is never charged for it otherwise.
|
|
735
|
-
|
|
736
|
-
accounts for one OnDemandMemory list line in the prefix figures
|
|
836
|
+
agent opens it when a task is about saving memory and is never charged for it otherwise. A
|
|
837
|
+
re-apply (`apply` on a drifted workspace) re-emits it, so a protocol change reaches every
|
|
838
|
+
workspace on the next apply. It accounts for one OnDemandMemory list line in the prefix figures
|
|
839
|
+
above.
|
|
737
840
|
|
|
738
841
|
OnDemandMemory paths are relative to the file the list sits in: `OnDemandMemory/<name>.md`
|
|
739
842
|
inside `.minnimemory/AlwaysOnMemory.md`, and `.minnimemory/OnDemandMemory/<name>.md` in the stub
|
|
@@ -742,10 +845,10 @@ the bare path from the stub, missing, and giving up; the stub has named the full
|
|
|
742
845
|
|
|
743
846
|
## Security
|
|
744
847
|
|
|
745
|
-
- `doctor`, `init`, and `mcp` make no network calls and never run a subprocess.
|
|
746
|
-
- `init`
|
|
747
|
-
cannot point `CLAUDE.md` or an OnDemandMemory file at a file outside the checkout.
|
|
748
|
-
- `
|
|
848
|
+
- `doctor`, `init`, `apply`, `undo`, and `mcp` make no network calls and never run a subprocess.
|
|
849
|
+
- `init`/`apply` refuse a symlinked source and refuse to write through a symlink, so a cloned
|
|
850
|
+
repo cannot point `CLAUDE.md` or an OnDemandMemory file at a file outside the checkout.
|
|
851
|
+
- `apply` refuses to write when the source holds a credential-shaped string, unless you pass
|
|
749
852
|
`--allow-secrets`. The verbatim backup in `.minnimemory/original/` ships with a `.gitignore`
|
|
750
853
|
so it stays local.
|
|
751
854
|
- The MCP server validates `manifest.json` and only serves files that resolve inside
|
|
@@ -769,11 +872,11 @@ verbatim, the original never destroyed.
|
|
|
769
872
|
See [`docs/DESIGN.md` section 2, "What it is not"](docs/DESIGN.md#2-what-it-is-not): not a
|
|
770
873
|
conversation compressor, not a RAG index over your code, not a proxy or model router, not a
|
|
771
874
|
summariser. One addition specific to this package: **not a compiler for a memory routing list.**
|
|
772
|
-
`init`
|
|
773
|
-
override - compiling a routing list re-files its hook lines as content and orphans
|
|
774
|
-
file. A memory directory is `
|
|
775
|
-
|
|
776
|
-
|
|
875
|
+
`init`/`apply` refuse `MEMORY.md`, or any file that is mostly links to topic files beside it,
|
|
876
|
+
with no override - compiling a routing list re-files its hook lines as content and orphans
|
|
877
|
+
every topic file. A memory directory is `doctor`/`init`'s job to audit (registered by default,
|
|
878
|
+
no write access needed) and `--profile full`'s `scan`/`reorganize` job to restructure (facts
|
|
879
|
+
first, then `ops`, backup first).
|
|
777
880
|
|
|
778
881
|
## Measurement policy
|
|
779
882
|
|
|
@@ -814,7 +917,7 @@ has been exercised end to end, and this README will not claim otherwise until th
|
|
|
814
917
|
|
|
815
918
|
Moved to [`docs/DESIGN.md` section 11, "Milestones"](docs/DESIGN.md#11-milestones) (2026-09-16):
|
|
816
919
|
merged with that section's own milestone table, which had drifted out of date. Publish state
|
|
817
|
-
lives there too (
|
|
920
|
+
lives there too (`1.0.0-beta.1` has been on npm since 2026-09-17).
|
|
818
921
|
|
|
819
922
|
## License
|
|
820
923
|
|