A few weeks ago I tested billion-context, which squeezes a long coding-agent session so it fits a small context window (my hands-on write-up). That covers one session. The other half of the problem shows up the next morning: I open a new session and the agent has forgotten everything, including decisions we made together yesterday.

claude-mem goes after that second half. It has been around since August 2025, has 116k GitHub stars, and Medium already has several explainers on it. So I won't explain it again. I installed it, ran the same task in fresh sessions with and without it, and counted everything I could: context sent per request, wall time, tool calls, and how often the agent had to go looking for things it should already know.

What claude-mem is (from the repo, not the hype)

claude-mem (github.com/thedotmack/claude-mem, Apache-2.0, by Alex Newman) describes itself as "persistent memory for AI coding agents: the next session starts where the last one left off." I tested v15.18.1, released on 12 Nov 2026. It has three parts:

  • Hooks in your agent send every tool call (reads, edits, commands) to a small local worker.
  • An observer, which is a second model, turns that activity into short "observations" and writes a summary when the session ends.
  • Context injection: the next session starts with a compact index of those observations. The agent fetches full details only when it needs them, through a three-step search (search, then timeline, then get_observations) that the project calls mem-search. There is also a save_memory tool for saving a note on purpose.

Everything is stored in SQLite at ~/.claude-mem/claude-mem.db, with Chroma adding semantic search on top of SQLite's keyword search. The worker also serves a web viewer on localhost. The README lists Claude Code, Codex, Cursor, OpenCode and 11 more agents. The observer can run on your Anthropic plan, a hosted claude-mem plan with a 30-day trial, or your own Gemini or OpenRouter key.

One honest detail from the README deserves credit: the "index rows are about a tenth the size of a full record" claim comes with the note that it "is not a measured recall or end-to-end saving." So I measured it myself.

My setup

I don't have a Claude subscription, and I wanted to test it without paying for anything, so I used:

  • Coding agent: OpenCode 1.19, with OpenCode Zen's free deepseek-v4.1-flash-free model (no login needed)
  • Observer: my free-tier Gemini key, using gemini-flash-lite-latest
  • Memory: claude-mem 15.18.1, installed with npx claude-mem install --ide opencode --provider gemini
CLAUDE_MEM_GEMINI_API_KEY=<your Gemini key> npx claude-mem install --ide opencode --provider gemini npx claude-mem telemetry disable # anonymous usage analytics are on by default npx claude-mem start # worker on 127.0.0.1:37700, viewer at /viewer 

The install wasn't smooth. The plugin installed fine, but even with CLAUDE_MEM_ONLINE_OPTIN=false the installer then waited for a browser login to cmem.ai. The CLI help explains why: Gemini, Codex and OpenRouter providers "need a cmem.ai sign-in"; only claude and host don't. I stopped the installer after the plugin step and set CLAUDE_MEM_PROVIDER to gemini in ~/.claude-mem/settings.json myself.

The free Gemini tier was the bigger problem. My first observer model ran out of its 20-requests-a-day quota during the first session. claude-mem then set a 30-minute cooldown, saved in quota-cooldown.json, and paused capture. The model id gemini-3.5-flash-lite was rejected as invalid, so I used the gemini-flash-lite-latest alias instead. If you try this on a free key, pick a lite model before you start.

The test

I wrote a small invoicing repo, ledgerlite: seven Python files, five unittest tests, money stored as integer paise, and a deprecated float-based legacy_calc.py that looks tempting to use.

Session 1 (memory on): "The GST test is failing. Find the bug, fix it, run the tests." In the same prompt I added a decision that exists nowhere in the repo: finance has decided that any discount is capped at 30%, stored as basis points, and applied to the subtotal before GST. I also said never to use legacy_calc.py, and that new features need a line under "Unreleased" in CHANGELOG.md.

Session 2 (a brand-new session, same repo, same commit): "Add percentage discount support to invoices, following the finance rule we agreed last time. Add tests and run them."

I ran session 2 under three conditions, three times each:

  • With memory: restored from the same snapshot of the memory database before each run, so every run saw identical memory
  • Without memory: the same prompt, with no claude-mem at all
  • Without memory, re-explained: the same task, with me typing the 40-word rule again, which is what you'd normally do

The first no-memory baselines taught me something I hadn't planned for. With the plugin off, the agent still went looking for "the rule we agreed last time." It searched git history, then my home directory, and then opened ~/.claude-mem/claude-mem.db with Python's sqlite3 and read the rule straight out of the observations table. The memory is just a SQLite file that any process running as you can read, and an agent with shell access will find it. For a fair baseline I re-ran it in a bwrap sandbox with no claude-mem plugin or MCP server, and with my home and workspace directories hidden.

Results

 correct wall tool explore context processed feature time calls calls (input + cached) With memory (avg of 3) 3/3 35.0s 13.0 3.3 126,307 No memory (avg of 3) 0/3 31.2s 16.0 13.7 88,428 Re-explained (avg of 3) 3/3 34.0s 16.3 10.3 65,739 ------------------------------------------------------------------ First request, empty project: no claude-mem 7,470 tokens MCP server only 12,228 tokens (+4,758) plugin + MCP (full) 12,701 tokens (+5,231) 

Recall was perfect, and that is the headline. In all three memory runs the agent ran one claude_mem_search, then get_observations on the top result, and built the feature correctly: a 3,000-basis-point cap, the discount applied before GST, a CHANGELOG line under Unreleased, no legacy_calc.py, and 9 to 10 passing tests. Without memory, none of the three runs produced code. One searched the repo, git history and my home directory for the rule and then died on a permission prompt. The other two stopped and asked me to restate the rule, which is the right behaviour but means I'm the memory.

