Stop wasting tokens and re explaining your project between sessions A new open-source tool called Recall solves the cold-start problem for Claude Code by keeping a local log of sessions and condensing it into a resume-ready summary using a classical Python summarizer (TF-IDF + TextRank), entirely on the user's machine with no API calls. It saves usage credits by avoiding model tokens for memory and ensures privacy by never sending transcripts externally. The tool is free for subscription users and requires no installation beyond loading the plugin. Claude Code starts every session cold. Recall keeps a local log of your sessions and condenses it into a resume-ready summary — entirely on your machine. No API key, no external model, nothing sent anywhere. It's built for people running Claude Code locally on a subscription: the only AI in the loop is Claude Code itself; the summarization is done by a classical Python summarizer. Free on your subscription. It solves the cold-start problem — no more re-explaining the project each session — without a metered summarizer running up a bill. The summary is a local algorithm, not an LLM call, so persistent memory costs you nothing beyond the subscription you already pay for. Saves your usage credits. Two ways: 1 the summary is built locally, so capturing and updating your memory spends zero model tokens; and 2 resuming from a compact context.md ~1–2K tokens instead of re-explaining the project from scratch each session means far fewer tokens spent per session — stretching your subscription's usage limits or, on the API, lowering billed credits . Nothing leaves your machine. Your transcripts code, paths, sometimes secrets are never sent to any API. Most "memory" tools pipe your context to a model endpoint; Recall makes a privacy guarantee they can't. Zero-friction. No pip install , no local model to run, no key to configure, works offline. It starts working the moment the plugin loads. Two files, written into your project under .recall/ : — history.md the log. Append-only. Every session is captured here as it happens your prompts, Claude's replies, the files touched and commands run .— context.md the summary. Overwritten by the local summarizer — the condensed "where are we right now" you load into the next session: goal, summary, next steps / open threads , files touched, and where you left off. | Moment | What happens | |---|---| During the session | The Stop / SessionEnd hooks append new activity to .recall/history.md . Capture is incremental only new turns and fully local. | At session start | The SessionStart hook surfaces context.md and has Claude ask you two things: resume from the saved context? and keep logging this session? | Before you wrap up | You run /recall:save . The local summarizer reads history.md and over writes context.md . | …or automatically | Set auto save context: "on end" and context.md regenerates every time a session ends — no /recall:save needed. | There is no LLM call anywhere — the summary is produced by TF-IDF + TextRank extractive summarization running locally. scripts/summarizer.py ranks the most central sentences of your session: - TF-IDF sentence vectors - a cosine-similarity graph between sentences TextRank — PageRank power iteration over that graph — to score sentences- the top N are kept in original order context.md wraps that summary with deterministic facts pulled straight from the transcript and git: the goal your first ask , files touched, commands run, where you left off, and git diff --stat . No installs required. The whole TF-IDF + TextRank implementation is vendored in summarizer.py . If numpy happens to be importable it's used to vectorize the math faster on big sessions ; if not, an identical pure-Python TextRank runs instead. Same algorithm, same result — numpy is an optional accelerator, never a requirement. The save output tells you which path ran. /recall:save — run the local summarizer → over write context.md . /recall:show — print context.md . /recall:log — tail history.md . Drop this in your project root to override defaults: | Key | Default | Purpose | |---|---|---| output dir | ".recall" | Where history.md / context.md live. | capture history | true | Append session activity to history.md . | auto save context | "off" | Regenerate context.md when a session ends: "off" or "on end" . | summary sentences | 8 | How many sentences the summary keeps. | redact | true | Strip obvious secrets before writing the md files. | include git | true | Add git diff --stat + recent commits to context.md . | max input chars | 200000 | Cap on text fed to the summarizer oldest dropped . | Pause logging for a project without editing config: create .recall/.capture-paused . Delete it to resume. Recall makes no network calls, uses no API key, and loads no third-party model. The summarizer is local Python; the hooks are stdlib-only numpy is an optional accelerator . It reads your session transcript and writes only under output dir . Concretely: No credentials, ever. The plugin has zero references to API keys, auth, ANTHROPIC , or HTTP. If claude itself shows "Invalid API key" , that's the CLI's own auth — usually a stale ANTHROPIC API KEY env var shadowing your subscription login. unset ANTHROPIC API KEY or run env -u ANTHROPIC API KEY claude … . It has nothing to do with Recall. Redaction. A best-effort pass strips common secret shapes API keys, tokens, .env assignments, PEM keys before writing, since context.md / history.md may be committed. Best-effort, not a guarantee — review before committing. Hardened git. git diff / log are run with core.fsmonitor , diff.external , hooks, and the pager disabled, so an untrusted cloned repo can't use its own git config to execute code when Recall reads ground-truth. Set include git: false to skip git entirely. Confined writes. output dir is forced to stay inside the project; a project-shipped config can't redirect writes to an absolute path or ../.. . Scoped transcript. Recall only reads the transcript for the current project matched by cwd ; it never falls back to another project's sessions. Trust boundary for shared memory. context.md is injected into the model at session start. If you commit , treat it like any other shared input: a teammate or a bad actor with repo write access could craft a .recall/ as shared team memory context.md to attempt prompt-injection. SessionStart fences the content and labels it untrusted data, and Claude asks before relying on it — but if you don't fully trust who can write the repo, keep .recall/ git-ignored the default . Both are fine. Commit it for shared team memory, or git-ignore it for personal memory .gitignore ships ignoring it by default — flip the comment to commit . From the marketplace this repo is its own marketplace : /plugin marketplace add raiyanyahya/recall /plugin install recall@recall Local dev no install step : claude --plugin-dir /path/to/recall No pip install — the summarizer is vendored and stdlib-only numpy used as an optional accelerator if present . Work a session, run /recall:save , and open a fresh session — Recall greets you with where you left off. python -m venv .venv && . .venv/bin/activate pip install pytest ruff bandit numpy numpy optional ruff check scripts tests lint bandit -c pyproject.toml -r scripts security static analysis pytest run the suite also test without numpy claude plugin validate . official manifest validation CI .github/workflows/ runs lint + Bandit, the test suite across Python 3.9–3.13 with and without numpy both summarizer paths , CodeQL, secret scanning, and manifest JSON validation on every push and PR. See CONTRIBUTING.md /raiyanyahya/recall/blob/master/CONTRIBUTING.md and SECURITY.md /raiyanyahya/recall/blob/master/SECURITY.md . recall/ ├── .claude-plugin/plugin.json manifest ├── hooks/hooks.json SessionStart ask/resume · Stop+SessionEnd capture ├── commands/ /recall:save · show · log ├── scripts/ │ ├── summarizer.py vendored TF-IDF + TextRank numpy optional │ ├── make context.py build/overwrite context.md │ ├── capture.py append session activity to history.md │ ├── session start.py surface context + ask the start questions │ ├── parse transcript.py transcript → events + renderers │ └── config.py · common.py · redact.py ├── tests/ pytest suite summarizer, capture, security, … ├── .github/ CI, CodeQL, secret scan, dependabot ├── recall.config.json config template / defaults ├── pyproject.toml ruff / pytest / bandit config no runtime deps ├── LICENSE · SECURITY.md · CONTRIBUTING.md └── .gitignore Bugs and ideas are welcome — open an issue https://github.com/raiyanyahya/recall/issues/new/choose bug-report and feature templates provided or a pull request. See CONTRIBUTING.md /raiyanyahya/recall/blob/master/CONTRIBUTING.md before submitting, and report security vulnerabilities privately per SECURITY.md /raiyanyahya/recall/blob/master/SECURITY.md rather than in a public issue.