SuperAPI AI Directory

handoff

Agents & models

View repository

Updated 10-16 01:33

About this skill

Handoff: end a session on a file, not on compaction

Applies to every codebase, and to a plain folder without git. _agent/ at the root is the one folder for everything an agent leaves behind in a repo: working notes in _agent/docs/, these step logs in _agent/handoff/. It is never committed.

Compaction keeps whatever the compactor decides and cannot be inspected. A handoff is a file the human can read, correct and diff, and a feature that spans several sessions becomes an auditable log of steps: step N's Next is step N+1's Done.

The user provided: $ARGUMENTS

  • to <agent> or --to <agent>, anywhere in the arguments, or a plain "hand off to Codex" - the agent that runs the next session. Strip it before reading the rest. Known agents are in Launch command per agent. Default: the agent you are (claude in Claude Code).
  • resume [TICKET-or-slug] - you are the fresh session. Go to Resuming. With no goal, infer it the same way as below.
  • <TICKET-or-slug> ["step description"] - you are the ending session. Go to Writing a step.
  • Nothing - writing mode. Infer the goal from the branch name. With no ticket in the branch, or no git at all, use a kebab-case slug of the goal (router-decomposition; the folder name is a fine default for a small project). If that is unclear, ask. Never invent a ticket number.
GOAL=$(git branch --show-current 2>/dev/null | grep -oE '[A-Z]{2,}-[0-9]+' | head -1)   # feature/PROJ-42-search-index -> PROJ-42

Where the log lives

<root>/_agent/handoff/<TICKET-or-slug>/
  01-<step-slug>.md
  02-<step-slug>.md
  ...
if COMMON=$(git rev-parse --path-format=absolute --git-common-dir 2>/dev/null); then
  ROOT=$(cd "$COMMON/.." && pwd)                                                                      # main checkout, also from a worktree
  DIR="$ROOT/_agent/handoff/$GOAL"; mkdir -p "$DIR"                                                   # creates _agent/ when missing
  grep -qx _agent "$ROOT/.git/info/exclude" 2>/dev/null || echo _agent >> "$ROOT/.git/info/exclude"   # appends only when missing
else
  ROOT=$PWD; DIR="$ROOT/_agent/handoff/$GOAL"; mkdir -p "$DIR"                                        # no git: plain folder, nothing to exclude
fi

--git-common-dir, not --show-toplevel: in a worktree --show-toplevel resolves to the worktree's own root, and since _agent/ is not in git the file would be deleted with the worktree. --git-common-dir points at the main checkout from anywhere, so every worktree writes into the same folder and the log outlives the worktree. A worktree's .git is a file, not a directory, so this also makes the exclude path correct.

If _agent/ is not present, create it and add it to .git/info/exclude - the lines above do exactly that and are no-ops when it already exists, so run them every time instead of checking first. .git/info/exclude is per clone and never committed, so no tracked file is touched and _agent/ never shows up in git status.

No git repository (a plain folder): ROOT is the folder itself, there is nothing to exclude, and _agent/ simply sits next to the work. The header says so instead of naming a branch.

  • One folder per goal. Step files are two digits, then a short kebab slug of what the step was about. Sorted ls is the reading order; the newest file is the truth.
  • No index, no README.md, even past four files. The sequence is the index.

When to run it

After green - the normal case, and the one to encourage. The best moment is right after a verified milestone and before the context window degrades: a summary written by a degraded session is a degraded summary. Ending a healthy session on a handoff costs one short file, and the fresh session starts sharp.

When the session is screwed - the emergency case: the apology loop ("You're absolutely right", the same mistake twice), or the window nearly full. Write the step anyway, mark Where we are as mostly Believed with one line saying why, and stop. Do not keep working once the file is written.

The human decides when. Nothing here triggers on context size.