It did not save exploration of the code itself. The memory runs still read the source files before editing, and they should: you can't edit code you haven't seen. The drop in exploration calls (3.3 vs 13.7) came almost entirely from not having to hunt for a decision that only existed in a previous chat. On a 7-file repo there was nothing else for memory to save.

It cost more tokens than re-typing the rule. This surprised me. The memory block injected into the system prompt was small, 1,038 characters or about 250 tokens. The fixed cost is the tool definitions. The MCP server alone adds about 4,800 tokens to every request, and the plugin's own search tools add about 500 more. Across a run of 7 to 9 model calls, that is why the memory runs processed about 126k context tokens versus about 66k when I just re-explained the rule. Most of it was cached by the provider, so the uncached input was closer (16k vs 10k), but it is a fixed overhead you pay on every request. Wall time came out the same (35.0s vs 34.0s).

So the honest summary of the numbers: claude-mem replaced 40 words I would have had to type and remember to type, and it never blocked. In exchange, it added about 5,200 tokens to every request and ran a second model in the background.

What the next session actually saw

The injected block was short: one observation title ("Discovered GST calculation bug in invoice module") and the previous session's summary. The 30% rule wasn't in the index itself. It was in the summary's "Next Steps" line and in a note the agent had saved with save_memory during session 1.

There is a catch I only found by reading the database. The save_memory call went through the MCP server, which tagged the note with source claude, not opencode. Session-start context is limited to the current agent by default (CLAUDE_MEM_SESSION_START_INCLUDE_ALL_SOURCES is false, per the README). So that note never appeared in the injected index; the agent found it through search. The viewer's settings preview shows the same thing: switch the source to claude and it says "No previous sessions found for this project yet."

The reliability caveat: does "remember X" land?

Capture is done by a model, so it is probabilistic. I tested it three times from the same seeded state with a throwaway task (add a docstring) plus two casual facts, "remember for later that our release branch is named ship/2026-q4" and "Globex invoices always use 12% GST," and then checked the database 150 seconds after each session ended.

  • Run 1: the agent saved both facts itself with save_memory. The observer wrote nothing of its own, and no new session summary appeared.
  • Run 2: the agent saved one note. The observer wrote three observations, including a "decision" with both facts. Again no new summary.
  • Run 3: the agent saved nothing. The observer caught both facts, and the session summary has them in its notes.

Both facts landed 3 out of 3 times, but through a different path each time, and the end-of-session summary was written only once in three runs. The seed session was worse. The free Gemini endpoint returned transient errors, and the worker log reads Skipped expired live observer inputs; no replay scheduled {skipped=7}. Seven tool calls were never turned into observations, and the summary only appeared after I re-sent the summarize request. If something really matters, ask the agent to call save_memory explicitly and check the viewer. Don't assume the observer caught it.

The observer isn't free either. For the docstring session, which made 10 tool calls, it used 31,500 input tokens on Gemini and took 172 seconds to finish in the background.

Privacy: what I verified

  • <private> tags work as documented. I put a fake staging password inside <private> tags in all three reliability prompts. It appeared zero times in observations, summaries, stored prompts, raw tool records, the Chroma index or the worker log. The stored prompt shows the block removed. The docs also say tags are stripped at storage time, not from the live conversation, and I confirmed that: OpenCode's own session database had the string in 8 rows. <private> protects claude-mem's memory, not your agent's own history.
  • Local by default. Everything lives in ~/.claude-mem/ on your machine. The README says Cloud Sync is opt-in, and my viewer header said "Cloud sync off".
  • Telemetry is on by default. Anonymous usage analytics are enabled until you run npx claude-mem telemetry disable.
  • Screenshots are kept by default. CLAUDE_MEM_MEDIA_CAPTURE_ENABLED defaults to true. The "Keep images" switch stores converted copies of tool screenshots under ~/.claude-mem/media-v1/, with no size cap or age limit until the event is deleted. They upload to cmem.ai only if Cloud Sync is on, and go to the observer model only if a separate switch (off by default) is on.
  • Auto-redaction is opt-in. Regex redaction of common key formats is off until you set CLAUDE_MEM_REDACT_ENABLED to true. Unless you turn it on, anything a tool prints is stored as-is.
  • The database is a plain file. As the baseline agent showed me, anything running as your user can read it.

My take

claude-mem does the one thing it promises: a decision from yesterday's session reached today's session without me repeating it, every time I tried. For long-running projects where the context is mostly decisions, conventions and "we tried X and it broke," that's real value. It also pairs well with the billion-context approach: one keeps a single session small, the other carries the important parts into the next one.

What I'd tell my team before they install it:

  • Budget for the overhead. About 5,200 extra tokens per request on a small task is more than re-typing a short rule. The trade only pays off when the context you'd otherwise re-explain is large, or when you'd forget to re-explain it.
  • Don't run the observer on a free-tier key with a 20-requests-a-day limit. Capture silently drops work when the provider has problems.
  • Use save_memory for anything you can't afford to lose. Automatic capture is a model's judgement.
  • Turn off telemetry, decide on "Keep images" on purpose, turn on redaction, and use <private> for anything sensitive.

Reproduce it

npx claude-mem install --ide opencode # or --ide cursor, claude-code, codex-cli, ... npx claude-mem telemetry disable npx claude-mem start # session 1: do some work and state a decision; session 2: ask for work that depends on it npx claude-mem search "what discount rule did finance agree" open http://127.0.0.1:37700/viewer 

All numbers come from OpenCode's JSON event stream (opencode run --format json), on 12 Nov 2026 IST, with claude-mem 15.18.1 and a deliberately tiny repo. On a large codebase the balance between fixed overhead and saved exploration will look different. That's the next test I want to run.