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.
Files changed (56) hide show
  1. package/README.md +352 -249
  2. package/dist/bench.d.ts +0 -67
  3. package/dist/bench.js +0 -31
  4. package/dist/benchReport.d.ts +0 -8
  5. package/dist/benchReport.js +0 -8
  6. package/dist/bounds.d.ts +0 -24
  7. package/dist/bounds.js +0 -19
  8. package/dist/cli.d.ts +3 -12
  9. package/dist/cli.js +184 -71
  10. package/dist/compile.d.ts +0 -97
  11. package/dist/compile.js +0 -127
  12. package/dist/discover.d.ts +0 -103
  13. package/dist/discover.js +0 -121
  14. package/dist/doctor.d.ts +0 -5
  15. package/dist/doctor.js +0 -7
  16. package/dist/episodic.d.ts +0 -29
  17. package/dist/episodic.js +0 -26
  18. package/dist/hook.d.ts +0 -32
  19. package/dist/hook.js +0 -35
  20. package/dist/index.d.ts +0 -5
  21. package/dist/index.js +0 -5
  22. package/dist/init.d.ts +39 -47
  23. package/dist/init.js +88 -70
  24. package/dist/install.d.ts +40 -0
  25. package/dist/install.js +101 -0
  26. package/dist/instructions.d.ts +1 -45
  27. package/dist/instructions.js +0 -90
  28. package/dist/mcpServer.d.ts +2 -121
  29. package/dist/mcpServer.js +243 -537
  30. package/dist/paths.d.ts +0 -21
  31. package/dist/paths.js +0 -21
  32. package/dist/recall.d.ts +0 -71
  33. package/dist/recall.js +1 -94
  34. package/dist/recallDir.d.ts +0 -33
  35. package/dist/recallDir.js +0 -49
  36. package/dist/reorganize.d.ts +0 -31
  37. package/dist/reorganize.js +0 -66
  38. package/dist/report.d.ts +0 -7
  39. package/dist/report.js +2 -21
  40. package/dist/router.d.ts +0 -85
  41. package/dist/router.js +0 -87
  42. package/dist/rules.d.ts +0 -17
  43. package/dist/rules.js +1 -137
  44. package/dist/scan.d.ts +0 -35
  45. package/dist/scan.js +1 -39
  46. package/dist/text.d.ts +0 -110
  47. package/dist/text.js +0 -117
  48. package/dist/tokenizer.d.ts +0 -23
  49. package/dist/tokenizer.js +0 -30
  50. package/dist/types.d.ts +2 -78
  51. package/dist/types.js +0 -4
  52. package/dist/version.d.ts +1 -7
  53. package/dist/version.js +1 -7
  54. package/dist/writeProtocol.d.ts +0 -14
  55. package/dist/writeProtocol.js +0 -14
  56. 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 is an MCP server whose tools audit that file,
