description = """ Boot triage cycle - the daemon's watchdog for Deacon health. Boot is spawned fresh on each daemon tick to decide whether to start/wake/nudge/interrupt the Deacon, or do nothing. This centralizes the "when to wake" decision in an agent that can reason about context rather than relying on mechanical thresholds. Boot lifecycle: 1. Observe (wisps, mail, git state, tmux panes) 2. Decide (start/wake/nudge/interrupt/nothing) 3. Act 4. Clean inbox (discard stale handoffs) 5. Exit (or handoff in non-degraded mode) Boot is always fresh - no persistent state between invocations. Handoff mail provides continuity for the next Boot instance. """ formula = "mol-boot-triage" version = 1 [[steps]] id = "observe" title = "Observe system state" description = """ Observe the current system state to inform triage decisions. **Step 1: Check Deacon state** ```bash # Is Deacon session alive? tmux has-session -t hq-deacon 2>/dev/null && echo "alive" || echo "dead" # If alive, what's the pane output showing? gt peek deacon --lines 20 ``` **Step 2: Check agent bead state** ```bash bd show hq-deacon 2>/dev/null # Look for: # - state: running/working/idle # - last_activity: when was last update? ``` **Step 3: Check recent activity** ```bash # Recent feed events gt feed --since 10m --plain | head -20 # Recent wisps (operational state) ls -lt $GT_ROOT/.beads-wisp/*.wisp.json 2>/dev/null | head -5 ``` **Step 4: Check Deacon mail** ```bash # Does Deacon have unread mail? gt mail inbox deacon 2>/dev/null | head -10 ``` Record observations for the decide step: - deacon_alive: true/false - pane_activity: active/idle/stuck - last_activity_age: duration since last activity - pending_mail: count of unread messages - error_signals: any errors observed """ [[steps]] id = "decide" title = "Decide on action" needs = ["observe"] description = """ Analyze observations and decide what action to take. **Decision Matrix** | Deacon State | Pane Activity | Action | |--------------|---------------|--------| | Dead session | N/A | START | | Alive, active output | N/A | NOTHING | | Alive, idle < 5 min | N/A | NOTHING | | Alive, idle 5-15 min | No mail | NOTHING | | Alive, idle 5-15 min | Has mail | NUDGE | | Alive, idle > 15 min | Any | WAKE | | Alive, stuck (errors) | Any | INTERRUPT | **Judgment Guidance** Agents may take several minutes on legitimate work. Ten minutes or more in edge cases. Don't be too aggressive - false positives are disruptive. Signs of stuck: - Same error repeated in pane - Tool prompt waiting indefinitely - Silence with pending mail - Agent reporting issues but not progressing Signs of working: - Tool calls in progress - File reads/writes happening - Recent commits or beads updates **Output**: Record decision as one of: - NOTHING: Let Deacon continue - NUDGE: Gentle wake signal (gt nudge) - WAKE: Stronger wake (escape + message) - INTERRUPT: Force restart needed - START: Session is dead, start fresh """ [[steps]] id = "act" title = "Execute decided action" needs = ["decide"] description = """ Execute the action decided in the previous step. **NOTHING** No action needed. Log observation and exit. **NUDGE** ```bash gt nudge deacon "Boot check-in: you have pending work" ``` **WAKE** ```bash # Send escape to break any tool waiting tmux send-keys -t hq-deacon Escape # Brief pause sleep 1 # Send wake message gt nudge deacon "Boot wake: please check your inbox and pending work" ``` **INTERRUPT** ```bash # This is more aggressive - signals Deacon to restart gt mail send deacon -s "INTERRUPT: Boot detected stuck state" \ -m "Boot observed stuck state. Please check your context and consider handoff. Observations: - If you're making progress, please update your agent bead to reflect activity." ``` **START** ```bash # Deacon is dead - daemon will restart it # Just log that we detected this echo "Boot detected dead Deacon session - daemon will restart" ``` Record action taken for status update. """ [[steps]] id = "cleanup" title = "Clean stale handoffs" needs = ["act"] description = """ Clean up stale handoff messages from Deacon's inbox. Handoff messages older than 1 hour are likely stale - the intended recipient either processed them or crashed before seeing them. **Step 1: List Deacon inbox** ```bash gt mail inbox deacon --json 2>/dev/null ``` **Step 2: Archive stale handoffs** For each message: - Check if subject contains "HANDOFF" or "handoff" - Check if age > 1 hour - If both: archive it ```bash # For each stale handoff: gt mail archive ``` **Step 3: Archive Boot's own old mail** Boot doesn't need persistent inbox. Archive anything processed: ```bash gt mail inbox boot --json 2>/dev/null # Archive any messages older than current session ``` Keep the system clean - old handoffs just add noise. """ [[steps]] id = "exit" title = "Exit or handoff" needs = ["cleanup"] description = """ Complete this Boot cycle. **In degraded mode (GT_DEGRADED=true)** Exit directly - no handoff needed: ```bash # Log completion echo "Boot triage complete: " exit 0 ``` **In normal mode** Write brief handoff for next Boot instance: ```bash gt mail send boot -s "Boot handoff" -m "Completed triage cycle. Action: Observations: Time: $(date)" ``` Then exit. The next daemon tick will spawn a fresh Boot. **Update status file** ```bash # The gt boot command handles this automatically # Status is written to $GT_ROOT/deacon/dogs/boot/.boot-status.json ``` Boot is ephemeral by design. Each instance runs fresh. """