Your repo's memory, indexed locally. One SQLite file. Zero API keys.
coderecall is an MCP server that turns any local repo into a searchable index your AI coding agent can query directly β code and the notes, decisions, and patterns you've accumulated about it. It runs entirely on your laptop. No OpenAI key. No Ollama. No vector DB to host. Vendor it into your project, run init, restart Claude Code.
- Confidence-tiered context. Searches return full content for high-confidence hits, summaries for medium, and metadata-only stubs for the rest β so the model spends tokens where it's confident, not everywhere.
- Knows when it's stale. Every search response embeds a banner the agent can see (
π‘ Index is 17 days old), so the model can prompt you to reindex instead of silently searching old code. - Code + knowledge in one call.
add_knowledge("we use SWR not React Query becauseβ¦")lives next to your source in the same index, retrieved by the samesearchtool. - 6 languages with real parsers β TypeScript/JavaScript, Python, Go, Rust, Ruby, Elixir β plus a generic fallback. Adding a new one is a single file.
- Truly local. Embeddings run in-process via
Xenova/bge-small-en-v1.5(384-D, ~30 MB on first run). Index lives in a single.coderecall/index.dbβ gitignored per developer, vectors never travel through git. The tool itself is vendored attools/coderecall/and committed, so the whole team stays on the same pinned version.
| coderecall | claude-context | basic-memory | continue.dev @codebase |
|
|---|---|---|---|---|
| Local-only, no API key | β | β (needs embedder + Milvus) | β | β (deprecated) |
| Indexes code | β | β | β | β |
| Stores notes / decisions alongside code | β | β | β (separate) | β |
| Single-file SQLite β no daemon, no Docker | β | β | β | β |
| Tells the agent when the index is stale | β | β | β | β |
git diff aware incremental reindex |
β | partial | n/a | β |
| Works with any MCP client | β | β | β | β (VS Code extension) |
coderecall is vendored per project β its source lives at <your-project>/tools/coderecall/, gets committed alongside your code, and every dev shares the same pinned version. The local index (.coderecall/) and tools/coderecall/node_modules/ are gitignored automatically by init.
Open Claude Code (or Cursor) inside the project you want to give a memory to, and paste this prompt:
Set up coderecall (https://github.com/FedeMadoery/coderecall) in this project: install bun if it's missing, vendor the repo into ./tools/coderecall with `bunx degit FedeMadoery/coderecall tools/coderecall` (so no nested .git), run `bun install` inside tools/coderecall, then from this project's root run `bun ./tools/coderecall/scripts/cli.ts init && bun ./tools/coderecall/scripts/cli.ts index`. Append the "Code Memory" snippet from the repo's README to my CLAUDE.md (create it if missing), then tell me to restart so the mcp__coderecall__search tools load. Don't commit or push anything.
The agent vendors the tool into ./tools/coderecall, wires it into this project's .mcp.json with a portable relative path, runs the first index (~30 MB model download), and updates CLAUDE.md. Restart Claude Code when it's done.
# 1. Install bun (one-time)
curl -fsSL https://bun.sh/install | bash
# 2. From your project root, vendor coderecall into ./tools/coderecall
bunx degit FedeMadoery/coderecall tools/coderecall
cd tools/coderecall && bun install && cd ../..
# 3. Wire it into the project (writes .coderecall.json + a relative .mcp.json entry)
bun ./tools/coderecall/scripts/cli.ts init
# 4. Index the codebase (downloads ~30 MB embedding model on first run)
bun ./tools/coderecall/scripts/cli.ts index
# 5. Restart Claude Code (or Cursor). The `mcp__coderecall__search` tools appear.
# 6. Commit ./tools/coderecall β its node_modules is gitignored, your team gets a pinned version.
git add tools/coderecall .gitignore .coderecall.json .mcp.json
git commit -m "Add coderecall MCP server"Tip:
alias coderecall="bun ./tools/coderecall/scripts/cli.ts", thencoderecall init,coderecall index,coderecall search "...".
Updating coderecall: re-run bunx degit FedeMadoery/coderecall tools/coderecall --force && cd tools/coderecall && bun install to pull the latest version. Diff and commit β your team gets the update on next pull.
Add this to your project's CLAUDE.md so the agent reaches for the tool first:
## Code Memory
Before reading source files directly, **search the index first**:
mcp__coderecall__search("how does authentication work")
Use `filter: "code"` or `filter: "knowledge"` to narrow. The index covers
this repo and any knowledge entries added via `add_knowledge`.| Tool | Purpose |
|---|---|
search |
Confidence-tiered search β returns full / summary / metadata tiers. Use this by default. |
search_memory |
Same hybrid search, always returns full content. |
add_knowledge |
Store a knowledge entry (architecture / decision / pattern / note / troubleshooting). |
list_knowledge |
List entries, optionally filtered by category or tag. |
index_files |
Index a path. Defaults to extensions from .coderecall.json. |
index_diff |
Index only files changed between two git refs β fastest way to refresh after a branch switch or git pull. |
get_file_context |
List every chunk in a file with line ranges and signatures. |
get_index_stats |
File count, chunk count, knowledge count, last-indexed timestamp. |
The search tool retrieves 5Γ the requested number of candidates, scores them with FTS5 keyword + cosine vector + recency, enforces diversity (max 3 chunks per file), then expands each result into one of three tiers:
| Tier | Score | What you get |
|---|---|---|
| π’ Full | β₯ 0.7 | Complete content |
| π‘ Summary | 0.4 β 0.7 | Signature + first docstring line |
| π΄ Metadata | < 0.4 | Title, filepath, tags |
That trade-off is the point: you spend context on results the model is confident about, and keep low-confidence hits visible (cheap) so the model can request expansion if needed.
coderecall init writes (or updates) three things in your project:
| File | What it is |
|---|---|
.coderecall.json |
Project config: indexed extensions, ignore globs, embedding model, staleness thresholds. |
.mcp.json (or .cursor/mcp.json with --client cursor) |
MCP server entry for coderecall. Merges next to any existing servers β won't clobber. |
.gitignore |
Appends .coderecall/ (and tools/coderecall/node_modules/ for vendored installs). |
The .mcp.json entry adapts to where coderecall lives:
- Vendored (the recommended setup β coderecall is inside the project at
tools/coderecall/): server path is written as a portable relative path (./tools/coderecall/src/index.ts) and theCODERECALL_PROJECT_ROOTenv var is omitted β the server uses the MCP client's launch CWD. The result is fully portable: commit.mcp.jsonand every teammate's setup works without path rewrites. - External (coderecall lives somewhere outside the project): server path is absolute, and
CODERECALL_PROJECT_ROOTis set explicitly.
It auto-detects the project language by scanning for a manifest file (mix.exs, Cargo.toml, go.mod, pyproject.toml / requirements.txt / Pipfile, Gemfile, tsconfig.json, package.json) and picks sensible default extensions. If no manifest is found, init will prompt interactively for a language; in non-interactive runs (agents, CI) it exits non-zero with a list of known languages so the agent can ask you, then re-run with --language <name> or --extensions ".ext1,.ext2". Both flags also override auto-detection β useful for polyglot repos (e.g. a Python service with a package.json for tooling). Re-run with --force to overwrite, --no-mcp to skip the MCP file, or pass a path: coderecall init /path/to/project.
The index is local per developer. .coderecall/ is gitignored β vectors are never shared via git. Every teammate runs indexing on their own machine against their own checkout.
coderecall indexScans the project, parses every file matching extensions, chunks it, embeds each chunk (384-D, batched), and stores everything in .coderecall/index.db. The first run also downloads the ~30 MB embedding model. Rough numbers on CPU: ~15β30 ms per chunk with batched embeddings; a 5,000-chunk repo finishes its first index in ~2β3 min.
Which files get scanned. In a git repo, the scanner uses git ls-files (tracked + untracked-but-not-gitignored) β so anything in your .gitignore is skipped automatically, including weirdly-named Python venvs (api-venv/, my-env-3.11/, etc.). Outside a git repo, it falls back to a glob walk using the ignore patterns in .coderecall.json; for Python projects it also detects venvs by their pyvenv.cfg marker so the directory name doesn't matter. Pass --no-git-ls to force the glob path.
coderecall index is content-hash-aware: every file's SHA-256 is stored, and unchanged files are skipped instantly. Running coderecall index against a fully-up-to-date repo finishes in under a second. So the safe default after a work session is to just re-run it.
The one thing a full index does not handle is deleted or renamed files β chunks for files that no longer exist stay in the DB. Use index-diff (which inspects git diff --name-status) or nuke .coderecall/ when that matters.
| Situation | Command |
|---|---|
| You edited some files | coderecall index |
| You deleted, moved, or renamed files | coderecall index-diff . --base HEAD~1 --head HEAD |
You just git pulled teammate work |
coderecall index-diff . --base ORIG_HEAD --head HEAD |
| You switched branches | coderecall index-diff . --base <prev-branch> --head HEAD |
You changed extensions or ignore in config |
rm -rf .coderecall && coderecall index |
You changed embeddingModel |
rm -rf .coderecall && coderecall index |
The server tracks when the last full index run completed and surfaces age in every search response. Two thresholds are configurable in .coderecall.json:
"staleAfterDays": 14,
"veryStaleAfterDays": 30Past the first threshold, every search response prefixes a yellow banner:
π‘ Index is 17 days old (threshold: 14d). Consider `coderecall index` to refresh.
Past the second, it turns red. The point is that the agent sees the warning and can suggest a reindex instead of silently searching against a stale snapshot.
Knowledge entries created via add_knowledge, import-obsidian, or import-knowledge-file are embedded the moment they're added β no separate reindex step. They live in the same SQLite DB and are searched alongside code by default.
No file watcher is built in β re-indexing while a tool is reading from the DB can race. Pick whichever fits your workflow:
- Manual β just run
coderecall indexbefore searching, after a work session. - Git
post-commithook β cheap on every commit thanks to content-hash skipping:# .git/hooks/post-commit coderecall index >/dev/null 2>&1 &
- Editor task β bind a key in VS Code / your editor to
coderecall index.
| Layer | What it does |
|---|---|
| MCP tools | search Β· add_knowledge Β· index_files Β· index_diff Β· get_file_context Β· get_index_stats |
| Confidence-tiered retrieval | pool β scoring β diversity β tiered expansion |
| Hybrid search | FTS5 (porter) + cosine 384-D |
| Indexing | scanner β parsers β chunker β embeddings |
| SQLite | knowledge_entries Β· code_files Β· code_chunks Β· embeddings Β· memory_fts |
A new language is a single file in src/indexer/parsers/<lang>.ts implementing the LanguageParser interface (regex or tree-sitter β your call), then a one-line entry in src/indexer/parsers/index.ts. PRs welcome.
CLI reference
coderecall init [path] [--language <name>] [--extensions ".ext1,.ext2"] [--force] [--no-mcp]
coderecall index [path] [--extensions ".ext1,.ext2"] [--no-git-ls]
coderecall index-diff [path] --base HEAD~1 --head HEAD
coderecall search "<query>" [--filter code|knowledge] [--limit 10] [--expansion selective|all|metadata_only]
coderecall search-legacy "<query>" # full-expansion mode (no tiering)
coderecall stats
coderecall add-knowledge # interactive
coderecall list-knowledge [--category X] [--tag Y]
coderecall import-obsidian --vault /path/to/vault
coderecall import-knowledge-file ./NOTES.md --category noteinit resolution order for which extensions to index: --extensions flag β --language preset β auto-detect from manifest β interactive prompt (TTY) β exit with instructions (non-TTY, so an agent can ask you).
Known --language presets: typescript, javascript, python, ruby, go, rust, elixir, java, kotlin, swift, csharp, cpp, php.
All commands honor CODERECALL_PROJECT_ROOT, CODERECALL_INDEX_PATH, CODERECALL_EXTENSIONS, CODERECALL_IGNORE, and CODERECALL_EMBEDDING_MODEL.
Config (.coderecall.json)
{
"indexPath": ".coderecall",
"extensions": [".ts", ".tsx", ".js", ".jsx"],
"ignore": [
"**/node_modules/**", "**/dist/**", "**/build/**",
"**/.next/**", "**/.git/**", "**/.coderecall/**"
],
"embeddingModel": "Xenova/bge-small-en-v1.5",
"staleAfterDays": 14,
"veryStaleAfterDays": 30
}indexPathβ where the SQLite DB lives. Relative paths resolve from the project root.extensionsβ what gets parsed. Anything not in the language registry falls back to a generic block chunker.ignoreβ glob patterns excluded during scanning.embeddingModelβ defaults toXenova/bge-small-en-v1.5(384-D, ~30 MB). Any other 384-D model is a drop-in. Switching to a different dimension (e.g.Xenova/bge-base-en-v1.5at 768-D) requires reindexing β old vectors are silently incompatible.staleAfterDays/veryStaleAfterDaysβ yellow / red staleness banner thresholds. Defaults: 14 / 30.
Troubleshooting
MCP tools don't appear after init β restart your MCP client. Claude Code reloads .mcp.json on launch.
Search returns nothing β run coderecall stats. If Total chunks is 0, run coderecall index.
Search returns stale results / deleted files β full index doesn't clean deletions. Run coderecall index-diff or rm -rf .coderecall && coderecall index.
First search/index is slow β first run downloads the ~30 MB embedding model. Subsequent runs use the local cache.
Type errors when editing β bun install && bunx tsc --noEmit.
The confidence-tiered expansion idea is loosely inspired by recent RAG-decoding research (notably Meta's REFRAG paper on selective chunk expansion), adapted here as a simple retrieval-side scoring heuristic rather than a learned decoder modification.
![]() @jichon Original idea |
![]() @FedeMadoery Author & maintainer |
@jichon originally conceived the idea this project is based on β he sketched it out for a single use case, and this repo generalizes it into a reusable tool.
MIT


