Polyhydra Skills  /  Agent Workflow

handoff

Split part of the current conversation into a durable handoff file and launch a fresh session seeded with it, so the old thread can close instead of dragging its context forward. Triggers on "handoff", "hand this off to a new thread", "close this thread and start fresh", "this thread is getting long". Also use when a new session is pointed at a handoff file, to orient before starting work.

Agent Workflow

Drop this in — save the block below as ~/.claude/skills/handoff/SKILL.md, or run:

mkdir -p ~/.claude/skills/handoff
cat > ~/.claude/skills/handoff/SKILL.md <<'EOF'
# (paste the full source block below into this file)
EOF

Full source

SKILL.md — copy everything inside
# Handoff

Move one piece of work out of a long-running conversation and into a fresh
session that inherits nothing but a file.

Two halves, and which one you're in is determined by where you were invoked:

- **write side** — invoked in the *old* thread. Extract the slice, write the
  file, print the launch command. The old thread can then be closed.
- **read side** — invoked in the *new* session, which was launched pointed at
  a handoff file. Verify the file is still true, then start work.

## Why not a subagent

The instinct is to reach for the Agent tool. Don't. A subagent does start
cold, but **its report comes back into the calling thread** — that grows the
context you're trying to shed, and the old thread still can't be closed.
Subagents are for fan-out. This skill is for handoff. They are not
substitutes.

The only thing that produces a genuinely disposable parent thread is a
separate `claude` process reading a file off disk.

---

# Write side

Invoked in the thread being split. **Only this thread can see its own
context**, so it has to be the author — a fresh session cannot come get it.

## Step 1 — establish the slice

The whole premise is that *part* of the thread moves and the rest stays. Get
that boundary explicit before writing anything.

If the user named the slice ("hand off the migration part"), use it. If they
said something open-ended ("hand this off"), and the thread has been working
on more than one thing, offer the candidate slices as `AskUserQuestion`
options — one option per coherent piece, plus "all of it, I'm closing this
thread entirely."

Do not guess when the thread has multiple live strands. Guessing wrong means
the new session works the wrong problem with confident-looking notes.

## Step 2 — gather real state, don't re-narrate

The handoff is a **state document, not a transcript summary**. Nobody needs
to know what was tried in what order. They need to know where things stand.

Pull live facts rather than trusting recollection of them:

```sh
git -C <repo> status --short --branch
git -C <repo> log --oneline -10
gh pr list --state open --head <branch>       # if the work has a PR
gh issue view <n>                             # if it's issue-backed
git -C <repo> worktree list                   # if work is isolated
```

Confirm the work is actually repo-backed before leaning on any of these —
`git rev-parse --is-inside-work-tree` — rather than assuming it. Config,
skills, and dotfile paths frequently are not (`~/.claude` is not a git repo),
and a handoff that implies a branch and a PR where none exist sends the next
session hunting for things that were never there. When there's no repo, note
what *is* true instead: the file paths, whether anything is backed up, and
how the change was verified.

Every claim in the file should be one someone can check. If a fact can't be
verified cheaply, mark it as an assumption rather than stating it flat.

## Step 3 — write the file

Location: `~/.claude/handoffs/<slug>-<YYYY-MM-DD>.md` (`mkdir -p` first).

That directory is deliberate. It is durable across sessions; it is *not*
under `~/.claude/jobs/*/tmp`, so `prune-jobs.py` will never delete it; and it
is outside every code repo, so a handoff never shows up as an uncommitted
file in `git status`. Do not write handoffs into the repo being worked on.

Use this schema. Keep it tight — a handoff that's longer than the work it
describes has defeated its own purpose.

