development
/handoff and /pickup: An Ephemeral Handover Doc Instead of Yet Another Doc To Rot
TL;DR
Two artifacts from our AI-at-work practice, each one shared in its own way:
- Coherence (our product) — the methodical plan → spec → plan → code loop that keeps a codebase honest with AI in the room. Each layer is checked against the next, so drift gets caught before it ships.
/handoffand/pickup(open-source skills, MIT) — the subject of this post. A paired Claude Code skill that gives you a deliberate, ephemeral handover document when you/clearthe context window mid-task, so the next session can come in cold and pick up exactly where you left off.
We didn’t invent /handoff; Matt Pocock had it first. We added /pickup because a handoff with no matching pickup is just another doc that rots on the floor.
GitHub → · MIT-licensed, drop into
~/.claude/skills/, done.
The cognitive load of /clear
If you use Claude Code seriously you /clear a lot. You should. Long sessions stale out, the context window gets thick with stuff that was relevant three turns ago, prompt-cache hit rates collapse, and the model starts doing that thing where it half-remembers a decision you reversed twenty minutes back.
The Token Economics cheat sheet puts /clear discipline at the top of the list. Clearing context is one of the highest-leverage moves you can make.
But — and this is the bit nobody talks about — /clear has a cognitive cost the tooling doesn’t measure.
Right before you clear, you have a moment of what was I actually doing? You’ve got something half-finished. There’s a decision you made that isn’t written down anywhere. There’s a file you were about to edit. There’s a test that’s failing for a reason you understand but the next session won’t. The next session will be smart, but it will be cold, and you, the meatbag, are now responsible for getting the relevant context across the gap.
What everyone does, including me until recently, is some variant of:
- Open a scratch doc —
HANDOFF.md,NOTES.md,TODO-current.md,where-i-was.md. - Type in a panic.
/clear.- Paste the doc back in.
- Months later, find seventeen of these scattered through the repo, none of them current, all of them lying.
This is what I have started calling Yet Another Doc To Rot.md. The disease is well-known. The cure is usually worse than the disease, because the cure is “remember to delete it” and we don’t.
Where we found /handoff
Matt Pocock had already solved half of this. His Claude Code skills had a /handoff skill — a deliberate, structured prompt that asks Claude to write a handover document at a specific moment, in a specific shape, knowing it’s about to get blown away by /clear. We tried it. It works. It’s good.
The thing that’s good about it isn’t the format — it’s the moment. /handoff is a ritual. You’re saying I know I’m about to clear; help me write down the things future-me will need. The model writes a tighter, more useful handover than a panicked human would, because it has the whole session in working memory and it can see what mattered.
What was missing, for us, was the other half.
Why we added /pickup
A handoff implies a pickup. Otherwise it’s just a note.
We use Claude Code in pairs of sessions all the time. End-of-day session A writes; morning session B continues. Pre-/clear session writes; post-/clear session continues. One of us in London writes; one of us in another timezone picks up. The shape is always the same: the next session needs to read the handover, ask the right questions, and resume the work without re-deriving the context from scratch.
In practice, what was happening was that the receiving session would either:
- Read the handoff, do a perfunctory “ok, on it”, and then immediately start re-exploring the codebase as if the handoff didn’t exist; or
- Treat the handoff as gospel, miss the bit where the previous session was wrong about something, and confidently continue down a dead end.
Both are failure modes of an unritualised pickup. The handoff document is in the context, but there’s no skill telling the model here is how you receive a handover — confirm the goal, identify any stale assumptions, ask the user the smallest number of clarifying questions, then proceed.
So we added /pickup. Same author, same repo as /handoff, deliberately paired. Run /pickup and the model:
- Reads the handover doc as the source of truth for intent, not current state.
- Re-checks current state from the working tree — branch, dirty files, test status.
- Reconciles the two and tells you, in one short paragraph, what it thinks it’s about to do.
- Asks for confirmation before it touches anything.
Steps 2 and 3 are the bit that makes the difference. The handoff document is a snapshot of intent at the moment of clear. The repo state has moved on. A good pickup is the diff between the two.
Why the doc is ephemeral, on purpose
Here is the design choice that matters most. The handover doc that /handoff produces is not checked in. It is written to /tmp with a timestamp-and-PID filename, and a single pointer file at ~/.claude/handoffs/latest records the most recent one for /pickup to find. The next /handoff writes a new file in /tmp and overwrites the pointer. The OS clears /tmp on reboot. Nothing about this artifact wants to live forever.
This is the bit that distinguishes a /handoff-/pickup pair from Yet Another Doc To Rot.
A normal project doc has to stay current forever. That is a colossal maintenance tax, and it is the reason most project docs are wrong by the second week. An ephemeral handover doc has one job: be correct at the moment it is produced, for the single consumer that is about to read it. Then it dies.
That framing eliminates the rot problem at the source. The doc is not pretending to be a persistent description of the project. It is a baton in a relay. A baton is useful for exactly the half-second it takes to pass; nobody expects a baton to remain accurate over the long run.
We’ve come to think of this as a small instance of intent coherence. The persistent layer of the project — the spec, the plan, the code — is what stays. The handover doc is a transient inference about where intent currently sits in that persistent layer, generated for one consumer, consumed once, discarded. Putting it in version control would be a category error: it would invite the doc to be treated as a layer it isn’t, and then it would rot in the way every persistent doc eventually rots.
This is also why we like that it’s two skills, not one. /handoff writes the baton. /pickup consumes it. The lifecycle is closed. You can’t accidentally treat the artifact as long-lived because there is a skill whose job is to consume and supersede it.
Why this fits how we already work
Coherence is the bigger picture this slots into. The Coherence method is a boring, methodical loop — plan → spec → plan → code — where each layer is deliberately checked against the next, so drift gets caught before it ships rather than discovered three weeks later in production. Those four artifacts, in that cycle, are the persistent backbone of a project. Everything else is derived.
A handover doc is a textbook everything else: generated from session state, consumed once, rebuilt next time. It doesn’t belong anywhere near the plan/spec layer, and it doesn’t need to be authored, maintained, or audited. /handoff and /pickup are the ephemeral ritual that lets the persistent Coherence loop carry on across /clear boundaries without smuggling session-state into a doc that pretends to be a spec.
If you’ve already bought the Coherence argument that the artifacts worth keeping are the ones you check against each other, the don’t persist what you can regenerate argument from /handoff-/pickup is the same argument scaled down to a single ritual.
How to try it
git clone https://github.com/viewyonder/claude-skills ~/code/claude-skills
mkdir -p ~/.claude/skills
cp -r ~/code/claude-skills/skills/handoff ~/.claude/skills/
cp -r ~/code/claude-skills/skills/pickup ~/.claude/skills/
Then in a Claude Code session:
/handoff # right before you /clear, or hand off to a teammate
/clear # or just close the session
/pickup # in the next session, before doing anything else
The two skills are short. Here they are in full — read them before you install them.
skills/handoff/SKILL.md
---
name: handoff
description: Compact the current conversation into a handoff document for another agent to pick up.
argument-hint: "What will the next session be used for?"
---
Write a handoff document summarising the current conversation so a fresh agent can continue the work.
1. Generate the handoff path with `HANDOFF="/tmp/handoff-$(date +%s)-$$.md" && touch "$HANDOFF" && echo "$HANDOFF"`. Use the printed path in the steps below. (BSD `mktemp` on macOS can't substitute `X`s when the template has a trailing suffix like `.md`, so a manual timestamp+PID path is more portable.)
2. Read the file before you write to it (it will be empty, but this satisfies the Write tool's "read before write" invariant for existing files).
3. Write the handoff content to that path.
4. Update the pointer file so `/pickup` can find this handoff: `mkdir -p ~/.claude/handoffs && echo "<path>" > ~/.claude/handoffs/latest` (substituting the actual handoff path).
5. Print the handoff path to the user so they have it if they want to pass it explicitly.
Suggest the skills to be used, if any, by the next session.
Do not duplicate content already captured in other artifacts (PRDs, plans, ADRs, issues, commits, diffs). Reference them by path or URL instead. The handoff doc is the *delta* — the conversational state and decisions that exist nowhere else.
If the user passed arguments, treat them as a description of what the next session will focus on and tailor the doc accordingly.
A note on step 1, since it’s the bit most likely to bite you: an earlier version used mktemp -t handoff.XXXXXX.md, which works on Linux’s GNU mktemp but quietly breaks on macOS’s BSD mktemp because BSD won’t substitute the Xs when the template has a trailing suffix. The current date +%s + $$ pattern is portable across both. Small thing, but it’s the kind of small thing that turns a clean ritual into a “why isn’t this working” detour.
skills/pickup/SKILL.md
---
name: pickup
description: Resume work from a /handoff document. Uses the most recent handoff by default, or an explicit path if provided.
argument-hint: "[optional path to a specific handoff file]"
---
Resume work from a previous session's handoff document.
## Locating the handoff
If the user passed an argument, treat it as the explicit path to a handoff file and read that file directly.
If no argument was passed:
1. Read the pointer file at `~/.claude/handoffs/latest` to get the path of the most recent handoff.
2. If the pointer file doesn't exist, tell the user no recent handoff was found and ask whether they want to pass an explicit path.
3. If the pointer file exists but the path it points to no longer exists (e.g. `/tmp` was cleared on reboot), tell the user the handoff has expired and ask how they want to proceed.
## Using the handoff
Read the handoff document and treat its contents as the starting context for this session. Then, before acting on any of it:
- Verify referenced paths, files, URLs, and issue numbers still resolve.
- Check whether work described as "pending" or "next" has already been completed since the handoff was written (e.g. commits landed, issues closed, branches merged).
- Note any drift between the handoff snapshot and current reality, and surface it to the user.
The handoff is a *starting hypothesis*, not gospel. The underlying repo, issues, commits, and docs it references are the source of truth — let reality override the snapshot where they disagree.
## Confirm before continuing
Once you've read the handoff and verified its references, give the user a short summary of:
- What the previous session was working on
- What state things were left in
- What the suggested next steps are (per the handoff)
- Any drift you noticed between the handoff and current reality
Then ask whether to proceed with the suggested next steps or take a different direction.
The line in /pickup that does the most work is the one that says the handoff is a starting hypothesis, not gospel. That’s what stops the receiving session from confidently continuing down a dead end on stale assumptions — it has explicit permission to overrule the baton when reality has moved on. The handoff describes intent at a moment; the repo describes state right now. The pickup is where those two get reconciled.
We tweaked the language away from Matt’s original a little to fit our voice, but the bones are his. Credit where credit is due.
What we’re still figuring out
A few open questions we’re sitting with. If you try this and have opinions, tell me.
- How long should the handover doc be? Currently uncapped. Probably should be capped. A 2,000-word handover defeats the purpose — the next session has to read it all, which costs tokens, which is exactly what we were trying to save.
- Should
/pickuprequire a handover, or fall back gracefully if there isn’t one? Currently it errors out. There’s a case for it just doing a normal session start if no baton is present. - Per-project vs. global state. The doc lives at a fixed path. If you work on multiple projects in parallel, you want one baton per project. Easy to fix; haven’t fixed it yet.
- Multi-session relays. What if three sessions are running in parallel against the same project? The baton metaphor breaks down. We don’t have a good answer here yet.
Closing
The lesson, if there is one, is that ephemeral is a design choice, not a failure mode. Most of the docs in your repo are pretending to be persistent and quietly rotting. A handover doc that knows it’s a baton — written for one consumer, read once, then dropped — sidesteps the rot problem entirely.
Matt got the first half right. We added the second half. The pair is small, MIT, and on GitHub. Try it. Tell us where it’s wrong.