> per-repo memory for claude code
Easy Memory
Per-repo memory for Claude Code. After each answer it saves a note. Before your next prompt it hands the agent a short index of the notes that match. The agent can ignore the index or open one note.
- Localone Python file, standard library only. No model calls, no network, nothing leaves your machine.
- Hooks and MCPa Stop hook, a prompt hook, and a stdio MCP server with four tools.
- Measured on yourselfa per-repo switch alternates memory on and off by day, and a report compares the two.
Problem and solution
Coding agents pay again for what an earlier session already found out.
Bar lengths are an illustration.
Without memory. A new session reads the same files and runs the same searches that an earlier session already did. Every step costs tokens.
With memory. The prompt hook adds an index of up to 5 lines. The agent opens one note and goes straight to the answer.
- notes are data, not instructions
- a hook never blocks you
- nothing written in your repo
More detail
They read the same files again, and long sessions carry every old tool result forward. The goal is fewer model tokens at the same accuracy.
- Notes are data, not instructions. The index says so, and note text is quoted so it cannot leave its frame.
- A hook never blocks you. On any error a hook exits 0, adds nothing and writes one line to a local log.
- Nothing is written inside your repo. Notes live under
~/.easy-memory/(files 0600, folders 0700).
Terms: a note is one saved answer with its question and the repo files it cited. The index is up to 5 lines about matching notes. The switch is the per-repo state: on, off or auto.
Context
This continues easy-context-mcp, retired on 2026-10-23. Memory between sessions was the first idea that beat plain grep.
Tokens with memory, as a share of the tokens without memory (without = 100%).
More detail
Code search (vectors plus a symbol graph) did not beat plain grep in any test. Three experiments came before any product code.
- exp 01 · Does memory from the last session cut tokens on a follow-up?
- Yes. The previous final answer cut tokens by 58% at the same accuracy and caught a renamed method. Resume was misled.
- exp 02 · Does it still work when saving, choosing and delivering memory are automatic?
- Risk. It cut tokens by 35% on one repo and added 4% on the other, about 15% saved overall. Stale memory misled 0 runs. The picker was the weak part.
- exp 03 · Can more precise injection save tokens on both repos?
- Go for a prototype. The index method (list notes, the agent opens one) cut tokens by 29% and 27%. Accuracy was the same.
The prototype is the index method from experiment 03. Raw agent answers from the experiments stay local, because they quote private source code.
How it works
The prompt hook never builds weights. It starts a background build and adds nothing until the file exists.
How a note is saved
More detail
- Stop hook saves one note per turn: the question, the answer, the time, and the sha256 of each repo file the answer cited.
- Prompt hook scores each note against your prompt. It adds at most 5 lines in a frame of at most 2,500 characters, and flags cited files as
CHANGED:orDELETED:. - MCP server offers
memory_search,memory_read,memory_listandmemory_forget. Ids are checked, and nothing outside the notes folder can be read or deleted. - Repo key: git worktrees of one repo share one store.
Install
Clone the repo, then run three commands from that clone. Run them from the main checkout, never from a git worktree.
-
01
Get the code
$ git clone git@github.com:thunderkds/easy-memory-mcp.git $ cd easy-memory-mcp $ python3 -m unittest discover -s testsPass: the last line reads
OK. -
02
Preview
$ python3 easy_memory.py install --dry-runPrints a diff. Writes nothing.
-
03
Install
$ python3 easy_memory.py installBacks up your settings, then adds the hooks.
-
end
Check
claude mcp listshowseasy-memoryconnected.
More detail
The hook commands keep an absolute path.
Step 02 prints a diff of your user-level Claude Code settings ($CLAUDE_CONFIG_DIR/settings.json, else ~/.claude/) and the claude mcp add command. It writes nothing.
Step 03 copies the settings file to settings.json.easy-memory.bak.<time>. It then adds a Stop hook (10 s timeout), a prompt hook (5 s timeout) and the allow rule mcp__easy-memory. It registers the MCP server with claude mcp add --scope user. Run it twice and the second run changes nothing.
Check: claude mcp list shows easy-memory connected. If claude is not on your PATH, the hooks still install and the manual command is printed.
Use it
The switch is per repo. auto is the default.
auto · by the day count since 1970-01-01
- evenon
- oddoff
- evenon
- oddoff
- evenon
- oddoff
- evenon
- oddoff
switch onforces every day onswitch offforces every day off
switchshow the state for this reposwitch on|off|autoset itreportcompare sessions with memory on and offinstall/uninstalladd or remove the hooks and the MCP server
More detail
| Command | What it does |
|---|---|
switch | Prints the state for this repo and what it means today. |
switch on|off|auto | Sets it. auto is the default: on for even days, off for odd days since 1970-01-01. The Stop hook saves notes in every state. |
report | Compares sessions with memory on and off from Claude's own session logs: sessions, median tokens, median turns, and how often a listed note was opened. |
install / uninstall | Add or remove the hooks, the allow rule and the MCP server. |
- The headline token count is input + cache creation + cache read + output, as the experiments counted it. A second column shows input + output only.
- With fewer than 10 sessions in either group, the report says
too few sessions to compareand prints no percentage. - Every prompt leaves one line in
~/.easy-memory/<repo key>/prompts.log: time, session id, configured and effective state, and whether an index was added.
See it in Easy Personal
Easy Personal is the family dashboard. Its Memory view shows a repo's store. Open Easy Personal
this repo, 3 Nov 2026
saved per day, last 30 days
Hit rate 70% of 56 prompts
Memory on vs off
- On3 sessions23.2M tokens / session
- Off5 sessions16.6M tokens / session
too few sessions to compare (3 on / 5 off, need 10 each)
Easy Personal reads report.json, which easy-memory refreshes about once an hour. It shows counts only, never note text.
More detail
report.json sits in the repo's store folder (~/.easy-memory/<repo key>/, mode 0600). It holds numbers, flags and a time. python3 easy_memory.py report --json prints the same object.
The comparison of memory on and off stays empty until each group has 10 sessions, as in the report command.
Remove it
Roll back if you see any of these:
- hook error on every prompt
- prompts ≥ 1 s
- MCP fails in claude mcp list
- permission prompt on open
$ python3 easy_memory.py uninstall # removes both hooks and the allow rule
$ claude mcp remove --scope user easy-memory # only if uninstall printed it as a manual step
$ python3 easy_memory.py uninstall --purge # also deletes ~/.easy-memory (prints the size first)More detail
Roll back if Claude Code shows a hook error on every prompt, prompts feel slow (about 1 s or more), the MCP server fails in claude mcp list, or opening a note triggers a permission prompt.
If the settings file is still wrong, copy the newest settings.json.easy-memory.bak.<time> back over it. Check: grep easy_memory "$CLAUDE_CONFIG_DIR/settings.json" prints nothing.
Measured
p95 of each hook, against its limit.
- 0.024 sword weights load
- 1.69 MBword-weights file
- 307tests pass (3 skipped: opt-in or host-dependent)
Prompt hook speed
Time per prompt, 4 Nov 2026. One scale for all bars.
Worst-case prompts
4 Nov 2026. Log scale: each grid line is 10 times the one before.
Word cache in a long serve, 4 Nov 2026: 1,600 long words used 95 MB before and 35 MB after.
More detail
An independent QA task checked the full cycle: install, save, index, MCP read, report, uninstall. It also checked file modes, no network traffic (a socket shim and strace), garbage input, and that the repo tree hash does not change.
Known limits
| Limit | Impact | Status |
|---|---|---|
| Notes pile up | Each note costs about 3× less since 4 Nov 2026, but the hook still gets slower as the store grows. | open |
| Index precision | About 8% of index lines were relevant in the 31 Oct 2026 check. Experiment 08 looks at it. | open |
| Big transcripts | A 400 MB transcript used 808 MB. | open |
| Non-git folder | The weights build has no cap. | open |
| Clear text | Notes are saved unencrypted (mode 0600). | accepted |
| Permission prompt | The live check has not run. | to run |
More detail
- Notes pile up
- The prompt hook still gets slower in a straight line as saved notes pile up. Since 4 Nov 2026 each note costs about 3× less: with 4,000 notes the hook takes 0.41 s (1.62 s before). At about 5 s the hook timeout kills it and the index silently disappears.
- Index precision
- In the 31 Oct 2026 check, about 8% of the index lines were relevant (an estimate: 67 of 845 lines on 298 real prompts). Experiment 08 tests a cut-off that drops weak lines. The index is not changed yet.
- Big transcripts
- The Stop hook reads the whole transcript into memory. A 400 MB transcript used 808 MB.
- Non-git folder
- The background weights build has no cap when Claude Code starts in a folder that is not a git repo.
- Clear text
- Answers and prompts are saved unencrypted (mode 0600). Do not use it where answers can hold secrets you would not keep on disk.
- Permission prompt
- The live check that opening a note causes no permission prompt has not run. It needs your own credentials.