{"slug": "stop-wasting-tokens-and-re-explaining-your-project-between-sessions", "title": "Stop wasting tokens and re explaining your project between sessions", "summary": "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.", "body_md": "Claude Code starts every session cold. Recall keeps a local log of your sessions and condenses it into a resume-ready summary —\n\nentirely 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.\n\n**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`\n\n(~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`\n\n, no local model to run, no key to configure, works offline. It starts working the moment the plugin loads.\n\nTwo files, written into your project under `.recall/`\n\n:\n\n—`history.md`\n\n*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`\n\n*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.\n\n| Moment | What happens |\n|---|---|\nDuring the session |\nThe `Stop` / `SessionEnd` hooks append new activity to `.recall/history.md` . Capture is incremental (only new turns) and fully local. |\nAt session start |\nThe `SessionStart` hook surfaces `context.md` and has Claude ask you two things: resume from the saved context? and keep logging this session? |\nBefore you wrap up |\nYou run `/recall:save` . The local summarizer reads `history.md` and (over)writes `context.md` . |\n…or automatically |\nSet `auto_save_context: \"on_end\"` and `context.md` regenerates every time a session ends — no `/recall:save` needed. |\n\nThere is no LLM call anywhere — the summary is produced by **TF-IDF + TextRank**\n(extractive summarization) running locally.\n\n`scripts/summarizer.py`\n\nranks the most central sentences of your session:\n\n- TF-IDF sentence vectors\n- a cosine-similarity graph between sentences\n**TextRank**— PageRank power iteration over that graph — to score sentences- the top\n*N*are kept in original order\n\n`context.md`\n\nwraps that summary with deterministic facts pulled straight from the\ntranscript and git: the goal (your first ask), files touched, commands run, where\nyou left off, and `git diff --stat`\n\n.\n\n**No installs required.** The whole TF-IDF + TextRank implementation is vendored\nin `summarizer.py`\n\n. If `numpy`\n\nhappens to be importable it's used to vectorize the\nmath (faster on big sessions); if not, an identical pure-Python TextRank runs\ninstead. Same algorithm, same result — numpy is an optional accelerator, never a\nrequirement. The save output tells you which path ran.\n\n`/recall:save`\n\n— run the local summarizer → (over)write`context.md`\n\n.`/recall:show`\n\n— print`context.md`\n\n.`/recall:log`\n\n— tail`history.md`\n\n.\n\nDrop this in your project root to override defaults:\n\n| Key | Default | Purpose |\n|---|---|---|\n`output_dir` |\n`\".recall\"` |\nWhere `history.md` / `context.md` live. |\n`capture_history` |\n`true` |\nAppend session activity to `history.md` . |\n`auto_save_context` |\n`\"off\"` |\nRegenerate `context.md` when a session ends: `\"off\"` or `\"on_end\"` . |\n`summary_sentences` |\n`8` |\nHow many sentences the summary keeps. |\n`redact` |\n`true` |\nStrip obvious secrets before writing the md files. |\n`include_git` |\n`true` |\nAdd `git diff --stat` + recent commits to `context.md` . |\n`max_input_chars` |\n`200000` |\nCap on text fed to the summarizer (oldest dropped). |\n\n**Pause logging** for a project without editing config: create\n`.recall/.capture-paused`\n\n. Delete it to resume.\n\nRecall makes **no network calls, uses no API key, and loads no third-party\nmodel.** The summarizer is local Python; the hooks are stdlib-only (numpy is an\noptional accelerator). It reads your session transcript and writes only under\n`output_dir`\n\n. Concretely:\n\n**No credentials, ever.** The plugin has zero references to API keys, auth,`ANTHROPIC_*`\n\n, or HTTP. If`claude`\n\nitself shows*\"Invalid API key\"*, that's the CLI's own auth — usually a stale`ANTHROPIC_API_KEY`\n\nenv var shadowing your subscription login.`unset ANTHROPIC_API_KEY`\n\n(or run`env -u ANTHROPIC_API_KEY claude …`\n\n). It has nothing to do with Recall.**Redaction.** A best-effort pass strips common secret shapes (API keys, tokens,`.env`\n\nassignments, PEM keys) before writing, since`context.md`\n\n/`history.md`\n\nmay be committed. Best-effort, not a guarantee — review before committing.**Hardened git.**`git diff`\n\n/`log`\n\nare run with`core.fsmonitor`\n\n,`diff.external`\n\n, 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`\n\nto skip git entirely.**Confined writes.**`output_dir`\n\nis forced to stay inside the project; a project-shipped config can't redirect writes to an absolute path or`../..`\n\n.**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`\n\nis 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/`\n\nas shared team memory`context.md`\n\nto 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/`\n\ngit-ignored (the default).\n\nBoth are fine. Commit it for shared team memory, or git-ignore it for personal\nmemory (`.gitignore`\n\nships ignoring it by default — flip the comment to commit).\n\n**From the marketplace** (this repo is its own marketplace):\n\n```\n/plugin marketplace add raiyanyahya/recall\n/plugin install recall@recall\n```\n\n**Local dev** (no install step):\n\n```\nclaude --plugin-dir /path/to/recall\n```\n\nNo `pip install`\n\n— the summarizer is vendored and stdlib-only (numpy used as an\noptional accelerator if present). Work a session, run `/recall:save`\n\n, and open\na fresh session — Recall greets you with where you left off.\n\n```\npython -m venv .venv && . .venv/bin/activate\npip install pytest ruff bandit numpy   # numpy optional\n\nruff check scripts tests               # lint\nbandit -c pyproject.toml -r scripts    # security static analysis\npytest                                 # run the suite (also test without numpy)\nclaude plugin validate .               # official manifest validation\n```\n\nCI (`.github/workflows/`\n\n) runs lint + Bandit, the test suite across Python\n3.9–3.13 **with and without numpy** (both summarizer paths), CodeQL, secret\nscanning, and manifest JSON validation on every push and PR. See\n[CONTRIBUTING.md](/raiyanyahya/recall/blob/master/CONTRIBUTING.md) and [SECURITY.md](/raiyanyahya/recall/blob/master/SECURITY.md).\n\n```\nrecall/\n├── .claude-plugin/plugin.json   # manifest\n├── hooks/hooks.json             # SessionStart (ask/resume) · Stop+SessionEnd (capture)\n├── commands/                    # /recall:save · show · log\n├── scripts/\n│   ├── summarizer.py            # vendored TF-IDF + TextRank (numpy optional)\n│   ├── make_context.py          # build/overwrite context.md\n│   ├── capture.py               # append session activity to history.md\n│   ├── session_start.py         # surface context + ask the start questions\n│   ├── parse_transcript.py      # transcript → events + renderers\n│   └── config.py · common.py · redact.py\n├── tests/                       # pytest suite (summarizer, capture, security, …)\n├── .github/                     # CI, CodeQL, secret scan, dependabot\n├── recall.config.json        # config template / defaults\n├── pyproject.toml               # ruff / pytest / bandit config (no runtime deps)\n├── LICENSE · SECURITY.md · CONTRIBUTING.md\n└── .gitignore\n```\n\nBugs and ideas are welcome — open an [issue](https://github.com/raiyanyahya/recall/issues/new/choose)\n(bug-report and feature templates provided) or a pull request. See\n[CONTRIBUTING.md](/raiyanyahya/recall/blob/master/CONTRIBUTING.md) before submitting, and report security\nvulnerabilities privately per [SECURITY.md](/raiyanyahya/recall/blob/master/SECURITY.md) rather than in a public issue.", "url": "https://wpnews.pro/news/stop-wasting-tokens-and-re-explaining-your-project-between-sessions", "canonical_source": "https://github.com/raiyanyahya/recall", "published_at": "2026-06-21 21:05:37+00:00", "updated_at": "2026-06-21 21:26:15.631660+00:00", "lang": "en", "topics": ["ai-tools", "developer-tools", "large-language-models", "ai-infrastructure"], "entities": ["Claude Code", "Recall", "TF-IDF", "TextRank", "numpy"], "alternates": {"html": "https://wpnews.pro/news/stop-wasting-tokens-and-re-explaining-your-project-between-sessions", "markdown": "https://wpnews.pro/news/stop-wasting-tokens-and-re-explaining-your-project-between-sessions.md", "text": "https://wpnews.pro/news/stop-wasting-tokens-and-re-explaining-your-project-between-sessions.txt", "jsonld": "https://wpnews.pro/news/stop-wasting-tokens-and-re-explaining-your-project-between-sessions.jsonld"}}