Event Lifecycle
The hook sequence from session start through shutdown. Each event routes to the SubQ CLI via the command declared in hooks.json.
Hook Contracts
Each hook's command, timeout, matcher, status message, and behavior when SubQ is missing.
SESSION START
SessionStart
Command: bash -c 'command -v subq && subq hooks ... || printf fallback'
Timeout: 45,000ms
Matcher: startup|resume
Status: "SubQ: Indexing codebase..."
STOP
Stop
Command: subq hooks --provider claude --event stop
Timeout: 30,000ms
Matcher: "" (all)
Status: "SubQ: Session handoff..."
PRE COMPACT — DEFERRED
PreCompact
Command: subq hooks --provider claude --event pre_compact
Timeout: 120,000ms
Matcher: "" (all)
Status: "SubQ: Building structured handoff..."
STOP FAILURE
StopFailure
Command: subq hooks --provider claude --event stop_failure
Timeout: 10,000ms
Matcher: "" (all)
Status: (none)
Detection & Degradation
What happens at each hook event depending on whether SubQ is installed, missing, or encounters an error.
stdout Format
Hooks return JSON to stdout. Two shapes—inject context or no-op.
Known Issues
Active bugs and constraints in the hook system.
SessionEnd hook broken for plugins
Claude Code issue #33458: SessionEnd hooks don't fire from plugins. We use Stop instead.
Stop cooldown required
Stop fires per turn, not per session. A 3-minute per-session cooldown prevents excessive handoff generation.
Timeout budgets vary by event
SessionStart gets 45s for indexing; StopFailure gets only 10s (advisory only). PreCompact has the largest budget at 120s for structured handoff before lossy compaction.