About setup-auto-handoff
setup-auto-handoff is a Claude Code skill that gates compaction until a recent handoff exists. It uses a PreCompact hook and explains the transcript-based fallback for OpenCode and Codex.
Key features
- 01Blocks compaction without a recent handoff
- 02Calls the hand-off skill
- 03Includes setup and verification steps
- 04Explains OpenCode and Codex fallback limits
Use cases
- 01Preserving context before Claude Code compaction
- 02Setting up and testing a PreCompact hook
- 03Handling handoffs in OpenCode or Codex
Install
Copy the command and run it in a terminal.
npx skills add https:/ / github.com/ dyrits/ skills --skill setup-auto-handoffAfter installing, type/setup-auto-handoffin Claude Code to confirm it loaded.
Bundled filesagents/openai.yamlscripts/precompact-handoff-gate.sh
Details
From the project READMESetup Auto-Handoff
Gates compaction: when Claude Code is about to compact (auto or manual), a PreCompact hook blocks it unless a handoff was written to .agents/handoffs/ in the last 5 minutes. The block reason tells the agent to run the hand-off skill first; the next compaction attempt passes once the handoff exists.
Calls: hand-off. If a called skill is not installed, tell the user its name and install command, npx skills@latest add Dyrits/SKILLS --skill=<name>, then carry out that step from its stated intent and report the step as done without the skill.
What works where
- Claude Code: fully supported (
PreCompacthook). This setup's main path. - OpenCode / Codex: no pre-compact hook exists. The fallback is their persisted transcripts (
codex resume, OpenCode session storage) plus the user's habit of runninghand-offat phase boundaries. Tell the user this plainly; do not fake coverage.
Steps
1. Copy the hook script
The bundled script is at scripts/precompact-handoff-gate.sh
Copy to .claude/hooks/precompact-handoff-gate.sh and make it executable (chmod +x).
The block message calls hand-off, which must be in your skill listing for the gate to resolve cleanly. When it is absent, recommend installing it first; the message's fallback (write the handoff file directly) still lets compaction proceed without it.
2. Register the hook
In .claude/settings.json (project scope; hooks cannot be scoped tighter), merge into the existing hooks object:
{
"hooks": {
"PreCompact": [
{
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/precompact-handoff-gate.sh"
}
]
}
]
}
}
Do not overwrite other hooks; merge the array.
3. Verify
-
.claude/hooks/precompact-handoff-gate.shexists and is executable -
.claude/settings.jsonparses (jq . .claude/settings.json) and carries thePreCompactentry - Simulate an auto-compact with no fresh handoff:
echo '{"trigger":"auto"}' | .claude/hooks/precompact-handoff-gate.sh; echo "exit: $?"
Expect a JSON decision: block on stdout and exit code 0.
- Simulate with a fresh handoff:
mkdir -p .agents/handoffs && touch .agents/handoffs/test.md
echo '{"trigger":"auto"}' | .claude/hooks/precompact-handoff-gate.sh; echo "exit: $?"
rm .agents/handoffs/test.md
Expect empty output, exit code 0.
4. Tell the user the loop
When the context limit hits: auto-compact fires, the hook blocks it with the instruction, the agent runs hand-off (a fresh file lands in .agents/handoffs/), compaction retries and passes. If compaction is ever truly unwanted, the user can remove the hook from .claude/settings.json. Manual /compact is gated the same way; /clear is not affected (it is a different event).
Notes
- The 5-minute freshness window stops a stale handoff from an hour ago satisfying the gate. Edit
FRESH_WINDOW_MINUTESin the script to tune. - The gate creates
.agents/handoffs/if missing, so the first blocked compaction is also the first handoff. - The hook needs
jqon PATH; check and tell the user if absent.