Writing a step

  1. Read the newest existing step, if there is one: ls "$DIR" | sort | tail -1. Its Goal is copied verbatim; its Next is what your Done answers.
  2. Number and name the file.
 LAST=$(ls "$DIR" | grep -oE '^[0-9]+' | sort -n | tail -1)
 N=$(printf '%02d' $((10#${LAST:-0} + 1)))       # 10# so 08 and 09 are not read as octal
 FILE="$DIR/$N-<step-slug>.md"

The step slug is the description from the arguments, kebab-cased, or two to four words for what the step did (fix-duplicate-results). 3. Header. The H1, then one italic line with the date and the session log that produced the file, then one italic line with the branch and where the session ran:

 # PROJ-42 - step 02: fix the duplicate search results

 *Written 2026-09-12. Session log: `~/.claude/projects/<project-key>/<SESSION-ID>.jsonl` (`claude --resume <SESSION-ID>`)*
 *Branch `feature/PROJ-42-search-index`, main tree `/path/to/repo`*
 TOP=$(git rev-parse --show-toplevel 2>/dev/null)   # equal to $ROOT: "main tree"; otherwise "worktree" at $TOP
 git branch --show-current 2>/dev/null

Without git the second line is *No git repository. Plain folder /path/to/folder*.

Working notes line. When the worknotes skill keeps a subject folder for the same goal, add a third italic line pointing at its README:

 ls -d "$ROOT"/_agent/docs/"$GOAL"*/README.md 2>/dev/null    # e.g. _agent/docs/PROJ-42-search-duplicates/README.md
 *Working notes: `_agent/docs/PROJ-42-search-duplicates/README.md`*

No match, no line. Do not invent a folder.

Finding the session id (Claude Code). It is the UUID directory in the scratchpad path from the system prompt, /private/tmp/claude-<uid>/<project-key>/<SESSION-ID>/scratchpad. The same <project-key> (the absolute cwd with / replaced by -) is the log directory, so the log is ~/.claude/projects/<project-key>/<SESSION-ID>.jsonl. ls it before writing the line. With no scratchpad path in context, take the newest log for this repo and say in the file that it is inferred:

 ls -t ~/.claude/projects/"$(pwd | tr / -)"/*.jsonl | head -1

Why the id: months later the file is the only artifact left, and the reasoning behind every line in it lives in the transcript. Another agent writes its own resume line when it knows its session id (codex resume <id>, grok --resume <id>); without a known id it writes Session: none (<tool>) and leaves the resume line out rather than inventing one. 4. Five sections, always all five, in this order. Template with hints: references/step-template.md. Filled: references/example-step.md.

Section Rule
## Goal The distant goal, repeated verbatim in every step. Copy it from the previous step. Change it only if the human changed it, and say so in a line under it. It is the anchor against drift.
## Done What this step finished: file paths, commit hashes, MR links. Facts, not intentions.
## Where we are Current state, split into ### Verified (something was run or observed - say what: the test that passed, the count printed, the screenshot) and ### Believed (the session thinks so but did not check). The writer does not know what it does not know either; the split is the point.
## Next The first three moves for the fresh session, concrete enough to start without thinking. Then what must not be done, and why.
## Session Session id and claude --resume line, repeated from the header so it survives copy-paste. Then the commands the next session runs before trusting this file: git status, git log --oneline -5, the test command, whatever applies.
  1. Keep it short. A handoff is a map, not the transcript; the transcript is one --resume away. When a working-notes README exists, Where we are links it for findings instead of restating them: the README owns what is known, the step owns what happens next. An operational fact that cost time goes into Next as a "do not" line, or into the repo's own skill, not into a growing appendix.

  2. Spawn the fresh session, when this folder is an Orca worktree. Writing the file is not the end of the job - the point is that the next agent starts without the human relaying anything. This skill uses the orca CLI for that. First build the launch command for the target agent (Launch command per agent below), then two checks, both free, before the one command:

    • ORCA_TERMINAL_HANDLE is set in the environment. If not, this session is not running inside Orca. Go to step 7 with the manual fallback.
    • The command uses --worktree current, the worktree that contains the current directory. If it fails with selector_not_found, Orca does not manage this folder (a plain folder, or a repo opened outside Orca). Go to step 7. Do not retry, do not try other selectors, do not run orca open.
 orca terminal create --worktree current --title "<GOAL> resume (<agent>)" \
   --command "<launch command>" --json

Five rules, each of which has a failure mode behind it:

  • terminal create, never worktree create. A resumed handoff continues the same branch, so it belongs in the checkout you are already in. worktree create makes a whole new one. Orca's own help says it: "Use this, not worktree create, for a fresh agent in the current checkout."
  • --command, never --agent. --agent exists only on worktree create, and the launch command already names the agent. One launch path for every agent.
  • current, never active. active is whatever worktree Orca has focused, which may not be the one this session runs in. current is the one containing $PWD.
  • The prompt rides in --command, never through orca terminal send. send silently truncates and delivers only the tail while reporting success. Every agent in the table takes its prompt as an argument, so nothing can be cut.
  • No --focus. The new terminal appears without yanking the human out of what they are doing. They switch to it when they are ready.

Report the handle from result.terminal.handle in the JSON - not result.handle, which does not exist. Only if the error says Orca itself is not running: orca open --json and retry once. Any other failure goes to step 7. Never claim a session was spawned that the JSON did not confirm. 7. End with exactly these two lines, and nothing after them:

 Handoff written: <FILE>
 Fresh <agent> session spawned in <worktree>: <terminal handle>

When the spawn did not happen, the second line is instead a command the human can paste into any terminal:

 Fresh session: cd <ROOT> && <launch command>

Launch command per agent

<P> is the prompt. For claude it is the slash command. For every other agent it is a plain sentence with the absolute path of the step just written, because that agent may not have this skill installed, and a path works either way:

Resume the handoff for <GOAL>: read only <FILE>, run the checks in its Session section, then start on its Next.

One line, in single quotes, no single quote inside it (rephrase instead of escaping).

Agent Command
claude claude '/handoff resume <GOAL>'
codex codex '<P>'
grok grok '<P>'
gemini gemini -i '<P>'
opencode opencode --prompt '<P>'
cursor cursor-agent '<P>'
  • gemini needs -i: a bare positional prompt runs once and exits instead of staying open.
  • Check the binary with command -v <binary> before spawning. Missing: say so in one line above the two final lines and print the fallback command anyway, so it works once installed.
  • Any other agent: ask the user for its launch command. Do not guess flags.

Resuming

You are the fresh session. Do not read the whole folder; that is the context you were started to save.

  1. Resolve ROOT and GOAL as in Where the log lives, then ls "$ROOT/_agent/handoff/$GOAL" and open only the newest step. If the folder does not exist, ls "$ROOT/_agent/handoff/" and ask which goal; do not guess.
  2. If the header has a Working notes line, open that README too - it holds what is already known, including the conclusions that turned out wrong. Read it before re-deriving anything.
  3. Read Goal, then Next. Run the verify commands from Session before trusting Where we are. If the tree disagrees with the file (dirty git status, a commit that is not there), say so before doing anything else.
  4. Open older steps only when Next or Where we are points at them.
  5. Start work. When the next milestone is green, run /handoff again.