{
  "markdown": "# claude-handoff\n\n![claude-handoff: the noisy transcript flows through chf and becomes a clean handoff.md and standing project memory](docs/assets/hero.svg)\n\n[![PyPI](https://img.shields.io/pypi/v/claude-handoff)](https://pypi.org/project/claude-handoff/)\n[![Python](https://img.shields.io/pypi/pyversions/claude-handoff)](https://pypi.org/project/claude-handoff/)\n[![CI](https://github.com/Vasilispapg/claude-handoff/actions/workflows/ci.yml/badge.svg)](https://github.com/Vasilispapg/claude-handoff/actions/workflows/ci.yml)\n[![Downloads](https://img.shields.io/pypi/dm/claude-handoff)](https://pypi.org/project/claude-handoff/)\n[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)\n\n**Turn any Claude Code session — even a crashed one — into a clean `handoff.md` another AI can continue from. And give Claude Code permanent project memory, distilled from your own history.**\n\n```bash\nchf\n```\n\nThat's it. Your latest session becomes `handoff.md`: the conversation without\nthe noise, the files that changed, the commands that ran — opening with\ninstructions to the receiving assistant, so you can paste it straight into\nGemini, GPT, claude.ai, or a fresh Claude Code session with zero extra\nprompting.\n\n![chf -o clipboard in action — five seconds from session to paste-ready handoff](docs/assets/demo.gif)\n\nClaude Code stores every session locally as JSONL\n(`~/.claude/projects/…/*.jsonl`), full of tool calls, tool results, thinking\nblocks and system reminders. Existing exporters dump all of that into\nmarkdown. `claude-handoff` instead produces a **handoff document** — and,\nsince it can read your *entire* history, a **project memory brief** too.\n\n- **Zero dependencies.** Stdlib only, Python 3.9+. A nine-module package —\n  also shipped as a generated single-file script you can `curl` and audit.\n- **Deterministic by default.** No API call, no cost, works offline.\n- **`--llm` when you want a real summary.** Claude, OpenAI or Gemini via\n  your own API key — or `--llm claude-cli`, which runs your locally-installed\n  Claude Code CLI on your existing Pro/Max plan: **no API key at all**.\n- **Noise-free.** Drops tool results, thinking blocks, system reminders,\n  subagent chatter, slash-command envelopes. Keeps user intent, assistant\n  answers, files modified, commands run — including the files and commands\n  of subagents (`agent-*.jsonl`), whose full transcripts stay behind\n  `--include-sidechains`.\n- **Project memory.** `chf --brief` distills a project's ENTIRE session\n  history into one living brief — what this is, where things stand,\n  decisions, fixes, conventions, and an ordered resume plan of open\n  threads, every claim citing its session; `--install-brief-hook` injects\n  it into every new Claude Code session, so Claude starts already knowing\n  the project.\n- **Safe to paste.** Secret-looking strings (API keys, tokens,\n  `password=`…) are redacted from every output — the handoff you paste into\n  a web chat is egress too. `--anonymize` goes further for public sharing.\n\n---\n\n## Prerequisites\n\n| Requirement | Minimum | Check | Notes |\n|---|---|---|---|\n| Python | 3.9+ | `python3 --version` | The only hard requirement |\n| Claude Code | any | `claude --version` | Only for `--llm claude-cli` (uses your Pro/Max login) |\n| pipx *(recommended)* | any | `pipx --version` | `pip install pipx` — or use brew / plain pip |\n\nNo third-party Python packages, ever — everything runs on the standard library.\n\n## Install\n\n```bash\npipx install claude-handoff        # or: pip install claude-handoff\n```\n\n```bash\nbrew install Vasilispapg/tap/claude-handoff   # Homebrew\n```\n\n```bash\n# or just grab the generated single-file build — stdlib-only, auditable:\ncurl -O https://raw.githubusercontent.com/Vasilispapg/claude-handoff/main/single/claude_handoff.py\npython3 claude_handoff.py --list\n```\n\nInstalling the package gives you two identical commands: `claude-handoff`\nand the short alias **`chf`**. Tab completion:\n\n```bash\neval \"$(claude-handoff --completions zsh)\"    # bash works too\n```\n\n---\n\n## 60 seconds: pick your situation\n\n**A session crashed, hit the usage limit, or you closed the terminal:**\n\n```bash\nchf -o clipboard\n```\n\n…then paste into claude.ai, ChatGPT, Gemini — or a fresh `claude` session.\nWorks on any old session; nothing needed to be installed *before* the crash.\n\n**Moving work from Claude Code to another model:**\n\n```bash\nchf --fit 32k -o clipboard         # sized to the receiver's context window\n```\n\n**\"Which session was it where we talked about CORS?\"**\n\n```bash\nchf --list --grep \"CORS\"           # every match, with a 🔍 context preview\nchf --grep \"CORS\"                  # or export the newest match directly\n```\n\n**Give Claude Code permanent memory of this project:**\n\n```bash\nchf --brief --llm claude-cli       # distill ALL sessions → one cited brief\nchf --install-brief-hook           # every new session starts knowing it\n```\n\n**A real summary instead of the transcript (goal / decisions / state / next):**\n\n```bash\nchf --llm claude-cli               # your Claude Code login — no API key\n```\n\n**A claude.ai or ChatGPT web chat instead of a terminal session:**\n\n```bash\nchf conversations.json --list      # each app's data export works as input\nchf conversations.json --name \"webhook bug\"\n```\n\n---\n\n## Project memory (`--brief`)\n\nClaude Code forgets everything between sessions — but the whole history is\non your disk. `chf --brief` reads **every** session of the current project\nand writes one memory document to `~/.claude/briefs/<project>.md`:\n\n- a factual **session timeline** + most-touched files (deterministic, free);\n- with `--llm`, a **distilled memory** that opens with *what this is*\n  (product, stack, current state) and *where things stand* (done / in\n  flight / not started), then decisions with their why, fixed bugs,\n  conventions — and *open threads* as an ordered resume plan, each with\n  its concrete next action and a `[in flight]` / `[blocked]` /\n  `[not started]` tag. Every bullet cites the session id it came from\n  (`chf --name <id>` opens the source).\n\n![chf --brief in action — the whole project history distilled into cited memory](docs/assets/demo-brief.gif)\n\nPer-session notes are cached, so refreshing after new sessions only pays\nfor the new ones — and a monster session (beyond ~120k chars) is\nmap-reduced *inside* the note, so the memory path never truncates:\nnothing is silently dropped, at any size.\n\nYou can also curate what feeds the memory: `--exclude <id>` leaves a\nsession out (a duplicate, an experiment — bare `--exclude` opens a\nnumbered picker that remembers: the stored exclusions arrive\npre-selected with ✗ and typed numbers toggle, so you edit the set\ninstead of re-picking it), and `--keep first:2,last:20` windows a huge history to\nthe founding sessions plus a sliding recent window. Both are **sticky** —\nstored in the brief's stamp, so hooks and later refreshes keep honoring\nthem until you change them (`--exclude none`, `--keep all`). And\n`chf --brief -o clipboard` ships the current brief — distillation\nincluded — straight to the clipboard, one paste away from handing your\nproject memory to another model.\n\nThe brief also goes beyond the project store: `chf --brief --grep X\n-o -` distills a **thematic memory** (only the sessions that talked\nabout X), and `chf conversations.json --brief -o brief.md` builds\nstanding memory **from a claude.ai or ChatGPT export** — every\nconversation, cited by its id. Both are exports by design (explicit\n`-o` only) so they never overwrite the standing brief.\n\nRunning **graphify**? The two tools compose in both directions, zero\nconfig: `chf --brief -o graphify` files the current memory into `raw/`\n— one evolving `project-memory.md` that the next `/graphify --update`\nlinks into the code's knowledge graph — and once\n`graphify-out/graph.json` exists, every brief gains a free `## Code\nmap` (communities, hub concepts, cross-community `bridges:`, labeled\n`flows:`) so new sessions know the code's *structure*, not just its\nhistory. The in-project copies (`raw/project-memory.md`, optional root\n`BRIEF.md`) refresh on every brief write — strictly refresh-only,\nhooks never create files. The full loop lives in\n**[docs/GUIDE.md](docs/GUIDE.md)**.\n\n```bash\nchf --install-brief-hook\n```\n\ninstalls two hooks: **SessionStart** injects the brief as context (Claude\nstarts already knowing your project — re-injected after `/compact` too),\n**SessionEnd** auto-refreshes the factual part for free. **No LLM ever runs\nfrom a hook**; the distilled part refreshes only when you say so. The brief\ncarries a freshness stamp, and when newer sessions or commits exist the\nfile and the injection don't just warn — they list them (session titles,\ncommit subjects), so a fresh session sees *what* changed, not merely that\nsomething did. Fully local; redaction applies as everywhere.\n\n→ Step-by-step mechanics, the honest cost table, and a full day-with-it\nwalkthrough: **[docs/GUIDE.md](docs/GUIDE.md)**.\n\n## Make it automatic\n\n```bash\nchf --install-hook                 # SessionEnd + PreCompact → handoff to ~/.claude/handoffs/\nchf --install-brief-hook           # SessionStart/End + PreCompact → project memory (above)\nchf --install-skill                # /claude-handoff skill → Claude Code drives chf correctly\n```\n\nPreCompact matters: right before Claude Code compacts a long session's\ncontext, both hooks snapshot state — the handoff preserves detail that\ncompaction is about to squeeze away, and the brief skeleton stays fresh\nmid-session.\n\nBoth edit `~/.claude/settings.json` non-destructively, are idempotent, and\nhave matching `--uninstall-*` flags. Hook failures never break the host\nsession, and hooks never trigger LLM calls or create files on their own.\n\nThe third one is for Claude itself: `--install-skill` puts a\n`/claude-handoff` skill into `~/.claude/skills/` (plus its trigger in\n`~/.claude/CLAUDE.md`), so Claude Code knows the tool's grammar instead of\nguessing — which session bare `chf` picks from inside a live session,\n`claude-cli` (subscription) vs `claude` (API key), `--fit` for token\nbudgets, no interactive pickers from an agent shell. Idempotent, respects\na hand-written section, and `--uninstall-skill` removes both pieces\nwithout touching anything else in either file.\n\n---\n\n## What the output looks like\n\n```markdown\n# Conversation handoff\n\n> To the receiving assistant: … you are taking over …\n\n## Session\n- Project: /home/you/myapp (branch main)\n- When: 2026-08-20 09:00 → 09:04\n- Activity: 2 user messages, 2 assistant replies, 4 tool calls\n\n## Files created / modified\n- auth.py\n\n## Commands run\n- python -m pytest tests/test_auth.py -q\n\n_🤖 2 subagent(s) contributed to the work above (--include-sidechains for their transcripts)._\n\n## Conversation\n\n_Condensed digest, every turn capped — verbatim messages with --full, a real summary with --llm._\n\n- **🧑 User:** the login breaks on unicode passwords…\n- **🤖 Assistant:** Found it — ascii encoding. Changed to utf-8, tests pass. _[4 tool calls]_\n- 🔔 Agent \"Update the docs\" finished\n```\n\nEvery turn is there, condensed to its lead — it's a summarize tool, not\nan exporter. `--full` switches to classic verbatim messages, and `--llm`\nreplaces the digest with a real summary that read *everything*.\n\n## Common commands\n\n```bash\nchf                                # latest session → handoff.md\nchf -i                             # numbered picker; \"1,3\" or \"2-4\" merges several\nchf --list                         # what sessions do I have? (title · first prompt)\nchf --list --format json           # the same, machine-readable\nchf --name \"login bug\"             # newest session whose title/prompt matches\nchf \"login bug\"                    # same — a non-path argument is a name search\nchf --grep \"CORS\"                  # newest session that *talked about* CORS\nchf --grep CORS --grep auth        # …that talked about BOTH (AND)\nchf a.jsonl b.jsonl                # several paths → ONE merged handoff\nchf --project myrepo               # latest session of a specific project\nchf path/to/session.jsonl -o -     # explicit file → stdout\nchf -o clipboard                   # straight to the clipboard — go paste it\nchf --full                         # verbatim messages instead of the digest\nchf --last 5                       # only the last 5 user turns\nchf --since 2h                     # only the last 2 hours of the session\nchf --fit 32k                      # sized to fit a 32k-token context\nchf --include-tools                # keep collapsed per-tool-call detail\nchf --include-sidechains           # append full subagent transcripts\nchf --anonymize                    # public-safe: ~ paths, no emails/IPs/username\nchf --project myrepo --merge       # whole project in ONE handoff, oldest → newest\nchf --format json -o session.json  # machine-readable handoff\n\n# LLM summaries (goal / decisions / current state / next steps).\n# --llm composes with EVERYTHING above — picker, --name/--grep/--project,\n# --merge, --last/--since, clipboard, JSON… (only --fit stays\n# deterministic-only, by design):\nchf --llm claude-cli               # your Claude Code login — no API key\nchf --llm ollama                   # local model — fully offline\nchf --llm claude                   # Anthropic API   (ANTHROPIC_API_KEY)\nchf --llm openai --model gpt-4o    # OpenAI API      (OPENAI_API_KEY)\nchf --llm gemini --with-transcript # Google API      (GEMINI_API_KEY)\nchf --llm claude-cli --focus \"emphasize the API decisions\"\nchf --grep CORS --llm claude-cli   # find the session, then summarize it\nchf -i --merge --llm claude-cli -o clipboard   # pick several → ONE summary, pasted\nchf --since 2h --llm claude-cli    # summarize just the last two hours\n\n# project memory:\nchf --brief                        # free factual brief (timeline + files)\nchf --brief --llm claude-cli       # + distilled decisions/fixes/conventions\nchf --brief --exclude              # numbered picker: edit the sticky exclusions (✗ pre-selected, numbers toggle)\nchf --brief --keep first:2,last:20 # bound a huge history: founding + recent\nchf --brief --keep since:30d       # …or by time — the window slides\nchf --brief --grep auth -o -       # thematic memory: only the auth sessions\nchf conversations.json --brief -o brief.md   # memory from a claude.ai/ChatGPT export\n```\n\n**Where does it look?** Sessions live in Claude Code's global store\n(`~/.claude/projects`), so you can run `chf` from anywhere. If your current\ndirectory *is* a project (or a subfolder of one), it scopes to that\nproject's sessions; a parent \"master folder\" scopes to every project under\nit; `--any` ignores the directory entirely. Auto-selection skips\nnearly-empty sessions (like the stub `claude /login` leaves behind) so\n\"latest\" means your latest *real* conversation — an explicit path, `--name`\nor `-i` always wins.\n\n**Big sessions.** Transcripts beyond one pass (~400k chars) are summarized\nmap-reduce style: notes per chunk, then one synthesis — nothing is silently\ndropped, and finished chunks are cached in `~/.cache/claude-handoff` so an\ninterrupted run resumes for free. Chunks run 4-way parallel on API\nproviders; `claude-cli` and `ollama` stay sequential by design. In a\nterminal you get a live progress bar:\n\n```text\n[█████████░░░░░░░░░░░░░░░] 3/9 chunks | 4m12s elapsed | ~8m left | summarizing part 4/8 (199,867 chars)…\n```\n\nSessions with API `usage` data also get a **Tokens** line in the header,\nand every run reports the output's ≈token size.\n\n## Privacy & zero-trust\n\n- **Nothing is sent anywhere unless you pass `--llm`** — deterministic mode\n  is fully offline.\n- **Redaction is on for every output**, not just LLM traffic: secret-shaped\n  strings (API keys, tokens, JWTs, `password=`…) are stripped from the\n  handoff itself, hook files, and MCP replies — a pasted document is egress\n  too. `--no-redact` opts out per run (and is deliberately *not* allowed in\n  the config file).\n- **`--anonymize`** additionally collapses your home directory to `~` and\n  replaces emails, IPv4s and your username with placeholders — for pasting\n  into public issues and forums.\n- `--llm claude-cli` and `--llm ollama` keep everything inside accounts and\n  machines you already control.\n- **Prompt-injection defense**: transcripts routinely embed untrusted text\n  (web pages in tool results, pasted READMEs). Every prompt that consumes\n  a transcript, the handoff preamble, and the brief injection wrapper all\n  frame that content as *data, not instructions* — pinned by tests. A\n  mitigation, not a proof; the parser itself never executes anything.\n\n## Config (optional)\n\nPut defaults you always use in `~/.config/claude-handoff/config.json`\n(CLI flags always win; `CLAUDE_HANDOFF_CONFIG` overrides the path):\n\n```json\n{ \"llm\": \"claude-cli\", \"fit\": \"32k\", \"include_tools\": true }\n```\n\nAllowed keys: `llm`, `model`, `fit`, `output`, `include_tools`,\n`include_sidechains`, `max_chars`, `anonymize`, `focus`. Security switches\n(`no_redact`) are deliberately **not** configurable — weakening redaction\nmust be an explicit per-run choice. A broken config warns and is ignored,\nnever fatal.\n\n## Environment variables\n\n| Variable | Purpose |\n|---|---|\n| `ANTHROPIC_API_KEY` / `CLAUDE_API` | key for `--llm claude` (first set wins) |\n| `OPENAI_API_KEY` / `GPT_API` | key for `--llm openai` |\n| `GEMINI_API_KEY` / `GOOGLE_API_KEY` / `GEMINI_API` | key for `--llm gemini` |\n| `OLLAMA_MODEL` / `OLLAMA_BASE_URL` | local Ollama model and endpoint |\n| `CLAUDE_HOME` | Claude Code home (default `~/.claude`) — where sessions, handoffs and briefs live |\n| `CLAUDE_HANDOFF_CACHE` | chunk/note cache dir (default `~/.cache/claude-handoff`) |\n| `CLAUDE_HANDOFF_CONFIG` | config file path (default `~/.config/claude-handoff/config.json`) |\n| `CLAUDE_HANDOFF_DEBUG` | `1` = same as `--debug`; also lights up the hooks (add it to the hook command or your shell env) |\n\n`claude-cli` needs no variable — it shells out to your installed\n[Claude Code](https://claude.ai/code) CLI, billed to your Pro/Max plan\n(run `claude` once to log in).\n\n## MCP server\n\nAny MCP client (Claude Desktop, Claude Code, …) can pull handoffs directly:\n\n```bash\nclaude mcp add claude-handoff -- claude-handoff --mcp\n```\n\nTools: `list_sessions` (what's on this machine) and `handoff` (build the\ndocument for a session by name/project/path; pass `anonymize` for a\nshareable version). Deterministic by default — an MCP client can only\ntrigger LLM summaries when you start the server with `--allow-llm`.\n\n## Troubleshooting\n\n**`claude-handoff: command not found` after `pip install`**\npip puts scripts in a user bin dir that may not be on PATH. Use\n`pipx install claude-handoff` or brew — both manage PATH — or add\n`~/.local/bin` (Linux) / `~/Library/Python/3.x/bin` (macOS) to your PATH.\n\n**\"No sessions found under ~/.claude/projects\"**\nYou're on a machine (or user) that hasn't run Claude Code, or your store\nlives elsewhere — point `CLAUDE_HOME` at it. Inside a project folder the\ntool scopes to that project; pass `--any` to search everything.\n\n**It picked the wrong session**\n\"Latest\" skips nearly-empty stubs but is still just the newest file. Use\n`-i` (picker), `--name \"part of the title\"`, or `--grep \"something said\"`.\n\n**`--llm claude-cli` fails or asks to authenticate**\nRun `claude` once and log in (`/login`). It works even when invoked from\n*inside* a Claude Code session — inherited `CLAUDE*` env vars are scrubbed\nso the nested CLI authenticates like a fresh one.\n\n**`--llm claude-cli` fails with \"Credit balance is too low\"**\nAn `ANTHROPIC_API_KEY` exported in your shell was winning over your\nPro/Max login and billing an (empty) Console account. Since 0.18.0 the\nkey is scrubbed from the spawned CLI automatically — upgrade if you see\nthis on an older version, or `unset ANTHROPIC_API_KEY` for the run.\n\n**\"Set ANTHROPIC_API_KEY … to use --llm claude\"**\nAPI providers need a key in the environment — see the table above. No key\nat all? Use `--llm claude-cli` (subscription) or `--llm ollama` (local).\n\n**`--fit` refuses to combine with `--llm` / `--max-chars`**\n`--fit` sizes the deterministic output on its own. If you didn't type it,\nyour config file probably sets `fit` — override with an explicit\n`--max-chars` removed, or drop the key.\n\n**The brief injection warns \"sessions newer than this brief exist\"**\nThat's the freshness stamp doing its job: run\n`chf --brief --llm claude-cli` to re-distill (cached — only new sessions\nare paid for). The factual part refreshes itself if the SessionEnd hook is\ninstalled.\n\n**Something silently did nothing?**\nTolerant-by-design paths (corrupt JSONL lines, unreadable files, cache\ntrouble) never crash the run — add `--debug` (or `CLAUDE_HANDOFF_DEBUG=1`)\nto see exactly what was skipped and why. Hooks always report their\nerrors on stderr while still exiting 0.\n\n**Garbled characters on Windows**\nSet `PYTHONUTF8=1` (the CI runs the whole suite that way).\n\n## Full flag reference\n\n| Flag | Meaning |\n|---|---|\n| `--list` | list sessions (date, size, project, title · first prompt); with a `conversations.json`, list its chats |\n| `--name QUERY` | pick newest session (or web conversation) whose title/first prompt contains QUERY |\n| `--grep TEXT` | pick newest session whose *conversation* contains TEXT (repeat the flag to require ALL terms); with `--list`/`-i` shows every match with a 🔍 preview |\n| `--project NAME` | pick latest session whose project path contains NAME (repeatable — several projects together) |\n| `-i` / `--interactive` | pick session(s) from a numbered list — `1,3` or `2-4` merges several into one handoff |\n| `--any` | ignore the current directory; consider every project's sessions |\n| `--last N` / `--since 2h` | keep only the tail of the conversation (N user turns / a time window) |\n| `--merge` | merge every session in scope into ONE handoff (session-break markers, summed activity) |\n| `--brief` | distill the project's whole history into `~/.claude/briefs/<project>.md` (deterministic; `--llm` for real distillation) |\n| `--exclude ID` | with `--brief`: leave session(s) out of the memory — an id prefix (from `--list` or the brief's citations), comma-separate or repeat for several; **bare `--exclude` opens a numbered picker with the stored set pre-selected (✗) — numbers toggle, empty keeps, `none` clears**; sticky across refreshes, `--exclude none` clears |\n| `--keep SPEC` | with `--brief`: window the sessions that feed the memory — `20` / `last:20` (most recent), `first:2` (founding), `since:7d` (by last activity; ISO dates work too), or combinations like `first:2,since:30d`; sticky, so refreshes keep a **sliding window**; `--keep all` clears |\n| `--install-brief-hook` / `--uninstall-brief-hook` | project memory hooks: inject the brief at SessionStart, auto-refresh facts at SessionEnd |\n| `--install-hook` / `--uninstall-hook` | auto-write a handoff to `~/.claude/handoffs/` when each session ends |\n| `--install-skill` / `--uninstall-skill` | install the `/claude-handoff` Claude Code skill (SKILL.md under `~/.claude/skills/` + trigger section in `~/.claude/CLAUDE.md`) so Claude drives chf correctly — idempotent, hand-written sections respected, uninstall leaves the rest of CLAUDE.md untouched |\n| `--format md\\|json` | markdown (default) or machine-readable JSON — also applies to `--list` |\n| `-o FILE` / `-o -` / `-o clipboard` / `-o graphify` | output file / stdout / clipboard / graphify corpus (`raw/`, for the knowledge graph) (default `handoff.md`) |\n| `--fit TOKENS` | size the deterministic handoff to a token budget (`32k`, `128k`, `1m`) by tightening transcript truncation |\n| `--full` | verbatim conversation turns (classic transcript) instead of the default condensed digest |\n| `--max-chars N` | cap the transcript section (default 80 000; keeps start + recent end) |\n| `--include-tools` | collapsed `<details>` blocks with each tool call |\n| `--include-sidechains` | append full subagent transcripts (inline sidechains and `<session-id>/subagents/agent-*.jsonl`); their file/command activity is always counted |\n| `--llm claude\\|openai\\|gemini\\|claude-cli\\|ollama` | LLM summary instead of raw cleaned transcript |\n| `--model ID` | override the LLM model |\n| `--focus TEXT` | extra instructions for the summary (e.g. `--focus \"emphasize the API decisions\"`) |\n| `--with-transcript` | with `--llm`, also append the cleaned transcript |\n| `--anonymize` | strip identity for public sharing: home paths → `~`, emails/IPs/username → placeholders |\n| `--no-redact` | keep secret-looking strings (default: redacted from every output, LLM or not) |\n| `--no-cache` | disable the chunk-note cache (`~/.cache/claude-handoff`) |\n| `--mcp` | run as an MCP server over stdio |\n| `--allow-llm` | with `--mcp`: let the `handoff` tool run LLM summaries (explicit opt-in) |\n| `--completions bash\\|zsh` | print a tab-completion snippet |\n| `--debug` | report tolerated failures (corrupt lines, unreadable files) on stderr — nothing becomes fatal |\n\n## Roadmap\n\n- Gemini exports as input (Google Takeout ships HTML only — bring a real, redacted export to build against)\n- Session chains: auto-detect `/compact`-continued sessions and offer to merge the lineage (`--follow`)\n\nPRs welcome.\n\n## How it compares\n\nThis space isn't empty — it's fragmented. Pick the tool that matches your situation:\n\n- **Exporters** — [claude-conversation-extractor](https://github.com/ZeroSumQuant/claude-conversation-extractor), [claude-code-log](https://github.com/daaain/claude-code-log), [claude-code-transcripts](https://github.com/simonw/claude-code-transcripts), [claude-to-markdown](https://github.com/legoktm/claude-to-markdown) — turn transcripts into readable Markdown/HTML, tool noise included, no handoff framing.\n- **Cross-CLI session movers** — [cli-continues](https://github.com/yigitkonur/cli-continues) (`npm i -g continues`) reads 16 coding CLIs' native session stores (Claude Code included) and injects a context doc into another *terminal* tool. Excellent for Claude Code → Codex/Cursor/Gemini CLI; but it can't target web chats, does no LLM summarization, and needs Node 22.5+.\n- **In-session handoff skills/plugins** — [thepushkarp/handoff](https://github.com/thepushkarp/handoff), [claude-session-handoff](https://github.com/thenguyenvn90/claude-session-handoff), [claude-code-handoff](https://github.com/Sonovore/claude-code-handoff) — great *if* you remember to run them before the session ends; the model writes the summary using your session's context, and the output targets the next *Claude* session.\n- **Browser extensions** — Handoff, LLM Context Bridge, ContextSwitch — transfer *web* chats between ChatGPT/Claude/Gemini; they can't see Claude Code sessions.\n\n`claude-handoff` is the post-hoc, paste-anywhere corner of this map: it works on the JSONL *after* the fact — old sessions, crashed sessions, sessions that hit the usage limit — needs nothing installed in advance, costs zero tokens by default, can write a real summary when you ask for one (`--llm`), and produces a document any receiving model can pick up, including claude.ai, ChatGPT and Gemini in the browser or on your phone. And with `--brief`, it's the only one that turns that history into standing project memory.\n\n## Development\n\n```bash\ngit clone https://github.com/Vasilispapg/claude-handoff && cd claude-handoff\npython3 -m unittest discover -s tests -v      # the whole suite (no deps needed)\npython3 -m claude_handoff tests/fixtures/agent_session.jsonl -o -   # smoke run\npython3 scripts/build_single.py --check       # single-file build is fresh\nuvx ruff check claude_handoff scripts tests   # lint (config in pyproject)\n```\n\nRuntime code lives in the `claude_handoff/` package; `single/claude_handoff.py`\nis **generated** — rebuild it with `python3 scripts/build_single.py` after\nany package change (CI fails when it's stale). New parser behavior starts\nwith a redacted fixture in `tests/fixtures/` — see\n[CONTRIBUTING.md](CONTRIBUTING.md) and [AGENTS.md](AGENTS.md) (instructions\nand invariants for both human and AI contributors).\n\n## Learn more\n\n[docs/GUIDE.md](docs/GUIDE.md) — **a day with claude-handoff**: walkthrough, how `--brief` works step by step, honest cost table, cheatsheet · [INDEX.md](INDEX.md) — file map · [docs/DEVELOPMENT.md](docs/DEVELOPMENT.md) — architecture, JSONL schema notes, design decisions · [AGENTS.md](AGENTS.md) — contributor guide for AI coding agents · [CONTRIBUTING.md](CONTRIBUTING.md) · [CHANGELOG.md](CHANGELOG.md)\n\n## License\n\nMIT\n\n---\n\nmcp-name: io.github.Vasilispapg/claude-handoff\n",
  "bytes": 28468,
  "sha": "b0fdedf4a289bf1f8f36a37ff6df902d6b5d9352c060eeeafc1c33fbdb6a1900",
  "repo_slug": "vasilispapg/claude-handoff",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_vasilispapg_claude_handoff_edc524b1/readme"
}