5
- compile it into a small AlwaysOnMemory body plus OnDemandMemory files loaded only when
6
- relevant, and serve it back on demand. The `minnimemory` command line underneath is the build layer those tools call;
7
- it is documented further down for maintainers.
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)). Rerun them yourself (after the build in
21
- [Install](#install)): `npx minnimemory init node_modules/minnimemory/examples/CLAUDE.md`.
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. `doctor`, `init`, and `bench`
28
- have no runtime dependencies; only `mcp` pulls in the MCP SDK.
29
-
30
- > **Status: 1.0.0-beta.1, prepared for a public beta; not yet on npm (2026-09-16).** `doctor`, `init`, and `bench` are implemented and tested from the
31
- > CLI. `mcp` is the product and still early: it works, is tested in-process, and `recall` (only, not the other tools)
32
- > has been exercised in a second host (Claude Code loading it as an external MCP server). The
33
- > default client surface is `--profile basic`: `check` before the workspace is compiled and
34
- > `recall` after, chosen from the workspace at launch; `optimize` and `sync` (same split) are
35
- > opt-in behind `--allow-write`, back up before every write, and have not yet been exercised
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
- Two commands do the work, plus an optional read-only MCP server for hosts that need one.
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`** compiles your memory file into a small AlwaysOnMemory body plus OnDemandMemory files
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. The package is `minnimemory` on npm; nothing else to download.
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
- claude mcp add minnimemory -- npx -y minnimemory mcp
130
+ npx -y minnimemory install
123
131
  ```
124
132
 
125
- Add `--allow-write` to let the agent also compile and maintain the file (`optimize` before the
126
- compile, `sync` after; every write is backed up first), and `--include-auto-memory` to include Claude Code's own
127
- auto-memory folder for this project:
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
- ```bash
130
- claude mcp add minnimemory -- npx -y minnimemory mcp --allow-write --include-auto-memory
131
- ```
137
+ Useful variants:
132
138
 
133
- Use `-s user` to register it once for every project instead of the current one. Restart Claude
134
- Code, then ask it to run `check`.
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), in its MCP config:
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
- The path is optional; without it the server uses its working directory.
150
-
151
- **Command line**, for the `doctor`/`init`/`bench` commands below: `npx minnimemory doctor`, or
152
- `npm install -g minnimemory` for a `minnimemory` binary. Maintainers working on the compiler
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
- Every block below is the real output of that command against
159
- `examples/CLAUDE.md`, a 75-line memory file for a fictional bookkeeping API, shipped in this
160
- package.
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
- ### 1. Find out what your setup costs
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
- ### 2. Preview the compile
229
+ **2. `init`: what would a compile do?**
194
230
 
195
- `init` is a **dry run by default**. It prints the full plan and writes nothing. The plan carries
196
- the decision as well as the shape: exact session bounds, a plain verdict, and the `doctor`
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. Pass --write to apply.
273
+ dry run, nothing written. Run "minnimemory apply" to compile.
240
274
  ```
241
275
 
242
- ### 3. Apply it
276
+ **3. `apply`: do it**
243
277
 
244
- ```bash
245
- npx minnimemory init --write
246
278
  ```
279
+ $ npx -y minnimemory apply
247
280
 
248
- Your original is copied verbatim to `.minnimemory/original/` before anything is touched.
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
- ### 4. Check the result
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
- ```bash
253
- npx minnimemory doctor
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
- ### 5. Keep it honest in CI
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
- Compiles. **Dry run by default.**
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
- | `--write` | actually apply. Without it, prints the plan and exits |
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` | compile even when the source holds a credential-shaped string. Without it, `--write` refuses |
395
+ | `--allow-secrets` | preview as if a credential-shaped source were allowed through |
335
396
 
336
- `init` follows a pointer: if `CLAUDE.md` is only `@AGENTS.md` or "See `AGENTS.md`", it compiles
337
- `AGENTS.md`. It never follows a symlink, in either direction.
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, two registered per launch) by default, for hosts that cannot hold the
342
- OnDemandMemory list in their own prefix or that have no memory file at all. `mcp`'s `--profile`
343
- picks the tool surface (`basic`/`full`); it is a different flag from `init`'s `--profile`
344
- (`auto`/`none`/`routing`/`full`, [below](#profiles)), which picks how much discipline guidance
345
- gets embedded in a compile - same word, two unrelated knobs on two different commands. Register
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
- #### The basic profile (default): `check`, `optimize`, `sync`, `recall`
439
+ ### `minnimemory install`
355
440
 
356
- Four verbs, two registered per launch. Which two follows from the workspace on disk, with no
357
- flag to set: the server looks once, at launch, for a `.minnimemory/` directory under its root.
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
- | workspace at launch | read-only | with `--allow-write` |
360
- |---|---|---|
361
- | not compiled (no `.minnimemory/`) | `check` | `check`, `optimize` |
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
- `recall` cannot answer without a manifest, and `check`/`optimize` have no first compile left to
366
- plan once one exists, so registering the other half would charge its definition every turn for
367
- a tool that session could not use. The surface is fixed for the life of the process: a session
368
- that compiles mid-way (`optimize` says so in its response) relaunches to get `recall` and `sync`.
369
- One consequence: compiling a second, uncompiled file under a root that already holds a
370
- `.minnimemory/` directory is not reachable over MCP on this profile; the CLI's `init` covers it.
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
- | `check(target?, budget?, format?)` | audit findings, always-loaded token count against budget, drift since init for an already-compiled target, and - when `target` is a single compilable file - the compile plan: AlwaysOnMemory/OnDemandMemory split, session bounds, compile-or-leave verdict. When `target` is a memory directory, already compiled, or an index file, the plan half is left out and one line says why plus what to call instead. `format: "json"` returns `{ doctor, plan, planUnavailableReason }` |
375
- | `optimize(target?, budget?, force?, ops?)` | write. A compilable file: compiles it, or - already compiled - re-applies it instead and says so. A memory directory: with no `ops`, returns `scan`-shape facts plus an instruction block describing the op shapes to propose; with `ops`, applies them (`write_file`/`delete_file`/`rename_file`), backing up every `.md` file first. `force` forwards to the compile path's own force. Needs `--allow-write` |
376
- | `sync(target?, budget?, force?)` | write. Checks a compiled `target` for drift (MM010) and, only if something drifted, re-applies it, keeping hand edits. Changes nothing when there is no drift unless `force: true`, a deliberate re-apply (on a compiled target this is the same operation as `optimize`, which is not registered on the compiled surface); never compiles a fresh target. Needs `--allow-write` |
377
- | `recall(query?, file?, headingsOnly?, maxTokens?)` | `query` given: the memory sections most relevant to it, content inline, best first, under a token cap, restricted to `file` when given. `query` omitted: the OnDemandMemory routing list, no content. `headingsOnly: true` with `file`: that file's headings only. `headingsOnly` without `file` is an error. When its index rebuild finds an OnDemandMemory file changed since `init` wrote it (MM010, the same hash `check`/`doctor` use), the response names the drifted files and points at `sync()`, or at the CLI when `--allow-write` is off |
378
-
379
- A `recall()` query that matches nothing does not just say so: the response inlines the same
380
- routing list `query` omitted returns, so the caller lands on the right `file` without a second
381
- round trip, followed by "No file matched; pick from the list above and call recall() with file
382
- set." (`module` on the full profile's `recall`).
383
-
384
- `check`/`optimize`/`sync` accept the literal `"auto-memory"` as `target` where it makes sense
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
- the gate in `Research/FlagShipInterfaces/README.md` part (c) runs (a live Pipeline run measuring
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, or driving a memory-directory reorganization directly rather than
446
- through `optimize`'s facts-then-ops loop.
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 `init --write`. 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` |
457
- | `update(target?, budget?)` | recompiles an already-compiled `target` from its stub and OnDemandMemory files, same as `init --update`. Needs `--allow-write` |
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 CLI's
462
- `init` and `init --update` do); `reorganize` is the multi-file path.
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: **check, then optimize, then
467
- sync**, with **recall** in between turns once something is compiled.
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
- check() - what does this file/directory cost, and what would compiling it do?
471
- - (show the person the result before doing anything)
472
- optimize() - compile it (or apply a reorganize plan you both approved)
473
- recall() - per-turn retrieval against the compiled workspace, in later turns
474
- sync() - after someone hand-edits a memory file, catch the workspace back up
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
- **The server only advertises the tools you asked for, and the basic profile only the half the
478
- workspace can use.** Every tool definition is charged to the client's prefix on every turn,
479
- called or not. Real costs (`Research/TokenTest/tool_cost.mjs`, `approx-v2` tokenizer; full table
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 | workspace | tools advertised | prefix cost |
483
- |---|---|---|---|
484
- | `mcp` (default, basic, read-only) | not compiled | `check` | 364 tokens |
485
- | `mcp --allow-write` (basic) | not compiled | `check`, `optimize` | 1,021 tokens |
486
- | `mcp` (default, basic, read-only) | compiled | `recall` | 329 tokens |
487
- | `mcp --allow-write` (basic) | compiled | `recall`, `sync` | 620 tokens |
488
- | `mcp` (default, basic, read-only) | memory directory | `recall`, `check` | 740 tokens |
489
- | `mcp --allow-write` (basic) | memory directory | `recall`, `check`, `optimize` | 1,397 tokens |
490
- | `mcp --profile full` (read-only) | any | `recall`, `modules`, `outline`, `scan`, `doctor`, `plan` | 1,666 tokens |
491
- | `mcp --profile full --allow-write` | any | + `apply`, `update`, `reorganize` | 2,668 tokens |
492
-
493
- The compiled rows are what a working session holds - well under this tool's own 2,000-token
494
- always-loaded budget. A tool that was not registered is absent from `tools/list` and answers
495
- "tool not found" if called; nothing is present-and-refusing, because a refusing tool still costs
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 cost that matters is the compiled one, because setup happens once: a working session on a
505
- compiled workspace holds `recall` for 329 tokens of definitions per turn, or `recall` and `sync`
506
- for 620 with `--allow-write`. The setup surface (`check` 364, `check` and `optimize` 1,021) is
507
- paid only by the session that does the first compile, and that session relaunches afterwards.
508
- The shipped `examples/CLAUDE.md` breaks even at 407 tokens per turn (see [Use it](#use-it)). The
509
- read-only definitions alone sit under that, but they are not the whole bill: every `recall`
510
- answer adds the sections it returns, up to 1,500 tokens by default, so one routed answer on that
511
- example costs more than the compile saved on that turn. The MCP route pays for itself when the
512
- per-turn prefix saving is bigger than the definition cost plus whatever `recall` returns for a
513
- typical query - in practice, a memory whose always-loaded prefix sits well above the 2,000-token
514
- budget, where the alternative `recall` is replacing is an agent reading the whole file on every
515
- task rather than a routed section. A small memory file is cheaper served the way this README's
516
- own examples are: compiled once, read directly by the agent, no server attached.
517
-
518
- #### Single-file compile (`check` + `optimize`, or `doctor` + `plan` + `apply` + `update` under `--profile full`)
519
-
520
- The CLI's `init`/`init --update`, over MCP, so an agent applies the interface without shelling
521
- out. `target` is a path relative to the server's root (default: the root itself); it is confined
522
- to the root the same way `reorganize`'s paths are - no absolute paths, no `..` segments, no
523
- escaping via a symlink.
524
-
525
- - `check` never writes; it is registered whenever the root is not yet compiled, with or
526
- without `--allow-write`. It audits (`doctor`) and, when `target` is a compilable file,
527
- previews the compile (`plan`) in the same response. Accepts `format: "json"`
528
- for a machine-readable shape instead of the rendered report.
529
- - `optimize` is gated behind `--allow-write`, same as `sync`. On a compilable file it refuses a
530
- compile that would not shrink the always-loaded prefix, refuses a source holding a
531
- credential-shaped string, and - on an already-compiled target - re-applies it instead of
532
- refusing outright, saying so in the response (`--profile full`'s `apply` refuses that case
533
- and points at `update()`; `optimize` just does what `update()` would). `sync` only ever
534
- re-applies, and only when `doctor`'s MM010 drift check finds something to re-apply or the
535
- call passes `force: true` (a deliberate recompile, reachable on the compiled surface where
536
- `optimize` is not registered); it keeps hand edits to AlwaysOnMemory text and OnDemandMemory
537
- file content, and backs up the pre-update stub first.
538
-
539
- #### Multi-file reorganization (`optimize` with `ops`, or `scan` + `reorganize` under `--profile full`)
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. `optimize`, pointed at a memory directory, splits
544
- the work along the same deliberate line the full profile's `scan`/`reorganize` pair always has:
545
-
546
- - **Facts first, and only facts.** With no `ops`, `optimize` returns `scan`-shape structure:
547
- frontmatter (`name`/`description`/`metadata.type`), section boundaries, which sections carry
548
- volatility evidence and why, candidate routing keywords, and blocks duplicated across files. It
549
- never classifies, merges, or decides on its own.
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 `optimize` just handed it.
553
- - **Then `optimize` again, with `ops`, executes.** The same explicit `write_file` / `delete_file`
554
- / `rename_file` operations `reorganize` takes, applied the same way.
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 root itself), or the
557
- literal `"auto-memory"`, which resolves to the operator's OS-level Claude Code auto-memory folder
558
- for this root - a real directory outside the server root, so it only resolves when the server is
559
- launched with `--include-auto-memory`; without the flag, `"auto-memory"` is refused with a clear
560
- error rather than silently falling back to the server root.
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
- - **Write access is opt-in per launch.** Without `--allow-write` the server is read-only:
580
- `optimize`/`sync` (basic) and `apply`/`update`/`reorganize` (full) are not registered at all,
581
- so a client cannot call them.
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 two-tool basic
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, `check` does the same on a compiled target, and on the basic profile's compiled
680
- surface, where `check` is absent, `recall` reports drift itself when it rebuilds its index):
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 init --update
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 init --update
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 **`init --episodic-json`** (O3, opt in), an episodic OnDemandMemory file is written as
725
- `OnDemandMemory/<name>.json`: the heading, any preamble, and one entry per dated bullet with its
726
- continuation lines, all verbatim, so the markdown rebuilds byte for byte. `recall`, `outline`,
727
- `bench`, `doctor` and `init --update` read JSON OnDemandMemory files as the markdown they stand for. The
728
- point is Anthropic's documented finding that a model is less likely to rewrite or summarize
729
- JSON it was only meant to append to. Off by default until it has run in a second host.
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 emits one OnDemandMemory file the source did not contain:
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
- `init --update` re-emits it, so a protocol change reaches every workspace on the next update. It
736
- accounts for one OnDemandMemory list line in the prefix figures above.
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` refuses a symlinked source and refuses to write through a symlink, so a cloned repo
747
- cannot point `CLAUDE.md` or an OnDemandMemory file at a file outside the checkout.
748
- - `init` refuses `--write` when the source holds a credential-shaped string, unless you pass
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` refuses `MEMORY.md`, or any file that is mostly links to topic files beside it, with no
773
- override - compiling a routing list re-files its hook lines as content and orphans every topic
774
- file. A memory directory is `check`'s job to audit and `optimize`'s (`mcp --allow-write`: facts
775
- first, then `ops`, backup first) to restructure. Auditing alone needs no write access - `check`
776
- is registered by default.
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 (as of 2026-09-16 the package is prepared but not yet on npm).
920
+ lives there too (`1.0.0-beta.1` has been on npm since 2026-09-17).
818
921
 
819
922
  ## License
820
923