---
name: apt:handoff
description: "Agent-to-agent handoff — compact current conversation into a HANDOFF artifact in the repo for a fresh agent to pick up"
apt-skill-version: {{APT_VERSION}}
stage: pause
intent: capture
when_to_use: "An agent (not a human) needs to transfer in-flight work to a different agent — different model, different CLI, a fan-out peer, or a fresh context window. Writes a HANDOFF artifact under .aperant/ so the receiver picks up exactly where the sender left off. NOT for human end-of-day stops (use /apt:pause) and NOT for harness auto-compact (the query loop handles that itself)."
user_invocable: true
internal: false
spawns_agent: false
agent_name: null
task_context: none
default_execution_mode: auto
execution_modes:
  - auto
  - step
allowed-tools: "Bash, Read, Write"
argument-hint: "apt:handoff [what the next session will focus on]"
gates: []
---
<objective>
Compact the current conversation into a HANDOFF document so a different agent — different model, different CLI, fan-out peer, or fresh context window — can pick up the work without re-discovering everything you already know.

Writes the handoff to `.aperant/handoffs/{id}/HANDOFF.md` (or `{task_dir}/handoffs/{id}/HANDOFF.md` when inside a routed task) so the artifact lives with the repo, survives across machines, and is discoverable by `/apt:resume` and team-status tooling.

**Use when:** an agent decides to transfer the work mid-flight. Examples — sender hit context-budget cap, the next phase needs a different model (e.g. Codex for a heavy refactor), a fan-out conductor is sharding scope to peers, or a planning agent is handing a locked plan to an executor.

**Do NOT use when:**
- The human operator wants to stop — use `/apt:pause` (it stashes uncommitted work and updates `CONTINUE_INDEX.md`).
- The harness is about to auto-compact — the query loop handles that itself; agents executing plans must checkpoint to `build-progress.json` instead.
- A new task is starting fresh — use `/apt` (router) or `/apt:plan`.
</objective>

<your_environment>
- **Working directory:** The project root (or current task worktree if `state.active_tasks[taskId].worktree_path` is set)
- **apt-tools path:** `node packages/framework/bin/apt-tools.mjs` or the locally installed `apt-tools` binary
- **Constitution:** Read `AGENTS.md` in the project root if it exists
- **Handoff index:** `.aperant/HANDOFFS_INDEX.md`
- **Sibling skills:** `/apt:pause` (human stop), `/apt:resume` (restore from CONTINUE *or* HANDOFF), `/apt:fan-out` (parallel peers)
</your_environment>

<state_files>
## State Files

**Reads:**
- `AGENTS.md` — Project constitution
- Active Aperant artifacts for the current task, if any:
  - `{task_dir}/spec.md`, `{task_dir}/implementation_plan.json`, `{task_dir}/build-progress.json`
  - `{task_dir}/qa_signoff.json`, `{task_dir}/review.json`
  - `.aperant/debug/*/DEBUG.md`, `.aperant/quick/*/TASK.md`
- Git state (branch, uncommitted changes, recent commits)
- `.aperant/state.json` — active tasks, worktree paths

**Writes:**
- `{task_dir}/handoffs/{handoff-id}/HANDOFF.md` — if inside a routed task
- `.aperant/handoffs/{handoff-id}/HANDOFF.md` — if ad-hoc work outside any task
- `.aperant/HANDOFFS_INDEX.md` — index of all open handoffs

**Does NOT touch:**
- The git working tree. Handoffs are read-only against code. If there are uncommitted changes the sender intends the receiver to keep working on, reference them in the HANDOFF (path + status from `git status --short`) — do NOT stash. Stashing is `/apt:pause` semantics, not `/apt:handoff`.
</state_files>

<process>

## 1. Determine Handoff Location

Generate a handoff id: `handoff-{YYYYMMDD-HHMM}-{short-slug-of-next-focus}` (e.g. `handoff-20260522-1430-finish-mcp-token-rotation`).

**If inside a routed task** (task_dir is known from the conversation, or `state.json` has an active task for the current branch):
- Write to `{task_dir}/handoffs/{handoff-id}/HANDOFF.md`

**If ad-hoc work** (manual coding, not routed through /apt):
- Write to `.aperant/handoffs/{handoff-id}/HANDOFF.md`

```bash
mkdir -p {handoff_dir}
```

## 2. Gather Current State

### 2a. Git State
```bash
git branch --show-current
git status --short
git log --oneline -5
git stash list
```

### 2b. Active Aperant Artifacts
Check and read status of any of: `implementation_plan.json`, `build-progress.json`, `qa_signoff.json`, `review.json`, `.aperant/debug/*/DEBUG.md`.

### 2c. Conversation Context
From the current conversation, extract:
- What task was being worked on and the user's framing of why
- Key decisions made + rationale (especially decisions NOT obvious from the diff)
- What was tried, what worked, what failed and why
- Live blockers and open questions
- Any external state the receiver must check (running processes, deployed previews, CI runs, MCP server sessions)

## 3. Write HANDOFF.md

Create `{handoff_dir}/HANDOFF.md`:

