> 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.

Problem and solution

Coding agents pay again for what an earlier session already found out.

Without memory New session starts from zero Re-reads files same files again Re-runs searches same searches Answer after a long hunt many tokens With memory New prompt the hook runs Index up to 5 lines Opens one note memory_read Answer few tool calls fewer tokens Without memory New session starts from zero Re-reads files same files again Re-runs searches same searches Answer after a long hunt many tokens With memory New prompt the hook runs Index up to 5 lines Opens one note memory_read Answer few tool calls fewer tokens

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%).

Without memorythe reference100%
exp 01Yes. Same accuracy, caught a renamed method.42% −58%
exp 02Risk. Cut 35% on one repo, added 4% on the other.~85% ~−15%
exp 03 · repo AShipped method.71% −29%
exp 03 · repo BShipped method.73% −27%
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

00 01 02 03 04 Your answer ≥ 200 chars Stop hook saves one note per turn Note store ~/.easy-memory/ <repo> Prompt hook score ≥ 0.12 top 5 Next prompt + framed index 2,500-char frame Word weights built in the background side input MCP server memory_read opens one note optional main loop side path 00 01 02 03 04 Your answer ≥ 200 chars Stop hook saves one note per turn Note store ~/.easy-memory/ <repo> Prompt hook score ≥ 0.12 top 5 Next prompt + framed index 2,500-char frame Word weights built in the background side input MCP server memory_read opens one note optional main loop side path

The prompt hook never builds weights. It starts a background build and adds nothing until the file exists.

How a note is saved

One saved note question the prompt you typed answer the final reply time when it was saved cited files path + sha256 of each next prompt re-hash files File unchanged line is listed as it is File changed CHANGED: src/auth.py File deleted DELETED: src/old.py One saved note question the prompt you typed answer the final reply time when it was saved cited files path + sha256 of each next prompt re-hash files File unchanged line is listed as it is File changed CHANGED: src/auth.py File deleted DELETED: src/old.py
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: or DELETED:.
  • MCP server offers memory_search, memory_read, memory_list and memory_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.

  1. 01

    Get the code

    $ git clone git@github.com:thunderkds/easy-memory-mcp.git $ cd easy-memory-mcp $ python3 -m unittest discover -s tests

    Pass: the last line reads OK.

  2. 02

    Preview

    $ python3 easy_memory.py install --dry-run

    Prints a diff. Writes nothing.

  3. 03

    Install

    $ python3 easy_memory.py install

    Backs up your settings, then adds the hooks.

  4. end

    Check

    claude mcp list shows easy-memory connected.

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

  1. evenon
  2. oddoff
  3. evenon
  4. oddoff
  5. evenon
  6. oddoff
  7. evenon
  8. oddoff
  • switch onforces every day on
  • switch offforces every day off
  • switchshow the state for this repo
  • switch on|off|autoset it
  • reportcompare sessions with memory on and off
  • install / uninstalladd or remove the hooks and the MCP server
More detail
CommandWhat it does
switchPrints the state for this repo and what it means today.
switch on|off|autoSets 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.
reportCompares 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 / uninstallAdd 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 compare and 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

easy-memory143 notes

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.

Prompt hook7,831-file repo, 200 notes0.212 s of 1 s
Stop hook0.066 s of 2 s
  • 0.024 sword weights load
  • 1.69 MBword-weights file
  • 307tests pass (3 skipped: opt-in or host-dependent)

Prompt hook speed

Normal prompt real 440-note store before 290 ms after 145 ms 4,000-note probe slowest run before 1.62 s after 0.41 s Normal prompt real 440-note store before 290 ms after 145 ms 4,000-note probe slowest run before 1.62 s after 0.41 s

Time per prompt, 4 Nov 2026. One scale for all bars.

Worst-case prompts

1.7 MB / 150,000 words 440 notes before 171.7 s after 0.27 s 10 MB 440 notes before 3.98 s after 0.44 s 0.1 s 1 s 10 s 100 s log scale 1.7 MB / 150,000 words 440 notes before 171.7 s after 0.27 s 10 MB 440 notes before 3.98 s after 0.44 s 0.1 s 1 s 10 s 100 s log scale

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

LimitImpactStatus
Notes pile upEach note costs about 3× less since 4 Nov 2026, but the hook still gets slower as the store grows.open
Index precisionAbout 8% of index lines were relevant in the 31 Oct 2026 check. Experiment 08 looks at it.open
Big transcriptsA 400 MB transcript used 808 MB.open
Non-git folderThe weights build has no cap.open
Clear textNotes are saved unencrypted (mode 0600).accepted
Permission promptThe 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.