Durable, hierarchical, repo-scoped memory for Claude Code. Local-first MCP server with hybrid lexical + vector retrieval over your codebase, docs, and accumulated decisions.
Project description
claude-repo-mem
Durable, hierarchical, repo-scoped memory for Claude Code. Local-first MCP server.
claude-repo-mem indexes your repository — code, docs, and your own accumulated decisions — into a SQLite database with hybrid lexical + vector retrieval, then exposes it to Claude Code as 11 MCP tools. The point: Claude stops grepping. It calls recall(query) and gets back ranked, budgeted, tier-aware results in one round-trip.
Memory is durable. Decisions you remember() land as committed markdown files under .claude-repo-mem/memory/. Tasks survive session boundaries via handoff() / resume(). The index keeps itself warm via a file watcher or a git post-commit hook.
Status: v0.1, feature-complete. 5 development phases shipped, 255 tests passing. ~3.5k LoC of source.
Why
LLM coding assistants spend most of their context budget rediscovering code. They grep, they read, they re-read. claude-repo-mem replaces that with a structured index: each unit (function, class, doc section, decision) has three tiers — full source (T0), LLM summary (T2), and a single-line header (T1) — and retrieval picks the right tier to fit your budget.
The retrieval substrate is a graph: routes connect to handlers (Flask / Django / Express synthesizers), Python imports become edges, React useState setters tag their containing components. One trace(seed_handle) call surfaces the connected subgraph in full source.
Memory is the second half. remember(fact, scope, kind="decision") writes a markdown file with YAML frontmatter that's both human-readable and git-trackable. handoff() snapshots an in-flight task — intent, decisions, open questions, context handles — so the next session starts at ~2-4k tokens fully oriented.
Install
pip install claude-repo-mem
Requires Python 3.11+. Development install:
git clone https://github.com/amritmalla/claude-repo-mem
cd claude-repo-mem
pip install -e ".[dev]"
Quick start
cd your-repo
claude-repo-mem index # build the index (downloads bge-small on first run, ~90MB)
claude-repo-mem doctor # verify: units, by_layer, T2 coverage, counters
To expose it to Claude Code, drop a .mcp.json in your repo root:
{
"mcpServers": {
"claude-repo-mem": {
"command": "claude-repo-mem",
"args": ["serve", "--watch"]
}
}
}
Claude Code will auto-launch the server on workspace load. The --watch flag runs an incremental file watcher (debounced 750ms) so the index stays current as you edit.
Prefer not to run the watcher? Install a git hook instead:
claude-repo-mem install-hooks # writes .git/hooks/post-commit
Tools
All 11 tools are exposed over the MCP protocol. Group by intent:
Retrieval
recall(query, budget=3000, scopes?, layers?)— hybrid lexical + vector search with budgeted tier-aware fill.trace(seed_handles, depth=2, budget=8000)— graph traversal from a seed; returns full T0 source for connected nodes in one round-trip.expand(handle, tier="t0"|"t2"|"t1")— drill into one unit at a specific tier.
Memory
remember(fact, scope, kind="fact"|"decision"|"preference"|"convention", confidence?, supersedes?)— write a durable memory entry as.claude-repo-mem/memory/<scope>/<slug>.md.forget(handle)— tombstone a memory unit (frontmatter updated, file preserved).scopes()— list known scopes with unit counts.
Tasks & continuity
plan_task(intent, parent_id?, context_handles?)— LLM-decomposes into 2-6 independent child tasks via MCP sampling.tasks(status?, scope?, since_days?)— list persisted tasks with filters.handoff(task_id)— snapshot a task to.claude-repo-mem/handoffs/<id>.md+ write atask_snapshotunit.resume(task_id, budget=4000)— load latest snapshot + a budgeted bundle of its context handles.
Observability
stats()— index size, layer breakdown, tool-call counters.
CLI
claude-repo-mem index [--embedder NAME] [--no-embed] [--reset]
claude-repo-mem serve [--watch | --no-watch]
claude-repo-mem doctor # layer counts, T2 coverage, counters
claude-repo-mem install-hooks [--force] # git post-commit reindex
claude-repo-mem distill [--yes] [--transcript PATH] # extract durable memories from a transcript
claude-repo-mem bench --fixture queries.yaml [--k 5] [--no-embed]
Languages and synthesizers
| Language | Parser | Notes |
|---|---|---|
| Python | tree-sitter | classes, methods, functions, docstrings |
| JavaScript / TypeScript | tree-sitter | functions, classes, methods, JSX |
| Java | tree-sitter | classes, interfaces, methods, constructors |
| Go | tree-sitter | funcs, methods, structs, interfaces |
| Rust | tree-sitter | fn, impl methods, structs, traits |
| Markdown | markdown-it | sections by heading hierarchy |
Synthesizers add cross-file edges on top of parser output:
- Flask
@app.route(...)→ handler. - Django
path(...)/re_path(...)→ handler (resolves dotted refs againstviews.py). - Express
app.METHOD(url, handler)→ same-file handler. - Python imports → cross-module edges.
- React hooks —
useStatesetter calls emitmutates_state_ofedges on the containing component.
Embedders
Default is local bge-small (384d, CPU). Switch via --embedder or CLAUDE_REPO_MEM_EMBEDDER:
export OPENAI_API_KEY=sk-...
claude-repo-mem index --embedder openai --reset # text-embedding-3-small, 1536d
export VOYAGE_API_KEY=vy-...
claude-repo-mem index --embedder voyage --reset # voyage-3-lite, 512d
--reset is required when changing embedders — the vector dimension is baked into the SQLite vec0 table at schema creation.
LLM access
Tools that need an LLM (plan_task, summarizer backfill, distill) use MCP sampling by default — the host (Claude Code) supplies the model via the standard sampling protocol.
For CLI tools that run outside an MCP session (distill), fall back to the Anthropic API by setting:
export CLAUDE_REPO_MEM_LLM=anthropic
export ANTHROPIC_API_KEY=sk-ant-...
Where things live
.claude-repo-mem/
├── db.sqlite # the index (gitignored)
├── memory/<scope>/*.md # remember() writes — committed source of truth
├── handoffs/<task>.md # handoff() snapshots — committed, resumable
└── blobs/ # cached embeddings (gitignored)
Memory markdown files have YAML frontmatter:
---
kind: decision
scope: backend/auth
confidence: 0.9
created_at: 2026-05-26T10:00:00Z
---
We chose RS256 over HS256 so the API gateway can verify tokens without
holding the signing key.
Re-indexing preserves these — they're the source of truth, the SQLite index is derived.
Companion skills
plugin/skills/ ships three SKILL.md files that teach Claude when to call which tool:
claude-repo-mem-recall— use BEFOREGrep/Read.claude-repo-mem-trace— use AFTER recall when you have a seed handle.claude-repo-mem-handoff— use at end of session, before context bloat.
Drop them into any Claude Code plugin tree to make the tool-use rules ambient.
Integration with claude-full-stack-2.0
The claude-full-stack-2.0 plugin ships a memory-management skill that documents how to wire claude-repo-mem into projects built with that workflow. See INTEGRATION.md and skills/architecture/memory-management/ in that repo.
How it works
Substrate. A SQLite database with:
unit— addressable items (code symbols, doc sections, memories, tasks).relation— typed edges between units (calls,imports,route_to,child_task,mutates_state_of, …).unit_fts— FTS5 mirror of headers + summaries for lexical search.unit_vec— sqlite-vec virtual table for ANN search.
Retrieval. Hybrid: FTS BM25 ⊕ vector cosine, reciprocally-ranked, then a budget-aware fill that picks T0 / T2 / T1 per unit to fit your token cap. Overflow handles are returned for explicit drill-in.
Memory. Markdown files are the source of truth. The indexer treats .claude-repo-mem/memory/*.md like any other docs source — parse frontmatter, derive scope, write a memory layer unit. forget() tombstones via a sentinel handle so the FK constraint is satisfied.
Tasks. Units of layer=task, kind=task with structured JSON metadata. child_task relations build the tree. handoff() renders a markdown snapshot + writes a task_snapshot unit pointing at it.
Watcher. watchdog.Observer + a 750ms PathDebouncer → incremental_reindex(paths). Reindex jobs run on a single-worker BackgroundQueue so the watcher callback never blocks.
Full design in docs/specs/2026-05-25-claude-repo-mem-design.md. Per-phase plans under docs/plans/.
Development
pip install -e ".[dev]"
pytest # 255 fast tests
pytest -m slow # +5 slow tests (real watchdog FS events)
Phase tags mark each shipped milestone:
| Tag | Scope |
|---|---|
phase-1-complete |
Substrate, parsers, hybrid retrieval, recall / trace / expand |
phase-2-complete |
Memory layer, remember / forget / scopes / stats / plan_task / tasks, distillation |
phase-3-complete |
handoff / resume, file watcher, companion skills |
phase-4-complete |
Java / Go / Rust parsers, Django / Express / React synthesizers, install-hooks, background queue |
phase-5-complete |
Pluggable embedders (OpenAI / Voyage), queue-driven summarization, bench harness, distill UX |
License
MIT.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file claude_repo_mem-0.1.0.tar.gz.
File metadata
- Download URL: claude_repo_mem-0.1.0.tar.gz
- Upload date:
- Size: 47.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d1dedefd4cdf5242b98c8ec605042ba4e83fd0463e545ec2eb0fb0a44373426b
|
|
| MD5 |
35793b045987b32cd6db419b910ff1fe
|
|
| BLAKE2b-256 |
7e4b37f37ad8127d220916855c004d5ead86b0f655f94232b97dbc81dabc2640
|
Provenance
The following attestation bundles were made for claude_repo_mem-0.1.0.tar.gz:
Publisher:
python-publish.yml on amritmalla/claude-repo-mem
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
claude_repo_mem-0.1.0.tar.gz -
Subject digest:
d1dedefd4cdf5242b98c8ec605042ba4e83fd0463e545ec2eb0fb0a44373426b - Sigstore transparency entry: 1634595637
- Sigstore integration time:
-
Permalink:
amritmalla/claude-repo-mem@edbc341af5ac47cf7a65107a86271b8b556529e2 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/amritmalla
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@edbc341af5ac47cf7a65107a86271b8b556529e2 -
Trigger Event:
release
-
Statement type:
File details
Details for the file claude_repo_mem-0.1.0-py3-none-any.whl.
File metadata
- Download URL: claude_repo_mem-0.1.0-py3-none-any.whl
- Upload date:
- Size: 83.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1444df3c8135ac8ecd8ca3c2498d7bc8739037362fc20155d07ce2dece4aa9d5
|
|
| MD5 |
9337b6be1fceb4993b8c7f4440e52c8a
|
|
| BLAKE2b-256 |
ceacf95401f14c6771ff3a0c53bed98011fd7dfae25f5e1cca27f1a23cfe4546
|
Provenance
The following attestation bundles were made for claude_repo_mem-0.1.0-py3-none-any.whl:
Publisher:
python-publish.yml on amritmalla/claude-repo-mem
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
claude_repo_mem-0.1.0-py3-none-any.whl -
Subject digest:
1444df3c8135ac8ecd8ca3c2498d7bc8739037362fc20155d07ce2dece4aa9d5 - Sigstore transparency entry: 1634596610
- Sigstore integration time:
-
Permalink:
amritmalla/claude-repo-mem@edbc341af5ac47cf7a65107a86271b8b556529e2 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/amritmalla
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@edbc341af5ac47cf7a65107a86271b8b556529e2 -
Trigger Event:
release
-
Statement type: