diff --git a/.beads/formulas/mol-deacon-patrol.formula.toml b/.beads/formulas/mol-deacon-patrol.formula.toml index 504231c1..7acabf3a 100644 --- a/.beads/formulas/mol-deacon-patrol.formula.toml +++ b/.beads/formulas/mol-deacon-patrol.formula.toml @@ -12,7 +12,7 @@ Witnesses detect it and escalate to the Mayor. The Deacon's agent bead last_activity timestamp is updated during each patrol cycle. Witnesses check this timestamp to verify health.""" formula = "mol-deacon-patrol" -version = 2 +version = 3 [[steps]] id = "inbox-check" @@ -35,16 +35,30 @@ gt mail read **WITNESS_PING**: Witnesses periodically ping to verify Deacon is alive. Simply acknowledge -and mark as read - the fact that you're processing mail proves you're running. +and archive - the fact that you're processing mail proves you're running. Your agent bead last_activity is updated automatically during patrol. +```bash +gt mail archive +``` **HELP / Escalation**: Assess and handle or forward to Mayor. +Archive after handling: +```bash +gt mail archive +``` **LIFECYCLE messages**: Polecats reporting completion, refineries reporting merge results. +Archive after processing: +```bash +gt mail archive +``` -Callbacks may spawn new polecats, update issue state, or trigger other actions.""" +Callbacks may spawn new polecats, update issue state, or trigger other actions. + +**Hygiene principle**: Archive messages after they're fully processed. +Keep inbox near-empty - only unprocessed items should remain.""" [[steps]] id = "trigger-pending-spawns" @@ -350,10 +364,86 @@ This handles: All cleanup is handled by doctor checks - no need to run separate commands.""" +[[steps]] +id = "log-maintenance" +title = "Rotate logs and prune state" +needs = ["session-gc"] +description = """ +Maintain daemon logs and state files. + +**Step 1: Check daemon.log size** +```bash +# Get log file size +ls -la ~/.beads/daemon*.log 2>/dev/null || ls -la ~/gt/.beads/daemon*.log 2>/dev/null +``` + +If daemon.log exceeds 10MB: +```bash +# Rotate with date suffix and gzip +LOGFILE="$HOME/gt/.beads/daemon.log" +if [ -f "$LOGFILE" ] && [ $(stat -f%z "$LOGFILE" 2>/dev/null || stat -c%s "$LOGFILE") -gt 10485760 ]; then + DATE=$(date +%Y-%m-%dT%H-%M-%S) + mv "$LOGFILE" "${LOGFILE%.log}-${DATE}.log" + gzip "${LOGFILE%.log}-${DATE}.log" +fi +``` + +**Step 2: Archive old daemon logs** + +Clean up daemon logs older than 7 days: +```bash +find ~/gt/.beads/ -name "daemon-*.log.gz" -mtime +7 -delete +``` + +**Step 3: Prune state.json of dead sessions** + +The state.json tracks active sessions. Prune entries for sessions that no longer exist: +```bash +# Check for stale session entries +gt daemon status --json 2>/dev/null +``` + +If state.json references sessions not in tmux: +- Remove the stale entries +- The daemon's internal cleanup should handle this, but verify + +**Note**: Log rotation prevents disk bloat from long-running daemons. +State pruning keeps runtime state accurate.""" + +[[steps]] +id = "patrol-cleanup" +title = "End-of-cycle inbox hygiene" +needs = ["log-maintenance"] +description = """ +Verify inbox hygiene before ending patrol cycle. + +**Step 1: Check inbox state** +```bash +gt mail inbox +``` + +Inbox should be EMPTY or contain only just-arrived unprocessed messages. + +**Step 2: Archive any remaining processed messages** + +All message types should have been archived during inbox-check processing: +- WITNESS_PING → archived after acknowledging +- HELP/Escalation → archived after handling +- LIFECYCLE → archived after processing + +If any were missed: +```bash +# For each stale message found: +gt mail archive +``` + +**Goal**: Inbox should have ≤2 active messages at end of cycle. +Deacon mail should flow through quickly - no accumulation.""" + [[steps]] id = "context-check" title = "Check own context limit" -needs = ["session-gc"] +needs = ["patrol-cleanup"] description = """ Check own context limit. diff --git a/.beads/formulas/mol-refinery-patrol.formula.toml b/.beads/formulas/mol-refinery-patrol.formula.toml index 4ccb1e6f..b242acab 100644 --- a/.beads/formulas/mol-refinery-patrol.formula.toml +++ b/.beads/formulas/mol-refinery-patrol.formula.toml @@ -33,7 +33,7 @@ Witness Refinery Git After successful merge, Refinery sends MERGED mail back to Witness so it can complete cleanup (nuke the polecat worktree).""" formula = "mol-refinery-patrol" -version = 2 +version = 3 [[steps]] id = "inbox-check" @@ -65,19 +65,34 @@ A polecat's work is ready for merge. Extract details and track for processing. # - MR bead ID (REQUIRED for closing after merge) ``` -**IMPORTANT**: You MUST track the polecat name and MR bead ID - you will need them -in merge-push step to send MERGED notification and close the MR bead. +**IMPORTANT**: You MUST track the polecat name, MR bead ID, AND message ID - you will need them +in merge-push step to send MERGED notification, close the MR bead, and archive the mail. Mark as read. The work will be processed in queue-scan/process-branch. +**Do NOT archive yet** - archive after merge/reject decision in merge-push step. **PATROL: Wake up**: -Witness detected MRs waiting but refinery idle. Acknowledge and proceed. +Witness detected MRs waiting but refinery idle. Acknowledge and archive: +```bash +gt mail archive +``` **HELP / Blocked**: Assess and respond. If you can't help, escalate to Mayor. +Archive after handling: +```bash +gt mail archive +``` **HANDOFF**: -Read predecessor context. Check for in-flight merges.""" +Read predecessor context. Check for in-flight merges. +Archive after absorbing context: +```bash +gt mail archive +``` + +**Hygiene principle**: Archive messages after they're fully processed. +Keep only: pending MRs in queue. Inbox should be near-empty.""" [[steps]] id = "queue-scan" @@ -196,7 +211,13 @@ The MR bead ID was in the MERGE_READY message or find via: bd list --type=merge-request --status=open | grep ``` -**Step 4: Cleanup (only after Steps 2-3 confirmed)** +**Step 4: Archive the MERGE_READY mail (REQUIRED)** +```bash +gt mail archive +``` +The message ID was tracked when you processed inbox-check. + +**Step 5: Cleanup (only after Steps 2-4 confirmed)** ```bash git branch -d temp git push origin --delete @@ -205,8 +226,9 @@ git push origin --delete **VERIFICATION GATE**: You CANNOT proceed to loop-check without: - [x] MERGED mail sent to witness - [x] MR bead closed +- [x] MERGE_READY mail archived -If you skipped notifications, GO BACK AND SEND THEM NOW. +If you skipped notifications or archiving, GO BACK AND DO THEM NOW. Main has moved. Any remaining branches need rebasing on new baseline.""" @@ -232,13 +254,15 @@ Summarize this patrol cycle. **VERIFICATION**: Before generating summary, confirm for each merged branch: - [ ] MERGED mail was sent to witness - [ ] MR bead was closed +- [ ] MERGE_READY mail archived -If any MERGED notifications were missed, send them now! +If any notifications or archiving were missed, do them now! Include in summary: - Branches processed (count, names) - MERGED mails sent (count - should match branches processed) - MR beads closed (count - should match branches processed) +- MERGE_READY mails archived (count - should match branches processed) - Test results (pass/fail) - Issues filed (if any) - Branches skipped (with reasons) @@ -260,10 +284,41 @@ If context is HIGH (>80%): If context is LOW: - Can continue processing""" +[[steps]] +id = "patrol-cleanup" +title = "End-of-cycle inbox hygiene" +needs = ["context-check"] +description = """ +Verify inbox hygiene before ending patrol cycle. + +**Step 1: Check inbox state** +```bash +gt mail inbox +``` + +Inbox should contain ONLY: +- Unprocessed MERGE_READY messages (will process next cycle) +- Active work items + +**Step 2: Archive any stale messages** + +Look for messages that were processed but not archived: +- PATROL: Wake up that was acknowledged → archive +- HELP/Blocked that was handled → archive +- MERGE_READY where merge completed but archive was missed → archive + +```bash +# For each stale message found: +gt mail archive +``` + +**Goal**: Inbox should have ≤3 active messages at end of cycle. +Keep only: pending MRs in queue.""" + [[steps]] id = "burn-or-loop" title = "Burn and respawn or loop" -needs = ["context-check"] +needs = ["patrol-cleanup"] description = """ End of patrol cycle decision. diff --git a/.beads/formulas/mol-witness-patrol.formula.toml b/.beads/formulas/mol-witness-patrol.formula.toml index 0e638fe2..692bccdb 100644 --- a/.beads/formulas/mol-witness-patrol.formula.toml +++ b/.beads/formulas/mol-witness-patrol.formula.toml @@ -1,369 +1,56 @@ -description = """ -Per-rig worker monitor patrol loop. - -The Witness is the Pit Boss for your rig. You watch polecats, nudge them toward -completion, verify clean git state before kills, and escalate stuck workers. - -**You do NOT do implementation work.** Your job is oversight, not coding. - -## Design Philosophy - -This patrol follows Gas Town principles: -- **Discovery over tracking**: Observe reality each cycle, don't maintain state -- **Events over state**: POLECAT_DONE mail triggers cleanup wisps -- **Cleanup wisps as finalizers**: Pending cleanups are wisps, not queue entries -- **Task tool for parallelism**: Subagents inspect polecats, not molecule arms - -## Patrol Shape (Linear, Deacon-style) - -``` -inbox-check ─► process-cleanups ─► check-refinery ─► survey-workers - │ - ┌──────────────────────────────────────────────────┘ - ▼ - check-swarm ─► ping-deacon ─► context-check ─► loop-or-exit -``` - -No dynamic arms. No fanout gates. No persistent nudge counters. -State is discovered each cycle from reality (tmux, beads, mail).""" -formula = "mol-witness-patrol" -version = 1 +description = "Per-rig worker monitor patrol loop.\n\nThe Witness is the Pit Boss for your rig. You watch polecats, nudge them toward\ncompletion, verify clean git state before kills, and escalate stuck workers.\n\n**You do NOT do implementation work.** Your job is oversight, not coding.\n\n## Design Philosophy\n\nThis patrol follows Gas Town principles:\n- **Discovery over tracking**: Observe reality each cycle, don't maintain state\n- **Events over state**: POLECAT_DONE mail triggers cleanup wisps\n- **Cleanup wisps as finalizers**: Pending cleanups are wisps, not queue entries\n- **Task tool for parallelism**: Subagents inspect polecats, not molecule arms\n\n## Patrol Shape (Linear, Deacon-style)\n\n```\ninbox-check ─► process-cleanups ─► check-refinery ─► survey-workers\n │\n ┌──────────────────────────────────────────────────┘\n ▼\n check-swarm ─► ping-deacon ─► patrol-cleanup ─► context-check ─► loop-or-exit\n```\n\nNo dynamic arms. No fanout gates. No persistent nudge counters.\nState is discovered each cycle from reality (tmux, beads, mail)." +formula = 'mol-witness-patrol' +version = 2 [[steps]] -id = "inbox-check" -title = "Process witness mail" -description = """ -Check inbox and handle messages. - -```bash -gt mail inbox -``` - -For each message: - -**POLECAT_DONE / LIFECYCLE:Shutdown**: -Create a cleanup wisp for this polecat: -```bash -bd create --wisp --title "cleanup:" \ - --description "Verify and cleanup polecat " \ - --labels cleanup,polecat:,state:pending -``` -The wisp's existence IS the pending cleanup. Process in next step. -Mark mail as read. - -**MERGED**: -A branch was merged successfully. Complete the cleanup. -```bash -# Find the cleanup wisp for this polecat -bd list --wisp --labels=polecat:,state:merge-requested --status=open - -# If found, proceed with full polecat nuke: -# - Kill Claude session -# - Delete worktree -# - Delete branch -# - Remove agent bead -gt polecat nuke - -# Burn the cleanup wisp -bd close -``` -Mark mail as read. - -**HELP / Blocked**: -Assess the request. Can you help? If not, escalate to Mayor: -```bash -gt mail send mayor/ -s "Escalation: needs help" -m "
" -``` - -**HANDOFF**: -Read predecessor context. Continue from where they left off. - -**SWARM_START**: -Mayor initiating batch polecat work. Initialize swarm tracking. -```bash -# Parse swarm info from mail body: {"swarm_id": "batch-123", "beads": ["bd-a", "bd-b"]} -bd create --wisp --title "swarm:" \ - --description "Tracking batch: " \ - --labels swarm,swarm_id:,total:,completed:0,start: -``` -Mark mail as read.""" +description = "Check inbox and handle messages.\n\n```bash\ngt mail inbox\n```\n\nFor each message:\n\n**POLECAT_STARTED**:\nA new polecat has started working. Acknowledge and archive.\n```bash\n# Acknowledge startup (optional: log for activity tracking)\ngt mail archive \n```\nNo action needed beyond acknowledgment - archive immediately.\n\n**POLECAT_DONE / LIFECYCLE:Shutdown**:\nCreate a cleanup wisp for this polecat:\n```bash\nbd create --wisp --title \"cleanup:\" --description \"Verify and cleanup polecat \" --labels cleanup,polecat:,state:pending\n```\nThe wisp's existence IS the pending cleanup. Process in next step.\n**Do NOT archive yet** - archive after cleanup completes (in MERGED handling).\n\n**MERGED**:\nA branch was merged successfully. Complete the cleanup.\n```bash\n# Find the cleanup wisp for this polecat\nbd list --wisp --labels=polecat:,state:merge-requested --status=open\n\n# If found, proceed with full polecat nuke:\n# - Kill Claude session\n# - Delete worktree\n# - Delete branch\n# - Remove agent bead\ngt polecat nuke \n\n# Burn the cleanup wisp\nbd close \n\n# NOW archive both the MERGED mail and the original POLECAT_DONE mail\n# (The POLECAT_DONE message ID should be tracked in the cleanup wisp or MR bead)\ngt mail archive \ngt mail archive # If tracked\n```\nArchive after cleanup is complete.\n\n**HELP / Blocked**:\nAssess the request. Can you help? If not, escalate to Mayor:\n```bash\ngt mail send mayor/ -s \"Escalation: needs help\" -m \"
\"\n```\nArchive after handling (escalated or resolved):\n```bash\ngt mail archive \n```\n\n**HANDOFF**:\nRead predecessor context. Continue from where they left off.\nArchive after absorbing context:\n```bash\ngt mail archive \n```\n\n**SWARM_START**:\nMayor initiating batch polecat work. Initialize swarm tracking.\n```bash\n# Parse swarm info from mail body: {\"swarm_id\": \"batch-123\", \"beads\": [\"bd-a\", \"bd-b\"]}\nbd create --wisp --title \"swarm:\" --description \"Tracking batch: \" --labels swarm,swarm_id:,total:,completed:0,start:\n```\nArchive after creating swarm tracking wisp:\n```bash\ngt mail archive \n```\n\n**Hygiene principle**: Archive messages after they're fully processed.\nKeep only: active work, unprocessed requests. Inbox should be near-empty." +id = 'inbox-check' +title = 'Process witness mail' [[steps]] -id = "process-cleanups" -title = "Process pending cleanup wisps" -needs = ["inbox-check"] -description = """ -Find and process cleanup wisps (the finalizer pattern). - -```bash -# Find all cleanup wisps -bd list --wisp --labels=cleanup --status=open -``` - -For each cleanup wisp, check its state label: - -## State: pending (needs verification → MERGE_READY) - -1. **Extract polecat name** from wisp title/labels - -2. **Pre-kill verification**: -```bash -cd polecats/ -git status # Must be clean -git log origin/main..HEAD # Commits should be pushed -bd show # Issue closed or deferred -``` - -3. **Get branch and issue info**: -```bash -# Get current branch -git rev-parse --abbrev-ref HEAD - -# Get the hook_bead from agent bead -bd show # Look for hook_bead field -``` - -4. **Verify productive work** (ZFC - you make the call): - - Check git log for commits mentioning the issue - - Legitimate exceptions: already fixed, duplicate, deferred - - If closing as 'done' with no commits, flag for review - -5. **If clean**: Send MERGE_READY to refinery -```bash -gt mail send /refinery -s "MERGE_READY " -m "Branch: -Issue: -Polecat: -Verified: clean git state, issue closed" -``` -Then update the wisp to merge-requested state: -```bash -bd update --labels cleanup,polecat:,state:merge-requested -``` -**Do NOT kill the polecat yet** - wait for MERGED confirmation from refinery. - -6. **If dirty**: Leave wisp open, log the issue, retry next cycle. - -## State: merge-requested (waiting for refinery) - -Skip - waiting for MERGED mail from refinery. The inbox-check step handles -MERGED messages and completes these cleanup wisps. - -**Parallelism**: Use Task tool subagents to process multiple cleanups concurrently. -Each cleanup is independent - perfect for parallel execution.""" +description = "Find and process cleanup wisps (the finalizer pattern).\n\n```bash\n# Find all cleanup wisps\nbd list --wisp --labels=cleanup --status=open\n```\n\nFor each cleanup wisp, check its state label:\n\n## State: pending (needs verification → MERGE_READY)\n\n1. **Extract polecat name** from wisp title/labels\n\n2. **Pre-kill verification**:\n```bash\ncd polecats/\ngit status # Must be clean\ngit log origin/main..HEAD # Commits should be pushed\nbd show # Issue closed or deferred\n```\n\n3. **Get branch and issue info**:\n```bash\n# Get current branch\ngit rev-parse --abbrev-ref HEAD\n\n# Get the hook_bead from agent bead\nbd show # Look for hook_bead field\n```\n\n4. **Verify productive work** (ZFC - you make the call):\n - Check git log for commits mentioning the issue\n - Legitimate exceptions: already fixed, duplicate, deferred\n - If closing as 'done' with no commits, flag for review\n\n5. **If clean**: Send MERGE_READY to refinery\n```bash\ngt mail send /refinery -s \"MERGE_READY \" -m \"Branch: \nIssue: \nPolecat: \nVerified: clean git state, issue closed\"\n```\nThen update the wisp to merge-requested state:\n```bash\nbd update --labels cleanup,polecat:,state:merge-requested\n```\n**Do NOT kill the polecat yet** - wait for MERGED confirmation from refinery.\n\n6. **If dirty**: Leave wisp open, log the issue, retry next cycle.\n\n## State: merge-requested (waiting for refinery)\n\nSkip - waiting for MERGED mail from refinery. The inbox-check step handles\nMERGED messages and completes these cleanup wisps.\n\n**Parallelism**: Use Task tool subagents to process multiple cleanups concurrently.\nEach cleanup is independent - perfect for parallel execution." +id = 'process-cleanups' +needs = ['inbox-check'] +title = 'Process pending cleanup wisps' [[steps]] -id = "check-refinery" -title = "Ensure refinery is alive" -needs = ["process-cleanups"] -description = """ -Ensure the refinery is alive and processing merge requests. - -```bash -# Check if refinery session exists -gt session status /refinery - -# Check for pending merge requests -bd list --type=merge-request --status=open -``` - -If MRs waiting AND refinery not running: -```bash -gt session start /refinery -gt mail send /refinery -s "PATROL: Wake up" \ - -m "Merge requests in queue. Please process." -``` - -If refinery running but queue stale (>30 min), send nudge.""" +description = "Ensure the refinery is alive and processing merge requests.\n\n```bash\n# Check if refinery session exists\ngt session status /refinery\n\n# Check for pending merge requests\nbd list --type=merge-request --status=open\n```\n\nIf MRs waiting AND refinery not running:\n```bash\ngt session start /refinery\ngt mail send /refinery -s \"PATROL: Wake up\" -m \"Merge requests in queue. Please process.\"\n```\n\nIf refinery running but queue stale (>30 min), send nudge." +id = 'check-refinery' +needs = ['process-cleanups'] +title = 'Ensure refinery is alive' [[steps]] -id = "survey-workers" -title = "Inspect all active polecats" -needs = ["check-refinery"] -description = """ -Survey all polecats using agent beads (ZFC: trust what agents report). - -**Step 1: List polecat agent beads** - -```bash -bd list --type=agent --json -``` - -Filter the JSON output for entries where description contains `role_type: polecat`. -Each polecat agent bead has fields in its description: -- `role_type: polecat` -- `rig: ` -- `agent_state: running|idle|stuck|done` -- `hook_bead: ` - -**Step 2: For each polecat, check agent_state** - -| agent_state | Meaning | Action | -|-------------|---------|--------| -| running | Actively working | Check progress (Step 3) | -| idle | No work assigned | Skip (no action needed) | -| stuck | Self-reported stuck | Handle stuck protocol | -| done | Work complete | Verify cleanup triggered (see Step 4a) | - -**Step 3: For running polecats, assess progress** - -Check the hook_bead field to see what they're working on: -```bash -bd show # See current step/issue -``` - -You can also verify they're responsive: -```bash -tmux capture-pane -t gt-- -p | tail -20 -``` - -Look for: -- Recent tool activity → making progress -- Idle at prompt → may need nudge -- Error messages → may need help - -**Step 4: Decide action** - -| Observation | Action | -|-------------|--------| -| agent_state=running, recent activity | None | -| agent_state=running, idle 5-15 min | Gentle nudge | -| agent_state=running, idle 15+ min | Direct nudge with deadline | -| agent_state=stuck | Assess and help or escalate | -| agent_state=done | Verify cleanup triggered (see Step 4a) | - -**Step 4a: Handle agent_state=done** - -Check if a cleanup wisp exists for this polecat: -```bash -bd list --wisp --labels=polecat: --status=open -``` - -If cleanup wisp exists: -- state:pending → Will be processed in process-cleanups -- state:merge-requested → Waiting for refinery MERGED response - -If NO cleanup wisp exists (POLECAT_DONE mail missed): -Create one to trigger the cleanup flow: -```bash -bd create --wisp --title "cleanup:" \ - --description "Discovered done polecat without cleanup wisp" \ - --labels cleanup,polecat:,state:pending -``` -This ensures done polecats eventually get cleaned up even if mail was lost. - -**Step 5: Execute nudges** -```bash -gt nudge /polecats/ "How's progress? Need help?" -``` - -**Step 6: Escalate if needed** -```bash -gt mail send mayor/ -s "Escalation: stuck" \\ - -m "Polecat reports stuck. Please intervene." -``` - -**Parallelism**: Use Task tool subagents to inspect multiple polecats concurrently. - -**ZFC Principle**: Trust agent_state from beads. Don't infer state from PID/tmux.""" +description = "Survey all polecats using agent beads (ZFC: trust what agents report).\n\n**Step 1: List polecat agent beads**\n\n```bash\nbd list --type=agent --json\n```\n\nFilter the JSON output for entries where description contains `role_type: polecat`.\nEach polecat agent bead has fields in its description:\n- `role_type: polecat`\n- `rig: `\n- `agent_state: running|idle|stuck|done`\n- `hook_bead: `\n\n**Step 2: For each polecat, check agent_state**\n\n| agent_state | Meaning | Action |\n|-------------|---------|--------|\n| running | Actively working | Check progress (Step 3) |\n| idle | No work assigned | Skip (no action needed) |\n| stuck | Self-reported stuck | Handle stuck protocol |\n| done | Work complete | Verify cleanup triggered (see Step 4a) |\n\n**Step 3: For running polecats, assess progress**\n\nCheck the hook_bead field to see what they're working on:\n```bash\nbd show # See current step/issue\n```\n\nYou can also verify they're responsive:\n```bash\ntmux capture-pane -t gt-- -p | tail -20\n```\n\nLook for:\n- Recent tool activity → making progress\n- Idle at prompt → may need nudge\n- Error messages → may need help\n\n**Step 4: Decide action**\n\n| Observation | Action |\n|-------------|--------|\n| agent_state=running, recent activity | None |\n| agent_state=running, idle 5-15 min | Gentle nudge |\n| agent_state=running, idle 15+ min | Direct nudge with deadline |\n| agent_state=stuck | Assess and help or escalate |\n| agent_state=done | Verify cleanup triggered (see Step 4a) |\n\n**Step 4a: Handle agent_state=done**\n\nCheck if a cleanup wisp exists for this polecat:\n```bash\nbd list --wisp --labels=polecat: --status=open\n```\n\nIf cleanup wisp exists:\n- state:pending → Will be processed in process-cleanups\n- state:merge-requested → Waiting for refinery MERGED response\n\nIf NO cleanup wisp exists (POLECAT_DONE mail missed):\nCreate one to trigger the cleanup flow:\n```bash\nbd create --wisp --title \"cleanup:\" --description \"Discovered done polecat without cleanup wisp\" --labels cleanup,polecat:,state:pending\n```\nThis ensures done polecats eventually get cleaned up even if mail was lost.\n\n**Step 5: Execute nudges**\n```bash\ngt nudge /polecats/ \"How's progress? Need help?\"\n```\n\n**Step 6: Escalate if needed**\n```bash\ngt mail send mayor/ -s \"Escalation: stuck\" \\\n -m \"Polecat reports stuck. Please intervene.\"\n```\n\n**Parallelism**: Use Task tool subagents to inspect multiple polecats concurrently.\n\n**ZFC Principle**: Trust agent_state from beads. Don't infer state from PID/tmux." +id = 'survey-workers' +needs = ['check-refinery'] +title = 'Inspect all active polecats' [[steps]] -id = "check-swarm-completion" -title = "Check if active swarm is complete" -needs = ["survey-workers"] -description = """ -If Mayor started a batch (SWARM_START), check if all polecats have completed. - -**Step 1: Find active swarm tracking wisps** -```bash -bd list --wisp --labels=swarm --status=open -``` -If no active swarm, skip this step. - -**Step 2: Count completed polecats for this swarm** - -Extract from wisp labels: swarm_id, total, completed, start timestamp. -Check how many cleanup wisps have been closed for this swarm's polecats. - -**Step 3: If all complete, notify Mayor** -```bash -gt mail send mayor/ -s "SWARM_COMPLETE: " -m "All polecats merged. -Duration: minutes -Swarm: " - -# Close the swarm tracking wisp -bd close --reason "All polecats merged" -``` - -Note: Runs every patrol cycle. Notification sent exactly once when all complete.""" +description = "If Mayor started a batch (SWARM_START), check if all polecats have completed.\n\n**Step 1: Find active swarm tracking wisps**\n```bash\nbd list --wisp --labels=swarm --status=open\n```\nIf no active swarm, skip this step.\n\n**Step 2: Count completed polecats for this swarm**\n\nExtract from wisp labels: swarm_id, total, completed, start timestamp.\nCheck how many cleanup wisps have been closed for this swarm's polecats.\n\n**Step 3: If all complete, notify Mayor**\n```bash\ngt mail send mayor/ -s \"SWARM_COMPLETE: \" -m \"All polecats merged.\nDuration: minutes\nSwarm: \"\n\n# Close the swarm tracking wisp\nbd close --reason \"All polecats merged\"\n```\n\nNote: Runs every patrol cycle. Notification sent exactly once when all complete." +id = 'check-swarm-completion' +needs = ['survey-workers'] +title = 'Check if active swarm is complete' [[steps]] -id = "ping-deacon" -title = "Ping Deacon for health check" -needs = ["check-swarm-completion"] -description = """ -Send WITNESS_PING to Deacon for second-order monitoring. - -The Witness fleet collectively monitors Deacon health - this prevents the -"who watches the watchers" problem. If Deacon dies, Witnesses detect it. - -**Step 1: Send ping** -```bash -gt mail send deacon/ -s "WITNESS_PING " -m "Rig: -Timestamp: $(date -u +%Y-%m-%dT%H:%M:%SZ) -Patrol: " -``` - -**Step 2: Check Deacon health** -```bash -# Check Deacon agent bead for last_activity -bd list --type=agent --json | jq '.[] | select(.description | contains("deacon"))' -``` - -Look at the `last_activity` timestamp. If stale (>5 minutes since last update): -- Deacon may be dead or stuck - -**Step 3: Escalate if needed** -```bash -# If Deacon appears down -gt mail send mayor/ -s "ALERT: Deacon appears unresponsive" \ - -m "No Deacon activity for >5 minutes. -Last seen: -Witness: /witness" -``` - -Note: Multiple Witnesses may send this alert. Mayor should handle deduplication.""" +description = "Send WITNESS_PING to Deacon for second-order monitoring.\n\nThe Witness fleet collectively monitors Deacon health - this prevents the\n\"who watches the watchers\" problem. If Deacon dies, Witnesses detect it.\n\n**Step 1: Send ping**\n```bash\ngt mail send deacon/ -s \"WITNESS_PING \" -m \"Rig: \nTimestamp: $(date -u +%Y-%m-%dT%H:%M:%SZ)\nPatrol: \"\n```\n\n**Step 2: Check Deacon health**\n```bash\n# Check Deacon agent bead for last_activity\nbd list --type=agent --json | jq '.[] | select(.description | contains(\"deacon\"))'\n```\n\nLook at the `last_activity` timestamp. If stale (>5 minutes since last update):\n- Deacon may be dead or stuck\n\n**Step 3: Escalate if needed**\n```bash\n# If Deacon appears down\ngt mail send mayor/ -s \"ALERT: Deacon appears unresponsive\" -m \"No Deacon activity for >5 minutes.\nLast seen: \nWitness: /witness\"\n```\n\nNote: Multiple Witnesses may send this alert. Mayor should handle deduplication." +id = 'ping-deacon' +needs = ['check-swarm-completion'] +title = 'Ping Deacon for health check' [[steps]] -id = "context-check" -title = "Check own context limit" -needs = ["ping-deacon"] -description = """ -Check own context usage. - -If context is HIGH (>80%): -- Ensure any notes are written to handoff mail -- Prepare for session restart - -If context is LOW: -- Can continue patrolling""" +description = "Verify inbox hygiene before ending patrol cycle.\n\n**Step 1: Check inbox state**\n```bash\ngt mail inbox\n```\n\nInbox should contain ONLY:\n- Unprocessed messages (just arrived, will handle next cycle)\n- Active work markers (POLECAT_DONE waiting for MERGED confirmation)\n\n**Step 2: Archive any stale messages**\n\nLook for messages that were processed but not archived:\n- POLECAT_STARTED older than this cycle → archive\n- HELP/Blocked that was escalated → archive\n- SWARM_START that created tracking wisp → archive\n\n```bash\n# For each stale message found:\ngt mail archive \n```\n\n**Step 3: Verify cleanup wisp hygiene**\n\nCheck that all cleanup wisps are in valid states:\n```bash\nbd list --wisp --labels=cleanup --status=open\n```\n\n- state:pending → Will be processed next cycle\n- state:merge-requested → Waiting for refinery\n\nIf any cleanup wisp is older than expected (>1 hour in merge-requested state),\nthe refinery may be stuck. This was checked in check-refinery step.\n\n**Goal**: Inbox should have ≤5 active messages at end of cycle." +id = 'patrol-cleanup' +needs = ['ping-deacon'] +title = 'End-of-cycle inbox hygiene' [[steps]] -id = "loop-or-exit" -title = "Loop or exit for respawn" -needs = ["context-check"] -description = """ -End of patrol cycle decision. +description = "Check own context usage.\n\nIf context is HIGH (>80%):\n- Ensure any notes are written to handoff mail\n- Prepare for session restart\n\nIf context is LOW:\n- Can continue patrolling" +id = 'context-check' +needs = ['patrol-cleanup'] +title = 'Check own context limit' -**If context LOW**: -- Sleep briefly to avoid tight loop (30-60 seconds) -- Return to inbox-check step -- Continue patrolling - -**If context HIGH**: -- Write handoff mail to self with any notable observations: -```bash -gt handoff -s "Witness patrol handoff" -m "" -``` -- Exit cleanly (daemon respawns fresh Witness) - -The daemon ensures Witness is always running.""" +[[steps]] +description = "End of patrol cycle decision.\n\n**If context LOW**:\n- Sleep briefly to avoid tight loop (30-60 seconds)\n- Return to inbox-check step\n- Continue patrolling\n\n**If context HIGH**:\n- Write handoff mail to self with any notable observations:\n```bash\ngt handoff -s \"Witness patrol handoff\" -m \"\"\n```\n- Exit cleanly (daemon respawns fresh Witness)\n\nThe daemon ensures Witness is always running." +id = 'loop-or-exit' +needs = ['context-check'] +title = 'Loop or exit for respawn'