```markdown
# Handoff: {one-line summary of what the next agent should focus on}

## Session Info
- **Date:** {ISO datetime}
- **Sender:** {model + CLI, e.g. "Claude Opus 4.7 / Claude Code"}
- **Suggested receiver:** {model + CLI hint, or "any agent"}
- **Branch:** {current branch}
- **Worktree:** {worktree_path if task-isolated, else repo root}
- **Last commit:** {hash} — {message}
- **Task ID:** {task-id, if routed task; else "ad-hoc"}

## Focus For The Receiver
{The single most important paragraph — what is the receiver supposed to DO next, in concrete terms. If the user passed args to /apt:handoff, that text drives this section.}

## What Was Being Done
{Plain-language description of the current activity and how it fits the broader task.}

## Decisions Made (do NOT relitigate)
- {decision 1} — {rationale}
- {decision 2} — {rationale}

## Existing Artifacts (read these, do not duplicate)
- `{path or URL}` — {what it contains, why it matters}
- `{path or URL}` — {what it contains, why it matters}

> Reference paths and URLs instead of pasting content. PRDs, plans, ADRs, issues, commits, diffs, /apt:debug DEBUG.md, /apt:design DESIGN.md — link, don't copy.

## Current State
- **Pipeline stage:** {plan | execute | verify | review | debug | design | quick | none}
- **Subtask progress:** {n}/{total} (if applicable, with the in-flight subtask id)
- **Uncommitted changes:** {yes/no — list files, do not stash}
- **External state the receiver must check:** {running dev servers, open PRs, MCP sessions, etc.}

## Blockers
- {blocker 1 — what's needed to unblock, and which file/person/check resolves it}
- (none)

## What Was Tried
- {approach 1} — {outcome}
- {approach 2} — {outcome}

## Next Steps (ordered)
1. {immediate next action}
2. {following action}
3. {…}

## Suggested Skills
Tell the receiver which Aperant skills are likely to fire next. Map verbs to the live `/apt:*` registry — do NOT invent skill names.

- `/apt:resume` — first thing the receiver should run to load this handoff into context.
- `/apt:execute` — if a plan exists and subtasks remain.
- `/apt:debug` — if the open blocker is a reproducible bug without a known cause.
- `/apt:spar` — if the next decision wants a second-LLM challenge before committing.
- `/apt:plan` — if scope changed and the existing plan is stale.
- (omit any that don't apply)

## Redaction Checklist
Before saving, scrub the HANDOFF for:
- [ ] API keys, bearer tokens, OAuth secrets (Anthropic, Stripe, Convex, GitHub, etc.)
- [ ] Database connection strings with passwords
- [ ] Personally identifiable information not already in the repo
- [ ] Internal URLs that should not leave the team
```

## 4. Update Handoff Index

Update `.aperant/HANDOFFS_INDEX.md`. Create with this header if it does not exist:
```markdown
# Open Handoffs

| Focus | Branch | Date | Suggested receiver | Location |
|-------|--------|------|--------------------|----------|
```

Append one row:
```
| {focus (truncated to 60 chars)} | {branch} | {YYYY-MM-DD HH:MM} | {model hint or "any"} | {relative path to HANDOFF.md} |
```

If a row already exists for this handoff path, update it instead of appending.

## 5. Report

```
Handoff written: {handoff_dir}/HANDOFF.md

Summary:
  Focus: {one-line}
  Branch: {branch}
  Pipeline stage: {stage}
  Suggested next skill: {/apt:resume → /apt:{stage}}
  Open handoffs: {total count from index}

Receiver picks up with:
  /apt:resume                # discovers this handoff via HANDOFFS_INDEX.md
  OR read {handoff_dir}/HANDOFF.md directly
```

</process>

<notes>
## Why this skill exists separately from /apt:pause

`/apt:pause` and `/apt:handoff` write the same shape of artifact but have different triggers and side effects:

| | `/apt:pause` | `/apt:handoff` |
|---|---|---|
| Trigger | Human types it | Agent decides mid-work |
| Audience | Future-you (same human) | A different agent |
| Uncommitted work | Stashes via `git stash` | Does NOT stash — references in-place |
| Index file | `.aperant/CONTINUE_INDEX.md` | `.aperant/HANDOFFS_INDEX.md` |
| Artifact name | `CONTINUE.md` | `HANDOFF.md` |
| Typical follow-up | Human runs `/apt:resume` hours/days later | Receiver agent runs `/apt:resume` immediately |

Keeping the index files separate lets `/apt:resume` distinguish "the human stopped here" from "another agent dropped this in your lap" when presenting recovery options.

## Receiver contract

The receiver is expected to:
1. Run `/apt:resume` (or read HANDOFF.md directly).
2. Load the referenced artifacts (paths under "Existing Artifacts").
3. Verify the listed external state still holds (e.g. dev server still running, PR still open).
4. Delete the HANDOFF.md and its index row after picking up. `/apt:resume` handles the cleanup automatically; manual readers should do it themselves to keep `HANDOFFS_INDEX.md` from drifting.
</notes>
