npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

minnimemory

v1.5.0

Published

MinniMemoryMCP: an MCP server that shrinks what Claude Code and Codex load every turn. It splits your memory files (CLAUDE.md, AGENTS.md) into a small AlwaysOnMemory part and OnDemandMemory files that load only when a task needs them: init, apply, undo, d

Readme

MinniMemoryMCP

Curated memory for AI agents, served over MCP. Your AI coding agent re-reads its entire project memory file on every turn, most of it irrelevant to the task in front of it, and an edited character near the top of that file busts prompt caching for everything after it. MinniMemoryMCP audits the file, compiles it into a small AlwaysOnMemory body plus OnDemandMemory files loaded only when relevant, and can undo the whole thing in one step. Four verbs, the same in Claude Code and in the terminal: init, doctor, apply, undo. Deterministic, lossless, offline: no model, no key, no network, and the MCP server never writes your memory files (its one write is init's record of where Claude Code loads from).

Built by Minni AI. Docs: minniai.com/minnimemorymcp/docs. Measured results: minniai.com/evidence. AI agents: start at minniai.com/agents.md. Watch: MinniMemoryMCP product demo, how it reduces your token usage.

Try it in the terminal first

Requires Node 18 or later. No install needed to try it once. init is always the first step: it finds what Claude Code loads, saves those locations, and previews the compile. Nothing is written to your memory until you run apply. The full loop, against examples/CLAUDE.md (the fixture shipped in this package), real output (approx-v2 tokenizer, an offline estimate; trimmed for length):

$ npx -y minnimemory init .

  memory map for /path/to/your/repo: every file Claude Code loads, by its own rules
  every session: 897 tokens

  MM003  "Current status" (lines 28-33) holds a status heading and  high
         status language in the always-loaded prefix
         -> move it to an OnDemandMemory file; editing it here invalidates
         the prompt cache every time
  ...2 more findings...

  always-loaded, files this plan rewrites: 897 -> 389 tokens (-56.6%)
  best case: kept only on turns that open none of the moved files. Measured on another memory with an agent that can read and search, whole sessions cost 24.0% less and answers held (judge 76 of 81 vs 74 for the original; ledger 2026-10-06).
  verdict: compile. Every turn with no routed file open saves 508 tokens; a turn with every
  routed file open (613 tokens) costs 105 more than today. It pays unless routed text is open
  on nearly every turn.

  operations:
    write     .minnimemory/.gitignore                             +5 -0
    copy      1 file(s) -> .minnimemory/original/ (CLAUDE.md -> CLAUDE.md.bak)
    write     .claude/OnDemandMemory/CLAUDE__history.md           +28 -0
    write     .claude/OnDemandMemory/CLAUDE__detail.md            +28 -0
    write     CLAUDE.md                                           +7 -47
    ...

  plan: 7eb0e22e815143d0
  dry run, nothing written. To write these files, run:
    npx -y minnimemory apply --plan 7eb0e22e815143d0 --budget 2000 .

$ npx -y minnimemory apply --plan 7eb0e22e815143d0 --budget 2000 .
  7 file(s) written; originals are under .minnimemory/. Undo any time: npx -y minnimemory undo .

$ npx -y minnimemory doctor
  nothing to apply: no drift since the last apply

$ npx -y minnimemory undo
  restored 1 file(s) in /path/to/your/repo
  deleted: 5 path(s), .minnimemory/ included

doctor is for later, after init: it refuses until init has run here ("run init first"). With no folder, doctor, apply and undo use the folder init saved. Its exit code (0 clean, 1 findings at or above --fail-on, 2 an error) is what a CI step keys on.

Your Claude Code memory folder (~/.claude/projects/<project>/memory) is loaded with files outside it: your ~/.claude/CLAUDE.md and anything it imports. minnimemory never searches for those; it reads only what it is told Claude Code loads, so it cannot guess wrong. In Claude Code the agent tells it (below). In a terminal, give it Claude Code's own load log, or the files by hand:

$ npx -y minnimemory init ~/.claude/projects/<project>/memory --from-log
$ npx -y minnimemory init ~/.claude/projects/<project>/memory --loaded ~/.claude/CLAUDE.md

init checks each path and saves the set for apply, doctor and undo. apply on a memory folder refuses until something was reported, because moving a file that an unseen outside file imports would break that import; --only-this-folder says nothing outside loads it.

apply --plan <hash> recomputes the plan from what is on disk and refuses if it no longer matches the hash init/doctor showed you, so what you saw is exactly what gets written. Plain apply (no --plan) works too and skips that check. Every command the tool prints is the one to paste, with the target path when it is not the current directory. Run from an installed copy (the npx cache, a global install, a checkout) the command calls that same copy directly, node "<path to minnimemory>/cli.js" apply --plan <hash>, so the plan is recomputed by the build that made it; only when the tool cannot tell where it runs from does it print npx -y minnimemory ....

Install for Claude Code

npm i -g minnimemory
minnimemory install

The first line installs the package once; the second registers the MCP server for every project on this machine (runs claude mcp add minnimemory -s user -- node "<path to minnimemory>/cli.js" mcp and prints exactly that line: a direct call to the installed copy, so Claude Code does not re-resolve the package through npx on every launch), turns on two prompt hooks by default (the memory hook and the drift notice, see below), and prints the next step. Restart Claude Code. Running it again is safe: it tells you it is already registered. After upgrading the package, run it again: it repoints the server and the hooks at the new copy.

The registration points at the copy install ran from, so that copy has to stay. Run as npx -y minnimemory install, it would be the npx cache, which npm clears on its own; the server would then show "Connection closed" and every hook would fail with no message. So from the npx cache install writes nothing and prints the two lines above.

Or as a Claude Code plugin

/plugin install minnimemory --marketplace MinniAI-com/minnimemory-plugin

The same release, the same server and the same hooks, installed and removed through /plugin, with nothing written to your settings.json by hand. Needs Claude Code 2.1.275 or later for the one-line form (older: claude plugin marketplace add MinniAI-com/minnimemory-plugin, then claude plugin install minnimemory@minniai) and Node 18.3 or later on your PATH. Pick one route: if minnimemory install ran on this machine, run minnimemory uninstall first (npx -y minnimemory uninstall for an older npx registration), or you get two servers and every hook twice. Updates come with claude plugin update minnimemory@minniai, or turn on auto-update for the minniai marketplace in /plugin; claude plugin uninstall minnimemory@minniai removes it. The plugin repo holds generated files only, built from the release tag (docs/DESIGN.md 7.1).

Useful variants of install:

| you want | run | |---|---| | this repo only, not every project | minnimemory install --scope project | | see the command without running it | minnimemory install --dry-run | | re-register over an existing entry | minnimemory install --force | | skip the hooks | minnimemory install --no-hook | | remove the registration and the hooks it added | minnimemory install --remove |

The memory hook (UserPromptSubmit, minnimemory hook) runs before every prompt and places the one short section of memory the prompt needs into the turn, only when the always-loaded memory does not already hold a better match, once per session. The agent answers in one call instead of opening or searching files. In a continuous 27-task session on our Control Case it cut the session's cost by a third with answers graded as good (measured 2026-10-11; the number reaches this README through the results ledger, like every figure here).

The drift notice hook (UserPromptSubmit) tells the agent when a memory file has changed since the last apply, so you never have to remember to run doctor by hand. It checks the project and the project's Claude Code memory folder, prints one short notice, only on drift, only once per distinct change. install writes it as a direct call to the installed copy, node "<path to minnimemory>/cli.js" drift, which costs one node start per prompt (about 0.15 s measured; a bare node is 0.08 s). It is never written as npx -y minnimemory drift: that form re-resolves the package on every prompt and measured 1.3 to 1.7 s. --no-hook skips it at install time; install --remove takes out both the MCP registration and the hook entry it added, leaving every other key and every other hook in your Claude Code settings untouched.

Install for Codex

Codex loads one chain of AGENTS.md files every turn: $CODEX_HOME/AGENTS.md, then one file per folder from the repo root down to your working directory. The project files share project_doc_max_bytes (32 KiB by default): the file that crosses it is cut there and nothing after it is added. Nothing loads on demand, so a long AGENTS.md is paid in full on every turn and whatever sits past the cap never reaches the model. The same four verbs trim it the same way.

npm i -g minnimemory
minnimemory install --host codex

This runs codex mcp add minnimemory -- node "<path to minnimemory>/cli.js" mcp --host codex (printed, and idempotent) and adds the two UserPromptSubmit hooks to ~/.codex/hooks.json (--scope project writes <repo>/.codex/hooks.json; Codex has no local scope). Without the codex binary it prints the [mcp_servers.minnimemory] block to paste into ~/.codex/config.toml and exits 2. Then open Codex and run /hooks once to trust the two minnimemory hooks. Do not skip this: Codex skips an untrusted hook, and without the memory hook the sections moved to OnDemandMemory/ never reach a turn. Until the hook has run, init says so in its map. Then ask Codex to run init. In a terminal: npx -y minnimemory init . --host codex. Codex's load set is fully determined by the files and config.toml, so --from-log and --loaded are not needed; the host is detected when CODEX_HOME is set or your Codex config registers minnimemory, and --host codex pins it. If you set CODEX_HOME, install passes it on to the server (--env CODEX_HOME=...), because Codex starts MCP servers without it.

In codex exec (no one to approve a tool call), Codex refuses MCP calls that need approval. The four verbs only read, so you can let them run without asking:

[mcp_servers.minnimemory]
default_tools_approval_mode = "approve"

Codex does not show MCP prompts, so the /mcp__minnimemory__<verb> slash commands are Claude Code only; in Codex, ask for the verb by name.

What is different on Codex: the map shows the chain (layer, file, bytes, loaded) and the cap in force (a file cut by the cap shows PART: first N bytes); doctor adds MM022 (a file past the cap) and MM023 (AGENTS.override.md shadowing an AGENTS.md); apply compiles the AGENTS.md Codex reads (the override file when present), puts routed pieces in OnDemandMemory/ beside it when the repo has no .claude/ folder, and refuses a plan whose compiled file would still be over the cap. A file that already fits under the cap, and so loads whole, is left as it is: splitting it cost recall on Codex (--force compiles it anyway). Started in a subfolder, one apply writes every file the session loads: your user AGENTS.md, the git root's and the subfolder's, each with its own backups, and one undo there puts them all back. The discovery record lives under $CODEX_HOME/minnimemory/. Nested AGENTS.md files below the root are listed with their size and not compiled. If your project has no AGENTS.md of its own, init works on your user file ($CODEX_HOME/AGENTS.md, which Codex loads in every project) and says so; doctor, apply and undo then follow it, with no folder or with the project named. In Codex, the agent tells init what Codex loaded for it, the way Codex shows it: the folder from each "AGENTS.md instructions for" header, and user for your user file; a guessed path is refused. Codex's own memories ($CODEX_HOME/memories/) are generated by Codex: the map lists them with their size, and they are never compiled. Measured on Claude Code; Codex measurement in progress (section 8 of the design).

Other MCP hosts (Cursor, Windsurf, Claude Desktop, SDK clients): install --host cursor and --host windsurf print the mcpServers entry to paste, but the hook and the load model are not built for them, and nothing there is exercised end to end.

Use it

Four verbs, the same four whether your agent calls them or you type them:

| verb | what it does | writes anything? | |---|---|---| | init | always first: takes where Claude Code loads from (your agent passes it; in a terminal --from-log or --loaded), checks and saves it, then the map of every file Claude Code loads (when, whose, tokens), the audit and the diff of every file apply would write, then the command to run | only its record of those locations, in your Claude config folder; never a memory file | | doctor | after init, never first: the audit, drift since the last apply, the re-apply diff | no | | apply | writes what init/doctor showed, originals backed up first; --plan <hash> checks nothing moved since you looked | terminal: yes, to disk. MCP: no. It returns the command to run and the list of operations (paths and line counts, no content), and your agent runs the command through your approval | | undo | puts your original memory files back and removes .minnimemory/ | terminal: yes. MCP: no. It returns the command and the operations the same way |

The order is always the same: init, then apply. A week later, after you have edited a memory file by hand, doctor, then apply again. undo at any time. doctor before init refuses and says to run init first.

It works on two shapes, through one engine. A host file (CLAUDE.md, AGENTS.md, GEMINI.md, .cursorrules) is trimmed in place: the file itself becomes the AlwaysOnMemory body plus a fenced OnDemandMemory list, and routed pieces land beside it in .claude/OnDemandMemory/. A memory folder (an index such as Claude Code's MEMORY.md plus topic files, or the project's own Claude Code auto-memory folder) is sorted in place: every topic file a linked host imports moves into AlwaysOnMemory/, trimmed the same way; every other topic file moves into OnDemandMemory/, untouched; routed pieces join it there. A topic file your index never linked gets a list line of its own, with trigger words, so it stops being a dead end; a file whose name marks it as a copy (x (old).md, x.bak.md, x_v1.md) is left off the list and named in the plan. The always-loaded set of a memory folder also counts the files outside it that load it, because Claude Code loads them on every turn too: your ~/.claude/CLAUDE.md when it imports from the folder, directly or through a chain (CLAUDE.md -> @AGENTS.md, or a stub that imports a dotfiles file which imports from the folder), and a CLAUDE.md or AGENTS.md that names the folder in a list item or a link. minnimemory never searches for those files: it reads only the files it is told Claude Code loads (the agent passes them to init from its own context; in a terminal --from-log reads Claude Code's own load log, or --loaded <path> names each one), and works out from their lines which of them load the folder. The report lists each linked file and how, the reported files that load nothing in the folder, and any place the report and the lines disagree. An @import line that changes is shown as its own block in the diff. A project root reads only itself: no parent CLAUDE.md, no user files. With no folder named and nothing recorded, the terminal asks and an MCP tool asks the agent to ask you.

Claude Code names its memory folder itself (~/.claude/projects/<project>/memory by default, or the folder an autoMemoryDirectory setting points at), and the agent passes that path to init as it sees it, so the folder is never worked out from a slug. The MCP server accepts that one folder outside the project it runs in, because Claude Code named it.

A file with __ in its name is the tool's (<parent>__history.md, <parent>__detail.md for a project root; the same names for a sorted folder's sources): a merge of every dated, volatile or task-specific section that parent routed out, one piece per reason so the index stays short. Every other file - AlwaysOnMemory/, OnDemandMemory/'s plain topic files, the index itself - is yours, edited the way you always have.

Before, a memory folder and the user-level host that imports from it:

~/.claude/CLAUDE.md                     loaded every turn
  @.../memory/feedback_a.md
~/.claude/projects/<project>/memory/
├── MEMORY.md                           index, loaded every turn
├── feedback_a.md                       always loaded: rules + incident history + dated notes
└── project_x.md                        on demand, nobody imports it

After apply:

~/.claude/CLAUDE.md                     same text; only the import path changed
  @.../memory/AlwaysOnMemory/feedback_a.md
~/.claude/projects/<project>/memory/
├── MEMORY.md                           same hook lines, link targets updated, list appended
├── AlwaysOnMemory/
│   └── feedback_a.md                   the rules only, same file name
├── OnDemandMemory/
│   ├── project_x.md                    moved, untouched
│   └── feedback_a__history.md          the dated notes routed out of feedback_a
└── .minnimemory/                       bookkeeping: manifest.json, original/, previous/

In Claude Code

After the install, open Claude Code in your project and say what you want in plain words. The server tells the agent the loop on connect, so these four requests are all it takes:

| you say | the agent calls | what you see | |---|---|---| | "clean up my memory" | init, with the auto memory folder and every file Claude Code shows as loaded in its context | the files that load your memory and how, then the findings and a summary of the plan: one line per file (action, path, lines added/removed), the moves and the import rewrite in full. Those locations are saved, so nothing is asked again | | "apply it" | apply | the command npx -y minnimemory apply --plan <hash> [path] to run and the operations it performs, one line each. Your originals are the first files written, to .minnimemory/original/ | | "check my memory" (a week later) | doctor | the findings, what drifted since the last apply, and the re-apply plan, or "nothing to re-apply" | | "undo the memory compile" | undo | the command that restores the originals and removes .minnimemory/, and the operations it performs |

The same four steps are slash commands. The server exposes each verb as an MCP prompt, and Claude Code lists a server's prompts as /mcp__<server>__<prompt>, so after the install these appear in the / menu:

/mcp__minnimemory__init
/mcp__minnimemory__doctor
/mcp__minnimemory__apply
/mcp__minnimemory__undo

Each one hands the agent a one-line instruction to call the matching tool; nothing is written by the command itself. Add a folder after it (/mcp__minnimemory__init C:\path\to\memory) when the target is not the recorded one.

Every write goes through your own tool's approval prompt. The MCP server itself only reads, and it never sends your files' content through the model: apply/undo return the command and the operation list (about 240 tokens on the fixture above, about 300 on an 85-file memory folder); content: true adds the files to write, for an agent that cannot run commands; backups are listed as copies to make (from -> to), since their content is the file already on disk. init/doctor return a summary diff over MCP by default (the plan table plus one line per file); pass diff: "full" for the complete unified diff the terminal always shows.

What gets generated

A project root:

your-repo/
  CLAUDE.md                       AlwaysOnMemory body + the fenced OnDemandMemory list
  .claude/
    OnDemandMemory/
      <parent>__history.md        dated, volatile sections, merged
      <parent>__detail.md         task-specific sections, merged (over about 1,500 tokens they
                                  are split into <parent>__detail-<section>.md pieces instead)
  .minnimemory/
    manifest.json                 token counts, hashes, triggers, provenance
    original/
      CLAUDE.md.bak               verbatim copy of what was there before

The OnDemandMemory list inside the host file is a routing manifest, not a summary:

<!-- minnimemory:ondemand-list -->
# OnDemandMemory

AlwaysOnMemory ends here. Read one file below only when the task matches its words.
New memory files go in .claude/OnDemandMemory/.

- `.claude/OnDemandMemory/CLAUDE__history.md`: test, src, error, deploys, status, services
<!-- /minnimemory:ondemand-list -->

manifest.json records what came from where: per-file token counts, content hashes for staleness detection, the keyword triggers, and the source line range each routed piece came from.

Commands

The CLI and the MCP basic profile share the same four lifecycle verbs; the only difference is who writes: the CLI writes to disk itself, the MCP tools return the one command to run and the operations it performs (file content only on request, content: true).

minnimemory init [path]

init is always the first step. It takes where Claude Code loads from (the agent passes it over MCP; in a terminal --from-log, --loaded or --memory-dir), checks every path, and saves it in your Claude config folder for apply, doctor, undo and the hooks: the one thing init writes, never a memory file. Then the map of every file Claude Code loads here: for a project, its own CLAUDE.md / AGENTS.md, CLAUDE.local.md, .claude/rules/ (a rule with paths: frontmatter loads only when a matching file is read), subfolder files Claude reads when it works there and every @ import inside it; for a memory folder, its index, the files it loads and the reported files that load it. Each file is tagged with when it loads, whose it is, and its tokens. --map prints only the map (--json for the data); init --json puts the map under map, beside doctor and plan.

The map starts with a setup block, so you know how the project is set up before anything is proposed: the host file Claude Code starts from, the file it points at when it is only a pointer (CLAUDE.md holding @AGENTS.md), the one file apply will rewrite, and whether that file is already compiled. When the project holds an AGENTS.md that Claude Code does not load, the map ends with a not loaded by Claude Code group that names each one and why: a CLAUDE.md in the same folder takes its place, or a CLAUDE.md higher up switches AGENTS.md off and no pointer sits beside it. Those files count toward no total. An AGENTS.md host is compiled, audited and undone exactly as a CLAUDE.md host is.

install also adds an InstructionsLoaded hook, which records what Claude Code actually loads for each project in a small file under your Claude config folder (machine-local, never in a repo). init --from-log reads it as the report of what loads your memory folder. And a PostToolUse hook on Read logs which OnDemandMemory files your sessions open (file names and counts only, in the same config folder); after 10 sessions doctor flags a file Claude read in most of them (MM024), since a file nearly every session reads is cheaper always-loaded. minnimemory stores no prompt text.

Then the first-time preview: the audit, then the plan with a unified diff of every file apply would overwrite and the full content of every file it would create, then the command to run. It never writes a memory file: passing --write or --update prints one line ("init never writes; use apply") and exits.

On a memory folder the plan sorts every always-loaded topic file into AlwaysOnMemory/, trimmed in place, and every other topic file into OnDemandMemory/, untouched; routed pieces join OnDemandMemory/ there, one per parent per reason. The always-loaded files are the ones you import on every turn, so that import is the placement decision: every stable section is a candidate to stay, whatever its heading says, and "volatile" means a status heading, a changelog-shaped body or repeated status phrases, never a date cited in a rule's rationale. With no --budget, the budget keeps every stable section and moves only the volatile ones; when nothing is volatile the plan says so, tells you what a lower budget would save (from a real second plan), and leaves the choice to you. A lower --budget is shared fairly: a file that fits an equal share stays whole, the largest files split the rest, and a heading-less file over its share keeps its leading paragraphs and routes the rest as <name>__detail.md. A single host file's default budget is 60% of the file, never under 2,000. On a file over about 3,300 tokens, where 60% is above that floor, the saving lands at 40% or more with the rules still in the file; a smaller file saves less, since the floor lets it keep more: its rule sections and what every task needs (commands, build, test, architecture) stay, by content rather than by heading alone, and its records, references and one-task runbooks move; a section over the room keeps its head and routes the rest as one "(continued)" piece. The plan prints the budget it used and names every section kept out to fit, so change --budget with the numbers in front of you. Sections that read as hard rules (a heading or first line with HARD STOP, never, always or must) are placed first, before size decides. To pin any other section, put <!-- minnimemory:keep --> on the line under its heading. A pinned section that still does not fit is named in the plan as "a rule". .minnimemory/ (backups, manifest) is bookkeeping only, never something Claude Code auto-loads.

| flag | effect | |---|---| | --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 | | --loaded <path> | a file Claude Code loads this session; repeatable; the only way a file outside the folder is read (--host-file still works) | | --memory-dir <path> | the auto memory folder Claude Code names; also the folder to use | | --from-log | take the loaded files from Claude Code's own load log for this folder | | --diff summary | the plan and the operation list without the file diffs | | --budget <n> | always-loaded token budget AlwaysOnMemory must fit (default: see above) | | --profile <name> | how much guidance to embed: auto, none, routing, output (the answer-length rules alone, about 230 tokens), full (default auto) | | --allow-secrets | preview as if a credential-shaped source were allowed through | | --episodic-json | plan episodic OnDemandMemory files (changelogs, logs) as JSON, not Markdown |

Profiles: auto is the same as none today, for every source: the list header already tells the agent how to route. none embeds no rules block; routing is the rules routing depends on, about 210 tokens; full is the complete discipline set, about 710 tokens. apply refuses (with --force to override) a compile that would not shrink the always-loaded prefix, naming the before/after tokens and the break-even point.

minnimemory doctor [path]

After init, never first: it refuses until init has run for this project, and with no path it uses the folder init saved. The audit, drift since the last apply (MM010), then the re-apply plan and "run apply", or "nothing to apply". Never modifies anything. Works on a repo, a memory folder, or a single file. Names a workspace compiled by an older layout (manifest v4/v5) as such, with "run undo, then apply" as the fix.

| flag | effect | |---|---| | --json | machine-readable output: the audit under doctor, the plan under plan | | --force | on a compiled workspace with no drift, show the re-apply plan anyway | | --ci | terse output, no colour | | --fail-on <sev> | exit 1 at this severity or above: low, med, high (default high) | | --budget <n> | always-loaded token budget for MM001 (default: the budget the workspace was compiled at, else 60% of the host file, at least 2000) | | --policy <file> | a team's rule pack (policy.json): MM020 reports a required line missing from the always-loaded memory, MM021 banned text in any memory file; its always_on_tokens is the MM001 budget when --budget is not given. Without it, neither rule runs | | --only <ids> | run only these rules, comma separated | | --ignore <ids> | skip these rules, comma separated | | --rules | list the rule set and exit |

Exit codes: 0 clean, 1 findings at or above --fail-on, 2 execution error, so a CI step (npx -y minnimemory doctor --ci --fail-on med) can fail the build on memory bloat the same way a lint error would.

minnimemory apply [path]

Writes what init or doctor showed. On a memory folder it refuses until init was told what loads it (moving a file an unseen outside file imports would break that import); --only-this-folder says nothing outside loads it. Looks at the workspace and does the right thing: an uncompiled host file or memory folder gets a fresh compile; a compiled workspace with drift gets re-applied, keeping every hand edit and every routed file; a compiled workspace with no drift prints "nothing to apply" and changes nothing. Same flags, backups (.minnimemory/original/, .minnimemory/previous/) and refusals as init/doctor.

--plan <hash> recomputes the plan from disk and refuses with "the plan on disk no longer matches" when the hash differs from the one init/doctor printed, so what you approved is what gets written; plain apply skips that check and always writes the current plan.

apply follows a pointer: if CLAUDE.md is only @AGENTS.md or "See AGENTS.md", it compiles AGENTS.md and leaves the pointer untouched. A compiled host file renamed afterwards (for example CLAUDE.md to AGENTS.md, with or without a pointer left behind) is the same host: doctor reports the rename, and one apply carries the manifest and the backups over, so undo still restores your original into the file that holds your memory now. A pointer rewritten by hand so that it no longer reaches the compiled file is reported as drift; apply then writes nothing and tells you the two ways out. Neither follows a symlink, in either direction. A workspace compiled by an older layout (manifest v4/v5) refuses with "run undo, then apply".

minnimemory undo [path]

Restores every original from .minnimemory/original/ and removes .minnimemory/. On a memory folder it also moves every sorted file back to the top level and removes AlwaysOnMemory// OnDemandMemory/ once they are empty. Restores the original always: the files as they were before the first apply, whatever re-applies happened since. A routed file you edited since the last apply would lose those edits, so undo names it and refuses unless you pass --force. "nothing to undo" when not compiled; a clear error when an original copy is missing (doctor reports that as a finding before it matters). Works the same, byte for byte, on a workspace compiled by an older layout (manifest v4 or v5) - "run undo, then apply" always has an undo to run.

undo works only on the machine that ran apply. The backups in .minnimemory/original/ are gitignored, so they never reach your repo: a teammate's clone has the compiled files and the manifest, but nothing to restore from. There, the way back is git history (the commit before the compile). If .minnimemory/manifest.json is lost or unreadable (a git merge conflict is enough), apply refuses and changes nothing; undo --force still restores every backup in original/ and leaves .claude/OnDemandMemory/ for you to delete, since nothing then records which files there it wrote.

minnimemory mcp [path]

Starts an MCP server, --profile basic (the same four verbs, always registered) by default.

| flag | effect | |---|---| | --profile <name> | basic (default): init, doctor, apply, undo, read-only. full: the six maintainer tools (recall, modules, outline, doctor, plan, always; apply with --allow-write) | | --allow-write | adds the full profile's write tool. No effect on basic, which is read-only by construction |

init/doctor take diff: "summary" (default) or "full"; apply/undo take content: true to include file content for a host without a shell. With format: "json", init returns three keys, map (each load group, and each file's path, tokens and owner), doctor and plan; doctor returns the last two. Every reply's data block carries a code drawn for that reply in its open and close lines, so no line of memory text can end it; a memory line that looks like the marker is also shown with "(quoted)" in the text form, and the JSON form keeps it exact. Register it with your agent rather than running it by hand: minnimemory install above (a direct node "<path>/cli.js" mcp registration), or by hand with claude mcp add minnimemory -- npx -y minnimemory mcp.

minnimemory install

Registers minnimemory with the current host in one command instead of the manual claude mcp add line above, turns on the memory hook and the drift notice hook, and prints the next step.

| flag | effect | |---|---| | --scope <name> | user, project, or local, same meaning as claude mcp add -s (default user) | | --write | serve the full profile with its write tools (--profile full --allow-write); the default basic profile never writes | | --dry-run | print the command without running it, exit 0 | | --force | remove an existing registration first, then re-add | | --no-hook | skip the hooks (memory, drift notice, and on Claude Code the load log and the Read usage log; on by default) | | --precise-reads | the Read hook also answers a whole-file Read of a large memory file with only the sections the current prompt needs, and names the rest by line range; off by default until a live check confirms Claude Code accepts the trimmed Read | | --remove | remove the MCP registration and the hooks install added; the same as minnimemory uninstall | | --host <name> | codex: register with Codex (codex mcp add) and write the two hooks to ~/.codex/hooks.json or <repo>/.codex/hooks.json, see Install for Codex. cursor, windsurf or json: print the mcpServers snippet to paste (and the config file for Cursor and Windsurf) instead of registering with Claude Code; no hook |

Idempotent: an existing registration is reported, with the command to change it, not duplicated. Without the claude CLI on PATH it prints the manual line and a JSON snippet instead, exit 2; if claude itself errors, its stderr is printed, exit 1.

minnimemory uninstall

Takes out what install added: the MCP registration (claude mcp remove minnimemory) and the two hooks in your Claude settings.json. Every other hook and setting stays, including another tool's hook that happens to look like ours. --dry-run shows the removals first; --scope matches the one you installed with. Running it twice is harmless.

npx -y minnimemory uninstall

It does not undo your memory. A compiled folder keeps working as plain markdown without the tool, and uninstall lists each one still compiled with its undo command, so run those first if you want the originals back. It also leaves ~/.claude/minnimemory/ (the init records, the load log and any undo backups); delete that yourself once you have checked undo-backups/. Restart Claude Code afterwards.

minnimemory recall <path> <query...>

Ranks a compiled workspace's OnDemandMemory sections, or a manifest-less memory directory, against a query. Changes nothing.

| flag | effect | |---|---| | --max-tokens <n> | cap on returned tokens (default 1500); the top hit is always returned | | --headings | print only "file > heading path (n tokens)" lines, not the content |

minnimemory hook

A Claude Code UserPromptSubmit hook, registered by install by default: reads the hook's JSON off stdin, ranks the prompt against the compiled memory, and prints one fenced memory section to stdout, or nothing. It prints nothing when the always-loaded memory holds the best match, prints only the single best section and only under 400 tokens, only when that section shares at least two words with the prompt and at least half of them, and never the same section twice in one session (it reads Claude Code's session_id and keeps a small record under <config>/minnimemory/hook-sessions/). Measured live on 2026-10-11: a third lower session cost on a continuous 27-task session, answers graded as good (Minni-AI run 2026-10-11-211152).

| flag | effect | |---|---| | --max-tokens <n> | cap on the ranked candidates (default 600); the placed section is capped at 400 regardless | | --headings | print only heading-path lines, not the content | | --dir <path> | an explicit memory directory, overriding the hook JSON's own cwd resolution |

minnimemory drift

A second UserPromptSubmit hook: reads the same stdin JSON, checks a compiled workspace for drift (doctor rule MM010), and prints a one-line notice only when something changed since the last apply, once per distinct change. minnimemory install registers it for you by default; --no-hook skips it.

minnimemory bench [path]

What the compiled shape costs over a whole session, rather than on one turn: the tokens a compile moves out of the always-loaded prefix are not the same as tokens saved, since an OnDemandMemory file the agent opens becomes part of the conversation and is re-sent for the rest of the session.

| flag | effect | |---|---| | --turns <n> | session length for the exact bounds (default 50) | | --workload <file> | one task description per line; without it, only the assumption-free bounds are reported | | --whole-files | model an agent that reads the whole file the OnDemandMemory list named, instead of the ranked section | | --json | machine-readable output |

Reports two kinds of claim, labelled every time: the exact bounds (best case, no OnDemandMemory file opened; worst case, every file opened on turn 1 and carried; break-even), and, with --workload, a session model routed the same way recall ranks.

Footprint

The MCP server's own always-loaded cost, measured (not assumed), approx-v2 tokenizer:

| | tokens | |---|---| | basic profile tool schemas (init, doctor, apply, undo), read-only | 1,251 | | basic profile tool schemas, --allow-write (no effect on basic) | 1,251 | | server instructions text | 50 |

Measured against a real registered server over an in-memory MCP transport, not assumed. Claude Code defers a tool's full schema until it decides the tool is relevant, so the real per-turn cost of a connected-but-unused server may already be lower than the schema total above; the instructions text is charged every turn regardless and is kept under about 60 tokens for that reason.

Security

  • init, doctor, apply, undo, and mcp make no network calls and never run a subprocess.
  • apply/undo refuse a symlinked source and refuse to write or delete through a symlink, so a cloned repo cannot point a memory file, or a routed piece, at a file outside the workspace.
  • apply refuses to write when the source holds a credential-shaped string, unless you pass --allow-secrets, and the prompt hook never places a memory section that holds one (it prints one redacted notice instead, once per session). .minnimemory/.gitignore keeps the verbatim backups (original/, previous/) and the drift stamp local; manifest.json and graph.json are meant to be committed, so a teammate's doctor sees the same drift.
  • apply refuses a source that is not valid UTF-8 rather than rewriting it with replacement characters, and keeps a CRLF file's line endings.
  • undo refuses, unless you pass --force, when a compiled file was edited since the last apply or the workspace was re-applied since the first: it restores the originals from before the first apply, and says what that would discard.
  • The MCP server validates manifest.json and only serves files that resolve inside OnDemandMemory/ (or .claude/OnDemandMemory/ for a project root), whatever the manifest says.
  • doctor --json includes the absolute workspace path and the headings of your auto-memory files. Read it before pasting it somewhere public.

What it does not do

  • Not a conversation compressor. It touches only your memory file, never the conversation.
  • Not a RAG index over your code. It compiles the memory file you already wrote, nothing else.
  • Not a proxy or model router. No model is called by any of the four verbs.
  • Not a summariser. Every source line lands somewhere verbatim, with a stated reason.
  • Not a compiler for a memory routing list. apply refuses MEMORY.md as a single file, or any file that is mostly links to topic files beside it: compiling a routing list re-files its hook lines as content and orphans every topic file. Point it at the folder instead: the folder compile leaves the index's own lines alone and appends its list.

FAQ

Does it send my code or memory files anywhere? No. Every command makes no network calls at all. There is no telemetry and no API key.

Will it destroy my CLAUDE.md? No. init/doctor are dry run by default. apply copies your original verbatim to .minnimemory/original/ before anything is modified, never writes over that backup, and undo restores it byte-identical on the machine that ran apply.

Does this fight with prompt caching? The opposite. Splitting volatile content out of the always-loaded prefix is precisely what keeps the cache valid across sessions.

Does it work with Cursor or Codex? Codex: yes, since 1.4.0 (see Install for Codex): the same four verbs on the AGENTS.md chain Codex loads, with its byte cap as a second ceiling. Cursor: the MCP server runs there (install --host cursor prints the entry) but the hook and the load model are not built, and nothing there is exercised end to end.

License

Proprietary, free to use. Copyright MinniAI. You may install and run the package, unmodified, for your own use, including at work, from npm, a Claude Code plugin marketplace or Anthropic's directory. You may not redistribute or modify it yourself, or take it apart to build a competing product; reading its source is fine. The files it reads and writes on your machine stay yours, and it sends nothing off your machine. The short instruction lines it writes into your memory files are yours to keep, edit, commit and publish with your repository. The bundled open-source components keep their own licences (THIRD_PARTY_NOTICES.md in the plugin). Full terms in the LICENSE file shipped with the package.