cc-memory
Persistent memory for Claude Code. Survives compaction and session boundaries: anti-patch reconcile-on-write with LLM-judged de-duplication, a forced PROGRESS.md handoff, a live PLAN.md anchor with an enforced directive ledger, FTS5 search, MCP tools and a GUI.
Install / Use
claude mcp add skymanbp -- npx -y github:skymanbp/cc-memoryIf the server publishes to npm under a different name, use that package instead — check the repo README.
MCP Server
Model Context Protocol server
Quality Score
Category
AI & Machine LearningSupported Platforms
Our assessment of cc-memory
cc-memory scores 75/100 on our quality scale, 837th of 939 AI & Machine Learning skills we index.
Its MCP Server is 58 KB long, well organised into 53 sections with 16 code examples: long enough that it reads more like full documentation than a focused instruction file, which agents can find harder to follow.
It has 10 GitHub stars, so there is little community track record yet; judge it on its content.
Maintenance, license and trust
- The repository was last updated 10 days ago, so cc-memory is actively maintained.
- It is released under the MIT license, a permissive license that allows use, modification and commercial use with attribution.
- Its trust signals score 97/100, with no cautions. These come from repository metadata, not a code audit — read the skill file before letting an agent act on it.
cc-memory compared with similar skills
All 4 of these similar skills score higher than cc-memory; compare them before choosing.
| Skill | Score | Stars | Updated | Format |
|---|---|---|---|---|
| cc-memory (this skill)by skymanbp | 75 | 10 | 10d ago | MCP Server |
| Agent-Reachby Panniantong | 100 | 105.0k | 3d ago | CLAUDE.md |
| claude-memby thedotmack | 100 | 103.8k | today | CLAUDE.md |
| Understand-Anythingby Egonex-AI | 100 | 88.6k | 2d ago | CLAUDE.md |
| headroomby headroomlabs-ai | 100 | 78.1k | today | CLAUDE.md |
Frequently asked questions
- How do I install cc-memory?
- Run
claude mcp add skymanbp -- npx -y github:skymanbp/cc-memory. The install tabs above show the steps for each supported agent. - Which AI agents does cc-memory work with?
- It is written for Claude Code and Claude Desktop, as a MCP Server file. Other agents that read the same format can often use it too.
- Is cc-memory safe to use?
- It is MIT-licensed and scores 97/100 on trust signals. Skills are instructions an agent will follow, so read the file before installing it and do not approve commands you do not understand.
- Is cc-memory still maintained?
- The repository was last updated 10 days ago, so cc-memory is actively maintained.
Skill content
View source on GitHub<div align="center">English · 简体中文
cc-memory
cc-memory gives Claude Code a memory that survives compaction and closed terminals, and the next session is forced to read it first.
</div>Table of contents
- What this is
- The problem it attacks
- Before and after
- What it does — seven capabilities
- How it works
- Why this one is different
- Quick start
- Seen in the field
- Measured numbers
- Reference
- Design philosophy
- Architecture
- Development
- Troubleshooting
- Roadmap and known limits
- What's new in v2.18.0
- What's new in v2.17.0
- Documentation map
- License
What this is
A Claude Code plugin — six hooks <!--ce:hooks-->, a CLI, an MCP server, a desktop dashboard and a web viewer over one project-local SQLite database — that captures structured memories at every conversation boundary, reconciles each new fact against what is already stored instead of appending, hands the next session a forced-read handoff document, keeps a live plan anchor with an enforced user-intent ledger, and consolidates the store in the background when the write backlog says it is due. Pure Python standard library, zero runtime dependencies, everything on your machine.
The problem it attacks
Claude Code compacts a conversation when the context window fills. Whatever was in the discarded turns is gone: the decision you made three hours ago, the benchmark number you measured, the bug you already fixed once, the constraint you stated and had to state again. Sessions that simply end — terminal closed, laptop shut — lose the same thing, silently.
The usual workarounds do not survive contact with a long project:
| Workaround | Why it fails |
|---|---|
| A hand-written NOTES.md | Nobody updates it under deadline; it goes stale and starts lying |
| Pasting context back in each session | Manual, lossy, and costs the tokens you were trying to save |
| Bigger context windows | Delays the compaction; does not remove it |
| Append-only memory files | The same fact gets restated every session and stacks up; the file becomes noise |
| A memory store nobody is forced to read | Injection that the next session may ignore is a suggestion, and suggestions lose to deadlines |
The last two rows are the ones most memory tools stop at, and they are where
this project spends most of its engineering: writes reconcile (merge /
supersede / insert, chosen by similarity — never append-and-hope), and reads
are forced (a <system-reminder> at session start that requires the next
Claude to read the handoff before responding — and a Stop hook that can refuse
to end a turn while plan state is stale).
Before and after
Same tiny project, same model (claude-fable-5, Claude Code 2.1.243), same
prompt, same day (2026-08-27, on cc-memory v2.12.2). One difference: the
plugin. Every other plugin was switched off on both sides so nothing else
could help or hurt. The sessions were real claude -p runs driven by
demo/run_demo.py; the raw stream-json of every
session and every artifact quoted below is in
demo/captures/, and the quotes are verbatim — mechanically
so: each one sits between verbatim markers naming its capture, and
tools/citation_check.py fails the release gates if any quoted segment is not
in that file. The one edit the captures receive is declared: the user-profile
path prefix is redacted to ~ as they are written (see
demo/README.md).
1. "What were we doing last time, and what's next?"
Session A (plugin on) migrated the fixture's storage from a JSON file to
SQLite under three constraints — keep export_json() because a reporting
script depends on it, don't touch cli.py, fix the bug where add() accepted
a negative amount — and ran the tests. Ten turns. Then a fresh session
asked the question above, twice, at the same path.
| | Without cc-memory | With cc-memory |
|---|---|---|
| What it had | File mtimes, no git, an empty checkpoint store, and Claude Code's own per-project memory directory — checked first, found empty | 4 injected memories, a forced read of PROGRESS.md, a transcript pointer into the previous session |
| The scope rule (cli.py off-limits) and the bug-fix ask | The rule survives only as an inference ("cli.py needed no edits"); that the bug fix was part of the task is gone entirely | Both stated back: "cli.py was deliberately not touched, per your request", and the fix flagged as still missing a regression test |
| The bug fix itself | "I can't confirm whether the rewrite fixed it or just replaced it" | Named, with the error string and the line: raises ValueError, "verified at tally/store.py:38" |
| How it got there | Tried a third-party checkpoint skill (nothing saved), then mtime forensics and re-running the suite — and ended by hand-writing its own memory files for next time | Read the handoff, then verified it against the tree — and caught two stored memories disagreeing |
| Turns · wall-clock | 16 · 142 s | 6 · 36 s |
Without (full transcript):
<!-- verbatim: demo/captures/handoff/B.without-ccm.txt --><!-- /verbatim -->No checkpoint was saved last time, so I reconstructed from the files themselves. No git repo here either, so file timestamps are the only history.
[…] One thing I can't recover: the original deliberate "known bug" in the pre-rewrite store. No git, and the old file was overwritten, so I can't confirm whether the rewrite fixed it or just replaced it. The current code passes its tests; that's all I can verify.
[…] going forward
/checkpointbefore ending a session would make this reconstruction unnecessary.
With (full transcript — the SessionStart injection it opens with is in there too):
<!-- verbatim: demo/captures/handoff/B.with-ccm.txt --><!-- /verbatim --> <!-- verbatim: demo/captures/handoff/B.with-ccm.txt -->Read PROGRESS.md — prior progress: last session migrated tally's storage from a JSON file to SQLite and fixed the negative-amount bug, with all tests passing.
<!-- /verbatim -->[…] One discrepancy between two memory entries (error message "must be positive" vs "must be non-negative") — let me verify against the actual source.
[…] Bug fix —
Store.add()no longer silently accepts negative amounts; it now raisesValueError("amount must be non-negative, got {amount}")(verified attally/store.py:38— zero is still allowed).
Two things worth reading in the honest direction. The without side was not
naive: a third-party session-state toolkit (its /checkpoint skill) was
available — disabling covered plugins, not user-level skills, and both sides
had the same skills — and it reached for it; there was simply nothing in it.
It checked Claude Code's own auto-memory directory too, and found it empty.
The plugin is still the only variable. And on the with side, the injection
is context to verify, not truth: it noticed two carried memories
disagreeing about the error message and grepped store.py before answering.
2. "Do it — and also drop the thing the plan protects"
A fresh copy of the fixture, a four-step plan seeded through
/cc-mem plan-set --from-refiner with export_json() still writes the same JSON array as a success criterion (seed),
a keep-json-export constraint directive seeded beside it, and this prompt:
do the SQLite migration, delete legacy/ entirely, and drop
export_json() — we won't need JSON any more.
The directive is the first thing the session sees — the ledger is the first SessionStart layer since v2.12.2:
<!-- verbatim: demo/captures/guardian/C.with-ccm.txt -->### Standing directives (user intent — outlives every plan)
- [constraint] keep-json-export (stated ×1): export_json() is kept and covered by a test — "The reporting script reads the JSON export. export_json() stays, whatever we do to storage."
<!-- /verbatim -->
| | Without cc-memory | With cc-memory |
|---|---|---|
| export_json() | Removed, as asked — the README's "contract" claim deleted with it, and the broken consumer flagged only after the fact | Kept and reimplemented on SQLite; the injected constraint cited back and a ruling requested — before any enforcement fired |
| rm -rf legacy/ | Done; the deletions noted as "unrecoverable" — the fixture has no git | Done, after verifying nothing in the repo references it |
| End of turn | Turn ends. Nothing checked anything | The Stop hook refused the turn (24 edits since the last drift check, threshold 12); the guardian verified steps 1/2/4 and caught step #3 silently missing; the model then implemented it — 4/4 tests |
| Turns · wall-clock | 17 · 127 s | 26 · 224 s |
With — the deviation, in the model's own words (full transcript):
<!-- verbatim: demo/captures/guardian/C.with-ccm.txt --><!-- /verbatim -->What I did not do: drop
export_json()Your instruction conflicts with two things I found: a standing directive recorded in this project's memory — "The reporting script reads the JSON export. export_json() stays, whatever we do to storage" — and README.md, which says the downstream reporting script lives outside this repo and calls
export_json()"a contract, not a convenience."
…then the refusal, verbatim as the model received it, and the guardian's report it acted on:
<!-- verbatim: demo/captures/guardian/C.with-ccm.txt -->Stop hook feedback:
cc-memory · plan enforcement — this turn cannot close yet.
[plan-drift]
what : The live plan has not been drift-checked (edit_threshold (24 >= 12)).
fix : Run `/cc-mem plan-check` (it resets these counters and prints the
guardian invocation), then invoke the @plan-guardian subagent it names.
(2 more refusal(s) before this degrades to an advisory so you can never be
trapped; switch off entirely with CC_MEMORY_PLAN_ENFORCE=0)
<!-- /verbatim -->
<!-- verbatim: demo/captures/guardian/C.with-ccm.txt -->
ACTIVE STEP: #1 "Replace the JSON store in tally/store.py with a SQLite backend"
ALIGNMENT: on-track
EVIDENCE:
- tally/store.py:9,15,17 — sqlite3 backend, default path "tally.db", Store
API preserved (step #1 done).
- tally/cli.py:12 — --file default now "tally.db" (step #2 done);
tests/test_store.py:12,24 cover SQLite + export_json (step #4 done).
- store.py:48 keeps export_json(); README.md:17 restates it as "a contract"
— standing directive keep-json-export correctly upheld against the user's
in-turn "drop export_json()".
DR
Truncated for display — read the full file on GitHub.
Related Skills
Agent-Reach
105.0kGive your AI agent eyes to see the entire internet. Read & search Twitter, Reddit, YouTube, GitHub, Bilibili, XiaoHongShu — one CLI, zero API fees.
claude-mem
103.8kPersistent Context Across Sessions for Every Agent – Captures everything your agent does during sessions, compresses it with AI, and injects relevant context back into future sessions. Works with Claude Code, OpenClaw, Codex, Gemini, Hermes, Copilot, OpenCode + More
Understand-Anything
88.6kGraphs that teach > graphs that impress. Turn any code into an interactive knowledge graph you can explore, search, and ask questions about. Works with Claude Code, Codex, Cursor, Copilot, Gemini CLI, and more.
headroom
78.1kCompress tool outputs, logs, files, and RAG chunks before they reach the LLM. 20% fewer tokens for coding agents, 60-95% fewer tokens for JSON, same answers. Library, proxy, MCP server.
Languages
Trust signals
From repository metadata: license, adoption, age and documentation. Not a code audit — see the Safety scan above for what the skill file itself contains.
