English | Русский
Change Memory gives Claude Code compact, local memory of what changed in your project across sessions. It stores semantic summaries, changed files, unresolved issues, risks, and compressed patches without loading full diffs into context by default.
A git-native, fully offline, team-shareable change log for your AI agent. Zero tokens, zero cloud, zero telemetry — the change history is plain JSON that commits with your repo and travels to the next coder, with author attribution. Unlike conversation-memory plugins, Change Memory remembers what changed in the code and why, not what was said in the chat. See Change Memory vs other memory plugins.
Category: development Keywords: claude-code, mcp, agent-memory, git-diff, context-management, token-optimization, coding-agent
Long coding sessions burn tokens re-reading history. Change Memory keeps a tiny on-disk "map" of your project's changes and hands Claude a compact snapshot at the start of a session instead of full diffs. The full patches are stored locally, gzip-compressed, and loaded only when explicitly requested.
The guiding principle:
The agent gets a short change map, not the whole diff. Full patch files are loaded only on explicit request.
- Continuity across sessions — pick up where you left off without re-explaining.
- Token efficiency — bootstrap context is budgeted (~700 tokens by default).
- Avoid repeating work — search past fixes, risks, and unresolved items.
- Local & private — no network, no telemetry. The semantic map can be committed to share with your team; raw diffs (patches) stay on your machine.
- Team-friendly — the change history travels with the repo, with author attribution, so the next coder sees who changed what and why.
Most memory plugins for AI agents record the conversation / agent observations and compress them with an LLM (spending tokens) or store them in a cloud / paid service. Change Memory deliberately occupies a different niche: a diff-centric, offline, git-committed change log.
| Change Memory | Conversation-memory plugins (e.g. claude-mem) | Cloud memory frameworks (e.g. Mem0, Zep) | |
|---|---|---|---|
| Remembers | What changed in the code, and why (git diffs + reason/risk) | What the agent did/said during the session | Facts, preferences, conversation history |
| Summarization | Offline heuristic — no LLM, no tokens | AI-compressed (consumes tokens / API) | LLM + embeddings |
| Storage | Local files (.change-memory/) |
Local DB (e.g. SQLite + vector) | Mostly cloud / paid tiers |
| Network / telemetry | None | Varies (API for compression) | Cloud by design |
| Team sharing | Built-in — map commits to git, with author attribution | Typically per-developer | Per-account |
| Auditability | Plain JSON, diffs in your PR | Opaque store | Remote service |
| Search | Keyword | Hybrid keyword + semantic | Semantic / graph |
| Agents | Claude Code | Often multi-agent | Many agents |
When to choose Change Memory: you want a shared, auditable record of code changes that costs nothing to run, sends nothing off your machine, and lives in the repo — ideal for privacy-sensitive, regulated, or team settings.
When another tool fits better: you want rich AI-written session summaries, semantic/vector recall over conversation history, or one memory layer across many different agents. These are complementary — Change Memory can run alongside them.
The plugin ships three parts:
- Agent Skill (
skills/change-memory) — teaches Claude when and how to use the memory (progressive disclosure: snapshot first, patches last). - MCP server (
mcp-server/) — local Node.js server exposing the memory tools. - Slash commands (
commands/) — quick entry points.
State lives in your project under .change-memory/:
.change-memory/
index.json # project metadata, active files, unresolved items, budgets [shared]
changes.jsonl # one JSON line per captured change (incl. author) [shared]
summaries/ # archived/compacted history [shared]
session.md # compact snapshot (mirrors get_session_context, regenerated) [local]
patches/ # gzip-compressed full diffs (chg_*.patch.gz) [local]
auto-capture.json# per-machine fingerprint + auto-capture on/off toggle [local]
.gitignore # written by init_memory: commits the map, ignores the rest
[shared] files are committed so teammates inherit the change history;
[local] artifacts stay on your machine. See Team workflow below.
See examples/change-memory/ for a static sample of
session.md and index.json so you can preview the format without a live install.
- Add this plugin from your Claude Code marketplace (or install locally).
- The MCP server runs from compiled output at
mcp-server/dist/index.js.- If you cloned the source, build it once:
npm install(thepreparescript runsnpm run buildautomatically). Requires Node.js ≥ 18.
- If you cloned the source, build it once:
- Restart Claude Code so it picks up the bundled MCP server defined in
.mcp.json.
.mcp.json registers the server for the plugin:
{
"mcpServers": {
"change-memory": {
"command": "node",
"args": ["${CLAUDE_PLUGIN_ROOT}/mcp-server/dist/index.js"]
}
}
}${CLAUDE_PLUGIN_ROOT} is provided by Claude Code and points at the installed
plugin directory. No configuration is required.
Change Memory is built to travel with the repo so the next coder understands what changed and why — without you re-explaining it.
- Commit the map.
init_memorywrites a.change-memory/.gitignorethat commitsindex.json,changes.jsonlandsummaries/(the semantic map) and ignorespatches/,auto-capture.jsonandsession.md(machine-local / heavy-binary). Just commit.change-memory/as part of your normal git flow — the plugin never runs git writes itself. - Attribution. Each change records its
authorfromgit config user.name/user.email, solist_changesandshow_changeshow who made it. - Fresh clone. A teammate who clones the repo runs
/memory-session(get_session_context) and immediately gets the rebuilt snapshot from the committed map — no patches required. They canshow_changeany change's metadata; the raw diff (includePatch: true) is only available for changes captured on their own machine, since patches stay local. - Share patches too (opt-in). Run
/memory share on(orconfigure({ sharePatches: true })) to commitpatches/as well, so teammates can load any change's diff. The flag is stored asshare_patchesin the committedindex.jsonand the managed.gitignoreis regenerated to trackpatches/;/memory share offreverts to local-only. You can also opt in at setup time with/memory-init share. Note this commits compressed patch blobs, which adds repo weight — leave it off unless the team wants full diffs.
Prefer not to share? Delete the generated
.change-memory/.gitignoreand add.change-memory/to your project's root.gitignoreto keep everything machine-local instead.
| Tool | Purpose |
|---|---|
init_memory |
Create .change-memory/ for the project. |
capture_change |
Snapshot the current git diff (incl. untracked files) → compressed patch + semantic summary. Accepts optional agent-authored llmSummary/llmRisk/llmType (host model, no network) that override the heuristic. |
configure |
Adjust settings: autoCapture (per-machine toggle) and/or sharePatches (team-wide via index.json). Omit a field to leave it unchanged; omit both to query. |
get_session_context |
Return the compact markdown snapshot. Never includes full diffs. |
show_change |
Show one change's metadata; the full patch with includePatch: true, or a single file's hunk with file: "<substring>". |
list_changes |
Compact table: id | type | file | summary. |
search_changes |
Search id, summary, files, reason, risk, tests, branch, commit. |
summarize_branch |
PR-ready markdown summary of a branch's changes, grouped by type, with files/risks/tests. |
compact_memory |
Archive old changes into a summary; keep recent ones; preserve patches. |
Three core commands are top-level; the rest live under a single /memory
dispatcher to keep the command surface small.
| Command | Action |
|---|---|
/memory-init [share-patches] |
Initialize memory; add share to commit patches too. |
/memory-capture [reason] |
Capture current changes. |
/memory-session |
Load the compact session context. |
/memory show <changeId> [patch] |
Show a change (add patch for the diff). |
/memory search <query> [limit] |
Search change history by keyword. |
/memory pr [branch] [limit] |
PR-ready summary of a branch's recorded changes. |
/memory compact [olderThanDays] [keepRecent] |
Archive old changes; keep recent ones. |
/memory auto <on|off|status> |
Turn automatic capture on/off (per-machine). |
/memory share <on|off|status> |
Turn patch sharing on/off (team-wide). |
Once the plugin is installed, Change Memory records changes automatically — you
don't need to run /memory-capture by hand.
A bundled Claude Code hook (hooks/hooks.json) fires on PostToolUse for the
Write, Edit and MultiEdit tools and runs the plugin's auto-capture command
(mcp-server/dist/cli/autoCapture.js) directly — no MCP round-trip.
- Manual capture still works.
/memory-capture(and thecapture_changetool) remain available — use them for a deliberate, named snapshot with a custom reason. - Debounced. At most one capture per
debounceMswindow (default 30s), so a burst of edits produces a single snapshot, not dozens. - Deduplicated. Auto-capture fingerprints the composed working-tree diff (tracked diff + untracked file contents). If the diff is unchanged since the last capture, it does nothing.
- Never touches git state. It only reads
git diff/git statusand writes into.change-memory/. It does notgit add,commit,checkout, or run any destructive git command. - Non-blocking. If memory isn't initialized, the path isn't a git repo, or the tree is clean, the hook skips silently and never interrupts your work.
Auto-capture keeps its bookkeeping in .change-memory/auto-capture.json
(last_fingerprint, last_capture_at, last_change_id).
Project-root note: the hook passes
${CLAUDE_PROJECT_DIR}(the directory Claude Code was launched in) asprojectPath. Open Claude Code at your git repository root, not a parent folder — if the repo is nested below the project root, auto-capture targets the wrong directory and silently skips.
- Run
/memory-initonce in a git repo (auto-capture is a no-op until initialized). - Ask Claude to edit a file. After the edit, check the latest entry:
list_changes(or/memory show) — a newchg_...with reasonauto: .....change-memory/auto-capture.json—last_change_idupdated.
- Ask for a second edit within 30s → no new entry (debounced/deduped). Wait >30s and edit again → a new entry appears.
The simplest way is the per-machine toggle:
- Run
/memory auto off(callsconfigure). The flag is stored in the local, gitignoredauto-capture.json, so it only affects your machine, never your teammates./memory auto onre-enables it;/memory auto statusreports the current state.
To hard-disable the hook for everyone (or as a fallback):
- Remove or rename
hooks/hooks.jsonin the installed plugin, or - Disable the plugin's hooks from
/hooks/ your Claude Code hook settings, or - Raise
debounceMsinhooks/hooks.jsonto a large value to throttle it.
The MCP tools (including manual capture_change) are unaffected.
# New session
/memory-session → Claude loads the compact snapshot
# ... you and Claude make changes ...
/memory-capture fixed token refresh on expiry
→ chg_20260618_210712_... | fix | Ada <ada@example.com> | src/auth.ts
# Later, recall details
search_changes("token") → finds the change
show_change(chg_..., includePatch:false) → metadata only
show_change(chg_..., includePatch:true) → full diff, on demand
show_change(chg_..., file:"src/app.ts") → just that file's hunk
# Session Context
Project: my-app
This is a compact memory snapshot for Claude Code.
It intentionally excludes full diffs to reduce token usage.
## Recent Changes
- chg_20260618_210712_de5c94c2 (Ada <ada@example.com>): Fix change: added 1,
modified 1 file(s) in src (`src/auth.ts`). Reason: fix token refresh. Full
patch stored locally.
## Active Files
- src/auth.ts
## Open Issues
- add tests for token expiry
## Constraints
- Keep context compact.
- Do not include full diffs by default.
- Load patch details only when needed.
## Available Memory Tools
- show_change(changeId)
- list_changes()
- search_changes(query)
- capture_change()This plugin is built to be safe for marketplace distribution:
-
Local only. All state lives in
.change-memory/inside your project. -
No telemetry, no analytics, no phone-home.
-
No external network calls. The server has no HTTP client. The optional richer summary (
llmSummary/llmRisk/llmTypeoncapture_change) is written by the host model (Claude Code) and passed in as plain text — the server itself never contacts an LLM and holds no API keys. -
No
evaland no dynamic code execution. -
No arbitrary shell. The only external process is
git, restricted to an allow-list of read-only argument vectors:git diffgit diff --name-onlygit diff --name-statusgit status --porcelain [--untracked-files=all]git rev-parse --is-inside-work-treegit config user.name/git config user.email(read-only, for author attribution)
Commands are executed via
execFile(no shell), and user input is never interpolated into a command. Write operations (commit/add/checkout) are impossible by construction. -
No user code is modified or committed. Capture is read-only.
-
Path traversal protection. Every file access is normalized and verified to stay inside the project root (
ensureInsideRoot). Patches live only under.change-memory/patches/. -
Bounded reads. Untracked file content embedded in patches is capped (256 KB per file) and binary files are skipped.
- Raw diffs never leave your machine. Patches are stored compressed locally and are gitignored by default; you control them.
- The map that can be committed (summaries, file lists, reasons, authors, open issues) is intentionally diff-free — only what a teammate needs to follow the history, not the source itself.
- The session snapshot deliberately excludes diffs to minimize what enters the model context.
- Don't want to share anything? See Team workflow for how to keep the whole
.change-memory/directory machine-local.
Not included in this first version:
- Cloud sync / remote storage
- External LLM summarization (the summarizer is heuristic and offline)
- VSCode extension or web dashboard
- Authentication
- Telemetry
- Arbitrary shell command execution
- Staged-vs-unstaged separation (captures the working-tree diff + untracked files)
- "No .change-memory found" — run
/memory-init(or callinit_memory). - "No changes to capture" — the working tree has no tracked changes and no untracked files. Make an edit first.
- "Not a git repository" —
capture_changereadsgit diff; run inside a git repo (git init). - Server not loading — ensure
mcp-server/dist/index.jsexists; runnpm install(which builds) and restart Claude Code. - Memory captured itself —
.change-memory/is always excluded from capture (seegetUntrackedFiles). The generated.change-memory/.gitignorealready keeps patches and machine-local state out of commits. - Author shows
(unknown)— set a git identity (git config user.name/git config user.email); pre-existing changes captured before this version have no recorded author.
See ROADMAP.md for what's shipped, what's next, and later ideas.
MIT — see LICENSE.