


Session Handoff
Compresses a long working session into a structured handoff a fresh session can continue from.
What it does
Long working sessions build up a lot of understanding that lives nowhere except the conversation. Then the session ends, or gets too long to keep, and the next one starts by re-reading everything, re-asking settled questions, and walking back into the same dead ends.
With this skill active, the assistant writes a short document aimed at a reader who was not there. It states the goal and exactly how much is finished, attaches evidence to anything it calls done, records each decision alongside the reason behind it, names one concrete next action, and lists what was already tried and failed so nobody repeats it.
You get a page you can hand to a new session, a colleague, or yourself next week, and start working from within a couple of minutes.
When to reach for it
Use it when a session is getting long, at the end of a work block on something multi-step, or when you are passing work to another person. It is also the right move before a break long enough that you will have forgotten the details.
Not needed for short, self-contained tasks - if the work finished and the result speaks for itself, a handoff is paperwork with no reader.
What's inside
session-handoff/
├── SKILL.md
└── references/
└── examples.md
--- name: session-handoff description: Compresses a long working session into a short handoff document a cold reader can continue from - goal and status, decisions with the reasoning that produced them, the exact next action, the dead ends already ruled out, and the commands that verify the current state. Use before context runs out, at the end of a work block, or when passing work to another session or person. --- # Session Handoff You are writing for someone with no memory of this session, who will start work in ten minutes. Everything they need is in the document; everything else is noise. ## Workflow 1. **Walk back through the session** and separate what was learned from what was merely said. 2. **State the goal in one sentence** and how much of it is done. 3. **Split the work into done, in progress, and not started**, with evidence for anything you claim is done. 4. **Record each decision with its reason.** A decision without its reason gets reversed by the next reader. 5. **Write the single next action**, concrete enough to begin without a decision. 6. **List the dead ends** - what was tried, what happened, why it was abandoned. 7. **Give the verification commands** and what a healthy result looks like. 8. **Collect the pointers**: branch, files with full paths, services, credentials location (never the credentials). ```text Handoff checklist [ ] Goal in one sentence [ ] Status split into done / in progress / not started [ ] Every "done" has evidence attached [ ] Every decision has its reason [ ] Next action is specific enough to start immediately [ ] Dead ends recorded with what happened [ ] Verification commands included, with expected output [ ] File paths absolute, branch named, no secrets ``` ## What to capture **The goal and how far it got.** Not the history of how it got there. **Decisions and their reasons.** "We stream the export rather than building it in memory, because a large tenant's report is around 900MB." Without the second half, the next session rewrites it as a simple in-memory build and rediscovers the limit in production. **The real state of the code.** Which branch, which files, what works, what is half-written and will not compile, what is stubbed. **The next action.** One thing, specific. "Wire the date-range picker in `reports.js:142` to the `from`/`to` query parameters the endpoint already accepts" - not "continue the filter work". **Dead ends.** Everything tried that failed, and what the failure looked like. This is the section that saves the most time and is the first one people leave out. **How to verify.** The commands that prove the state is what you say it is, and what output means healthy. **Pointers.** Branch, absolute file paths, service URLs, ticket numbers, where credentials live. ## What to leave out - The chronological story of the session. The reader wants the current state, not the journey. - Anything already obvious from the code or the commit history. - Options considered and rejected early, unless someone is likely to propose them again. - Praise, apology, and the phrase "as discussed" - there is no shared discussion with a cold reader. - Secrets, tokens, keys, connection strings with passwords in them. Say where they live instead. ## Document template ```markdown # Handoff: <topic> - <date> **Goal.** One sentence. **Status.** <n> of <m> done. One line on where things stand. ## Done - <thing> - evidence: <test, command output, or observed behaviour> ## In progress - <thing> - exact current state, including anything that will not compile or run ## Decisions - <decision> - because <reason> ## Next action <One concrete step, with the file and line if it has one.> ## Watch out - <dead end> - tried <what>, got <result>, abandoned because <reason> ## How to verify - `<command>` - expect: <what a healthy result looks like> ## Pointers - Branch: <name> - Files: <absolute paths> - Services / URLs / tickets: <list> - Credentials: <where they live, never the values> ``` ## Example A compressed version of a real handoff, showing the density to aim for: > **Goal.** Add CSV export to the reports page. > > **Status.** Backend done and tested; the date-range filter is not wired up. > > **Done.** `GET /api/reports/export` streams CSV - `pytest tests/api/test_export.py` > passes, 6 tests, including a 200k-row streaming case. > > **In progress.** The export button posts the current filters, but `reports.js` > sends `range: "last30"` while the endpoint expects `from` and `to` dates. The > request 400s. > > **Decisions.** Stream row by row rather than building the file in memory, > because the largest tenant's yearly report is roughly 900MB. > > **Next action.** In `reports.js:142`, convert the range selector value into > `from`/`to` ISO dates before the request. `dateRangeToBounds()` in > `utils/dates.js` already does this for the chart. > > **Watch out.** Tried returning the CSV as a single response body first; the > worker was killed at 512MB on the tenant above. Do not go back to that shape. > Also: the test database has three rows, so streaming is untested against real > volume anywhere but staging. > > **How to verify.** `pytest tests/api/test_export.py -q` expects 6 passed. Then > open `/reports`, pick any range, click Export - a file downloads today only if > you set the dates by hand in the network tab. Every line either tells the reader the state, stops them repeating a mistake, or tells them exactly where to type next. ## Rules - Write for a reader with zero memory of this session. No "as discussed", no "the file we changed", no "that bug". - Record why, not just what. An unexplained decision has a short life. - Be specific: absolute paths, exact commands, branch names, line numbers where they help. - Include what failed. A hidden dead end is a dead end the next session walks into. - Attach evidence to every claim of "done". "Tests pass" with the command beats "should be working". - Keep it scannable. A wall of prose is a handoff nobody reads. - No secrets in the document. Name the vault, the environment file, or the person to ask. - Prefer honest incompleteness. "I do not know why the staging build fails" is more useful than a guess presented as fact. ## Edge cases - **The session achieved nothing.** Say so, and record what was ruled out. A session that eliminated three theories has real value if the theories are written down. - **Handing to a person, not a session.** Add the context a colleague needs and a machine does not: who asked for this, what they are expecting, when, and who to ask about the ambiguous part. - **The work is blocked.** Lead with the blocker, name who or what unblocks it, and describe what can be done in the meantime. - **Half-written code that does not compile.** Say exactly which file and what state it is in. The next reader must not discover this by running the build. - **You are close to the end of context.** Write the handoff before you finish the last task, not after. An unwritten handoff is worth nothing. - **A decision was the user's, not yours.** Mark it as theirs. The next session should not reverse it unilaterally. - **Multiple threads of work.** One handoff per thread if they are truly independent. If they interact, write one document and say how they touch. ## Files - `references/examples.md` - two complete handoff documents at full length, one mid-feature and one for a paused investigation, plus a weak handoff rewritten line by line into a strong one. Read it to calibrate how much detail each section needs.
Install it
Unzip the download into .claude/skills/. The folder is already named right.
Unzip into ~/.claude/skills/ to use it everywhere.
Upload the zip under Settings, then Capabilities, then Skills (paid plans).
How to call it
Just describe the task. The description line inside the skill does the matching. Or call it directly:
/session-handoff
write a handoff for this sessionwe are running low on context, capture where we arewhat should the next session know?pause here and write up the statehand this over to someone else
Works beyond Claude
Skills use the open Agent Skills format. The exact same folder works in OpenAI Codex, Gemini CLI, Cursor, GitHub Copilot and other tools that read the format.
Using a plain chat app? Paste SKILL.md into ChatGPT or Gemini as instructions. You lose auto-triggering, but the method still works.
agentskills.io