```markdown
# Handoff: <one-line scope of the slice>

**Written:** <absolute date> · **From:** <what the old thread was doing>
**Where:** <the coordinates that actually exist — see below>

## The ask
<What this session is supposed to accomplish. Self-contained — written for
someone who never saw the original thread. No "continue what we discussed".>

## State right now
<Verified facts. Branch, dirty files, what's committed vs not, what's
deployed vs not, whether CI is green. Numbers, not impressions.>

## Decided — do not re-litigate
<Choices already made and closed, each with its one-line reason. This is the
highest-value section: without it the new session re-opens settled questions
and burns the context you were trying to save.>

## Ruled out — do not retry
<Approaches already attempted that failed, and how they failed. The single
most expensive thing to lose in a handoff, because a cold session will
otherwise walk straight back into them.>

## Next steps
1. <concrete, ordered, actionable>

## Done looks like
<The acceptance check. Ideally an exact command and its expected result.>

## Open questions
<Anything genuinely unresolved that the new session may need to ask about.
Empty is a good sign — if this is long, the slice may not be ready to hand
off.>
```

The two sections that justify the whole exercise are **Decided** and **Ruled
out**. A cold session with neither will cheerfully re-propose the approach
you rejected an hour ago. If you write nothing else well, write those.

### The "Where" line

List only coordinates that exist. Not every handoff is repo-backed — config,
skills, planning and triage threads often have no branch and no PR, and
padding those fields with `none` reads as missing information rather than as
a deliberate fact.

- **Repo-backed work** — path, branch, PR/issue links, and the worktree if
  the work is isolated:
  `**Where:** ~/code/<repo> · branch `<branch>` · PR #<n>`
- **Not version-controlled** — say so outright, because it's load-bearing:
  there is no branch to resume, no PR to check, and no backup if the file is
  deleted. Don't let a cold session infer a git workflow that isn't there.
  `**Where:** ~/.claude/skills/<name>/ — not version-controlled`
- **No filesystem home at all** (pure decision or research threads) — drop
  the line rather than inventing a location.

## Step 4 — hand back the launch command

Do not silently spawn the new session. Launching is the user's call — they
may want to finish something in the old thread first.

Scoping and launch mechanics (cwd-only scoping, hub-root-vs-repo, the
symlink trap, background vs interactive patterns) belong to the `projects`
skill — read `~/.claude/skills/projects/SKILL.md` § launch for those, not
restated here. What's specific to a handoff is the payload: point the new
session at the handoff file instead of an ad-hoc opening prompt.

Background (can be run directly; shell functions aren't available to the Bash
tool, so use full commands, and always label with `-n`):

```sh
cd ~/code/<repo> && claude --bg -n "<label>" --add-dir ~/projects/<hub> \
  "Read ~/.claude/handoffs/<file>.md and continue that work."
```

Interactive needs the user's own TTY — print it for them to run, preferring
their launcher shortcut (`pw <hub> <repo>`, `p <hub>`):

```sh
pw <hub> <repo>
# then: Read ~/.claude/handoffs/<file>.md and continue that work.
```

Close by telling them plainly that the old thread is now safe to close, and
name the file path so they can find it if they don't launch immediately.

---

# Read side

Invoked in a fresh session that was pointed at a handoff file.

1. **Read the file.** It is the scope. Don't widen it — the old thread kept
   the rest of the work deliberately.
2. **Verify before trusting.** A handoff is a snapshot of a moment that has
   since passed. Between writing and reading, CI may have finished, a PR may
   have merged, a branch may have moved. Re-run the cheap checks — `git
   status`, `gh pr view`, the acceptance command — and say plainly if reality
   has drifted from the file rather than proceeding on stale notes.
3. **Honor "Decided" and "Ruled out".** They exist to stop you re-deriving
   settled ground. If you think a decision was wrong, say so in one sentence
   and keep going under it — that's the user's call to reverse, not yours.
4. **Confirm the plan, then work.** Restate the ask and the first step in
   your own words so drift shows up immediately, then start.

If the file is missing, thin, or contradicts what's on disk, say so up front
rather than filling the gaps with plausible invention. A wrong handoff is
worse than no handoff, because it reads as authoritative.

---

## Ending a turn

Every handback here still ends in a picker — see CLAUDE.md's MAID section
for the rule, not restated here.

- **Write side** — launch background now / print the interactive command /
  adjust the slice / stop here.
- **Read side** — start on step 1 / re-verify drifted state first / adjust
  scope before starting.