Simplify Witness patrol: linear + Task tool, no Christmas Ornament (gt-p3v5n)

Design pivot:
- Remove mol-polecat-arm and dynamic bonding pattern
- Replace with linear patrol (Deacon-style) + Task tool parallelism
- Cleanup wisps as finalizers (marker wisp = pending cleanup)
- Discovery over tracking (no persistent nudge counts)

New docs:
- polecat-lifecycle.md: step-based restart model, evolution path
- witness-patrol-design.md: simplified, terse

Closed obsolete issues: gt-p3v5n.1 through gt-p3v5n.4

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Steve Yegge
2025-12-26 14:16:41 -08:00
parent 1df41e23c7
commit 0e90fca49f
7 changed files with 462 additions and 740 deletions

View File

@@ -1,50 +0,0 @@
{
"formula": "mol-polecat-arm",
"description": "Single polecat inspection and action cycle.\n\nThis molecule is bonded dynamically by mol-witness-patrol's survey-workers step. Each polecat being monitored gets one arm that runs in parallel with other arms.\n\n## Variables\n\n| Variable | Required | Description |\n|----------|----------|-------------|\n| polecat_name | Yes | Name of the polecat to inspect |\n| rig | Yes | Rig containing the polecat |\n| nudge_text | No | Text to send when nudging (default: \"How's progress?...\") |",
"version": 1,
"vars": {
"polecat_name": {
"required": true,
"description": "Name of the polecat to inspect"
},
"rig": {
"required": true,
"description": "Rig containing the polecat"
},
"nudge_text": {
"default": "How's progress? Need any help?",
"description": "Text to send when nudging the polecat"
}
},
"steps": [
{
"id": "capture",
"title": "Capture polecat state",
"description": "Capture recent tmux output for {{polecat_name}}.\n\n```bash\ntmux capture-pane -t gt-{{rig}}-{{polecat_name}} -p | tail -50\n```\n\nRecord:\n- Last activity timestamp (when was last tool call?)\n- Visible errors or stack traces\n- Completion indicators (\"Done\", \"Finished\", etc.)"
},
{
"id": "assess",
"title": "Assess work status",
"needs": ["capture"],
"description": "Categorize polecat state based on captured output.\n\nStates:\n- **working**: Recent tool calls, active processing\n- **idle**: At prompt, no recent activity\n- **error**: Showing errors or stack traces\n- **requesting_shutdown**: Sent LIFECYCLE/Shutdown mail\n- **done**: Showing completion indicators\n\nCalculate: minutes since last activity."
},
{
"id": "load-history",
"title": "Load intervention history",
"needs": ["assess"],
"description": "Read nudge history for {{polecat_name}} from patrol state.\n\n```\nnudge_count = state.nudges[{{polecat_name}}].count\nlast_nudge_time = state.nudges[{{polecat_name}}].timestamp\n```\n\nThis data was loaded by the parent patrol's load-state step and passed to the arm via the bonding context."
},
{
"id": "decide",
"title": "Decide intervention action",
"needs": ["load-history"],
"description": "Apply the nudge matrix to determine action for {{polecat_name}}.\n\n| State | Idle Time | Nudge Count | Action |\n|-------|-----------|-------------|--------|\n| working | any | any | none |\n| idle | <10min | any | none |\n| idle | 10-15min | 0 | nudge-1 (gentle) |\n| idle | 15-20min | 1 | nudge-2 (direct) |\n| idle | 20+min | 2 | nudge-3 (final) |\n| idle | any | 3 | escalate |\n| error | any | any | assess-severity |\n| requesting_shutdown | any | any | pre-kill-verify |\n| done | any | any | pre-kill-verify |\n\nNudge text:\n1. \"How's progress? Need any help?\"\n2. \"Please wrap up soon. What's blocking you?\"\n3. \"Final check. Will escalate in 5 min if no response.\"\n\nRecord decision and rationale."
},
{
"id": "execute",
"title": "Execute intervention",
"needs": ["decide"],
"description": "Take the decided action for {{polecat_name}}.\n\n**nudge-N**:\n```bash\ntmux send-keys -t gt-{{rig}}-{{polecat_name}} \"{{nudge_text}}\" Enter\n```\n\n**pre-kill-verify**:\n```bash\ncd polecats/{{polecat_name}}\ngit status # Must be clean\ngit log origin/main..HEAD # Check for unpushed\nbd show <assigned-issue> # Verify closed/deferred\n\n# Verify productive work (for 'done' closures)\ngit log --oneline --grep='<issue-id>' | head -1\n```\n\n**Commit verification** (ZFC principle - agent makes the call):\n- If issue closed as 'done' but no commits reference it → flag for review\n- Legitimate exceptions: already fixed elsewhere, duplicate, deferred\n- Agent must provide justification if closing without commits\n\nIf clean: kill session, remove worktree, delete branch\nIf dirty: record failure, retry next cycle\n\n**escalate**:\n```bash\ngt mail send mayor/ -s \"Escalation: {{polecat_name}} stuck\" -m \"...\"\n```\n\n**none**: No action needed.\n\nRecord: action taken, result, updated nudge count.\n\n## Output\n\nThe arm completes with:\n- action_taken: none | nudge-1 | nudge-2 | nudge-3 | killed | escalated\n- result: success | failed | pending\n- updated_state: New nudge count and timestamp for {{polecat_name}}\n\nThis data feeds back to the parent patrol's aggregate step."
}
]
}

View File

@@ -1,145 +0,0 @@
description = """
Single polecat inspection and action cycle.
This molecule is bonded dynamically by mol-witness-patrol's survey-workers step. Each polecat being monitored gets one arm that runs in parallel with other arms.
## Variables
| Variable | Required | Description |
|----------|----------|-------------|
| polecat_name | Yes | Name of the polecat to inspect |
| rig | Yes | Rig containing the polecat |
| nudge_text | No | Text to send when nudging (default: \"How's progress?...\") |"""
formula = "mol-polecat-arm"
version = 1
[[steps]]
description = """
Capture recent tmux output for {{polecat_name}}.
```bash
tmux capture-pane -t gt-{{rig}}-{{polecat_name}} -p | tail -50
```
Record:
- Last activity timestamp (when was last tool call?)
- Visible errors or stack traces
- Completion indicators (\"Done\", \"Finished\", etc.)"""
id = "capture"
title = "Capture polecat state"
[[steps]]
description = """
Categorize polecat state based on captured output.
States:
- **working**: Recent tool calls, active processing
- **idle**: At prompt, no recent activity
- **error**: Showing errors or stack traces
- **requesting_shutdown**: Sent LIFECYCLE/Shutdown mail
- **done**: Showing completion indicators
Calculate: minutes since last activity."""
id = "assess"
needs = ["capture"]
title = "Assess work status"
[[steps]]
description = """
Read nudge history for {{polecat_name}} from patrol state.
```
nudge_count = state.nudges[{{polecat_name}}].count
last_nudge_time = state.nudges[{{polecat_name}}].timestamp
```
This data was loaded by the parent patrol's load-state step and passed to the arm via the bonding context."""
id = "load-history"
needs = ["assess"]
title = "Load intervention history"
[[steps]]
description = """
Apply the nudge matrix to determine action for {{polecat_name}}.
| State | Idle Time | Nudge Count | Action |
|-------|-----------|-------------|--------|
| working | any | any | none |
| idle | <10min | any | none |
| idle | 10-15min | 0 | nudge-1 (gentle) |
| idle | 15-20min | 1 | nudge-2 (direct) |
| idle | 20+min | 2 | nudge-3 (final) |
| idle | any | 3 | escalate |
| error | any | any | assess-severity |
| requesting_shutdown | any | any | pre-kill-verify |
| done | any | any | pre-kill-verify |
Nudge text:
1. \"How's progress? Need any help?\"
2. \"Please wrap up soon. What's blocking you?\"
3. \"Final check. Will escalate in 5 min if no response.\"
Record decision and rationale."""
id = "decide"
needs = ["load-history"]
title = "Decide intervention action"
[[steps]]
description = """
Take the decided action for {{polecat_name}}.
**nudge-N**:
```bash
tmux send-keys -t gt-{{rig}}-{{polecat_name}} \"{{nudge_text}}\" Enter
```
**pre-kill-verify**:
```bash
cd polecats/{{polecat_name}}
git status # Must be clean
git log origin/main..HEAD # Check for unpushed
bd show <assigned-issue> # Verify closed/deferred
# Verify productive work (for 'done' closures)
git log --oneline --grep='<issue-id>' | head -1
```
**Commit verification** (ZFC principle - agent makes the call):
- If issue closed as 'done' but no commits reference it → flag for review
- Legitimate exceptions: already fixed elsewhere, duplicate, deferred
- Agent must provide justification if closing without commits
If clean: kill session, remove worktree, delete branch
If dirty: record failure, retry next cycle
**escalate**:
```bash
gt mail send mayor/ -s \"Escalation: {{polecat_name}} stuck\" -m \"...\"
```
**none**: No action needed.
Record: action taken, result, updated nudge count.
## Output
The arm completes with:
- action_taken: none | nudge-1 | nudge-2 | nudge-3 | killed | escalated
- result: success | failed | pending
- updated_state: New nudge count and timestamp for {{polecat_name}}
This data feeds back to the parent patrol's aggregate step."""
id = "execute"
needs = ["decide"]
title = "Execute intervention"
[vars]
[vars.nudge_text]
default = "How's progress? Need any help?"
description = "Text to send when nudging the polecat"
[vars.polecat_name]
description = "Name of the polecat to inspect"
required = true
[vars.rig]
description = "Rig containing the polecat"
required = true

View File

@@ -1,61 +0,0 @@
{
"formula": "mol-witness-patrol",
"description": "Per-rig worker monitor patrol loop using the Christmas Ornament pattern.\n\nThe 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.\n\n**You do NOT do implementation work.** Your job is oversight, not coding.\n\nThis molecule uses dynamic bonding to spawn mol-polecat-arm for each worker, enabling parallel inspection with a fanout gate for aggregation.\n\n## The Christmas Ornament Shape\n\n```\n ★ mol-witness-patrol (trunk)\n /|\\\n ┌────────┘ │ └────────┐\n PREFLIGHT DISCOVERY CLEANUP\n │ │ │\n inbox-check survey aggregate (WaitsFor: all-children)\n check-refnry │ save-state\n load-state │ generate-summary\n ↓ context-check\n ┌───────┼───────┐ burn-or-loop\n ● ● ● mol-polecat-arm (dynamic)\n ace nux toast\n```",
"version": 1,
"steps": [
{
"id": "inbox-check",
"title": "Process witness mail",
"description": "Process witness mail: lifecycle requests, help requests.\n\n```bash\ngt mail inbox\n```\n\nHandle by message type:\n- **LIFECYCLE/Shutdown**: Queue for pre-kill verification\n- **Blocked/Help**: Assess if resolvable or escalate\n- **HANDOFF**: Load predecessor state\n- **Work complete**: Verify issue closed, proceed to pre-kill\n\nRecord any pending actions for later steps. Mark messages as processed when complete."
},
{
"id": "check-refinery",
"title": "Ensure refinery is alive",
"needs": ["inbox-check"],
"description": "Ensure the refinery is alive and processing merge requests.\n\n**Redundant system**: This check runs in both gt spawn and Witness patrol to ensure the merge queue processor stays operational.\n\n```bash\n# Check if refinery session is running\ngt session status <rig>/refinery\n\n# Check for merge requests in queue\nbd list --type=merge-request --status=open\n```\n\nIf merge requests are waiting AND refinery is not running:\n```bash\ngt session start <rig>/refinery\ngt mail send <rig>/refinery -s \"PATROL: Wake up\" -m \"Merge requests in queue. Please process.\"\n```\n\nIf refinery is running but queue is non-empty for >30 min, send nudge. This ensures polecats don't wait forever for their branches to merge."
},
{
"id": "load-state",
"title": "Load persisted patrol state",
"needs": ["check-refinery"],
"description": "Read handoff bead and get nudge counts.\n\nLoad persistent state from the witness handoff bead:\n- Active workers and their status from last cycle\n- Nudge counts per worker per issue\n- Last nudge timestamps\n- Pending escalations\n\n```bash\nbd show <handoff-bead-id>\n```\n\nIf no handoff exists (fresh start), initialize empty state. This state persists across wisp burns and session cycles."
},
{
"id": "survey-workers",
"title": "Survey all polecats (fanout)",
"needs": ["load-state"],
"description": "List polecats and bond mol-polecat-arm for each one.\n\n```bash\n# Get list of polecats\ngt polecat list <rig>\n```\n\nFor each polecat discovered, dynamically bond an inspection arm:\n\n```bash\n# Bond mol-polecat-arm for each polecat\nfor polecat in $(gt polecat list <rig> --names); do\n bd mol bond mol-polecat-arm $PATROL_WISP_ID \\\n --ref arm-$polecat \\\n --var polecat_name=$polecat \\\n --var rig=<rig>\ndone\n```\n\nThis creates child wisps like:\n- patrol-x7k.arm-ace (5 steps)\n- patrol-x7k.arm-nux (5 steps)\n- patrol-x7k.arm-toast (5 steps)\n\nEach arm runs in PARALLEL. The aggregate step will wait for all to complete.\n\nIf no polecats are found, this step completes immediately with no children."
},
{
"id": "aggregate",
"title": "Aggregate arm results",
"needs": ["survey-workers"],
"waits_for": "all-children",
"description": "Collect outcomes from all polecat inspection arms.\n\nThis is a **fanout gate** - it cannot proceed until ALL dynamically-bonded polecat arms have completed their inspection cycles.\n\nOnce all arms complete, collect their outcomes:\n- Actions taken per polecat (nudge, kill, escalate, none)\n- Updated nudge counts\n- Any errors or issues discovered\n\nBuild the consolidated state for save-state."
},
{
"id": "save-state",
"title": "Persist patrol state",
"needs": ["aggregate"],
"description": "Update handoff bead with new states.\n\nPersist state to the witness handoff bead:\n- Updated worker statuses from all arms\n- Current nudge counts per worker\n- Nudge timestamps\n- Actions taken this cycle\n- Pending items for next cycle\n\n```bash\nbd update <handoff-bead-id> --description=\"<serialized state>\"\n```\n\nThis state survives wisp burns and session cycles."
},
{
"id": "generate-summary",
"title": "Generate handoff summary",
"needs": ["save-state"],
"description": "Summarize this patrol cycle for digest.\n\nInclude:\n- Workers inspected (count, names)\n- Nudges sent (count, to whom)\n- Sessions killed (count, names)\n- Escalations (count, issues)\n- Issues found (brief descriptions)\n- Actions pending for next cycle\n\nThis becomes the digest when the patrol wisp is squashed."
},
{
"id": "context-check",
"title": "Check own context limit",
"needs": ["generate-summary"],
"description": "Check own context usage.\n\nIf context is HIGH (>80%):\n- Ensure state is saved to handoff bead\n- Prepare for burn/respawn\n\nIf context is LOW:\n- Can continue patrolling"
},
{
"id": "burn-or-loop",
"title": "Burn and respawn or loop",
"needs": ["context-check"],
"description": "End of patrol cycle decision.\n\nIf context is LOW:\n- Burn this wisp (no audit trail needed for patrol cycles)\n- Sleep briefly to avoid tight loop (30-60 seconds)\n- Return to inbox-check step\n\nIf context is HIGH:\n- Burn wisp with summary digest\n- Exit cleanly (daemon will respawn fresh Witness)\n\n```bash\nbd mol burn # Destroy ephemeral wisp\n```\n\nThe daemon ensures Witness is always running."
}
]
}

View File

@@ -1,212 +1,225 @@
description = """
Per-rig worker monitor patrol loop using the Christmas Ornament pattern.
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.
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.
This molecule uses dynamic bonding to spawn mol-polecat-arm for each worker, enabling parallel inspection with a fanout gate for aggregation.
## Design Philosophy
## The Christmas Ornament Shape
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)
```
★ mol-witness-patrol (trunk)
/|\\
┌────────┘ │ └────────┐
PREFLIGHT DISCOVERY CLEANUP
│ │ │
inbox-check survey aggregate (WaitsFor: all-children)
check-refnry │ save-state
load-state │ generate-summary
↓ context-check
┌───────┼───────┐ burn-or-loop
● ● ● mol-polecat-arm (dynamic)
ace nux toast
```"""
inbox-check ─► process-cleanups ─► check-refinery ─► survey-workers
┌──────────────────────────────────────────────────┘
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
[[steps]]
id = "inbox-check"
title = "Process witness mail"
description = """
Process witness mail: lifecycle requests, help requests.
Check inbox and handle messages.
```bash
gt mail inbox
```
Handle by message type:
- **LIFECYCLE/Shutdown**: Queue for pre-kill verification
- **Blocked/Help**: Assess if resolvable or escalate
- **HANDOFF**: Load predecessor state
- **Work complete**: Verify issue closed, proceed to pre-kill
For each message:
Record any pending actions for later steps. Mark messages as processed when complete."""
id = "inbox-check"
title = "Process witness mail"
**POLECAT_DONE / LIFECYCLE:Shutdown**:
Create a cleanup wisp for this polecat:
```bash
bd create --wisp --title "cleanup:<polecat>" \
--description "Verify and cleanup polecat <name>" \
--labels cleanup,polecat:<name>
```
The wisp's existence IS the pending cleanup. Process in next step.
Mark mail as read.
**HELP / Blocked**:
Assess the request. Can you help? If not, escalate to Mayor:
```bash
gt mail send mayor/ -s "Escalation: <polecat> needs help" -m "<details>"
```
**HANDOFF**:
Read predecessor context. Continue from where they left off."""
[[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:
1. **Extract polecat name** from wisp title/labels
2. **Pre-kill verification**:
```bash
cd polecats/<name>
git status # Must be clean
git log origin/main..HEAD # No unpushed commits
bd show <assigned-issue> # Issue closed or deferred
```
3. **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
4. **If clean**: Execute cleanup
```bash
gt session kill <rig>/polecats/<name>
# Worktree removal handled by session kill
```
Then burn the cleanup wisp:
```bash
bd close <wisp-id> # or bd burn <wisp-id>
```
5. **If dirty**: Leave wisp open, log the issue, retry next cycle.
**Parallelism**: Use Task tool subagents to process multiple cleanups concurrently.
Each cleanup is independent - perfect for parallel execution."""
[[steps]]
id = "check-refinery"
title = "Ensure refinery is alive"
needs = ["process-cleanups"]
description = """
Ensure the refinery is alive and processing merge requests.
**Redundant system**: This check runs in both gt spawn and Witness patrol to ensure the merge queue processor stays operational.
```bash
# Check if refinery session is running
# Check if refinery session exists
gt session status <rig>/refinery
# Check for merge requests in queue
# Check for pending merge requests
bd list --type=merge-request --status=open
```
If merge requests are waiting AND refinery is not running:
If MRs waiting AND refinery not running:
```bash
gt session start <rig>/refinery
gt mail send <rig>/refinery -s \"PATROL: Wake up\" -m \"Merge requests in queue. Please process.\"
gt mail send <rig>/refinery -s "PATROL: Wake up" \
-m "Merge requests in queue. Please process."
```
If refinery is running but queue is non-empty for >30 min, send nudge. This ensures polecats don't wait forever for their branches to merge."""
id = "check-refinery"
needs = ["inbox-check"]
title = "Ensure refinery is alive"
If refinery running but queue stale (>30 min), send nudge."""
[[steps]]
description = """
Read handoff bead and get nudge counts.
Load persistent state from the witness handoff bead:
- Active workers and their status from last cycle
- Nudge counts per worker per issue
- Last nudge timestamps
- Pending escalations
```bash
bd show <handoff-bead-id>
```
If no handoff exists (fresh start), initialize empty state. This state persists across wisp burns and session cycles."""
id = "load-state"
id = "survey-workers"
title = "Inspect all active polecats"
needs = ["check-refinery"]
title = "Load persisted patrol state"
[[steps]]
description = """
List polecats and bond mol-polecat-arm for each one.
Survey all polecats and take action on stuck workers.
```bash
# Get list of polecats
gt polecat list <rig>
```
For each polecat discovered, dynamically bond an inspection arm:
**For each polecat, assess:**
1. **Capture tmux state**:
```bash
# Bond mol-polecat-arm for each polecat
for polecat in $(gt polecat list <rig> --names); do
bd mol bond mol-polecat-arm $PATROL_WISP_ID \\
--ref arm-$polecat \\
--var polecat_name=$polecat \\
--var rig=<rig>
done
tmux capture-pane -t gt-<rig>-<name> -p | tail -50
```
This creates child wisps like:
- patrol-x7k.arm-ace (5 steps)
- patrol-x7k.arm-nux (5 steps)
- patrol-x7k.arm-toast (5 steps)
2. **Determine status** (ZFC - you make the judgment):
- **working**: Recent tool calls, active processing
- **idle**: At prompt, no recent activity
- **error**: Showing errors or stack traces
- **done**: Showing completion indicators (should have sent POLECAT_DONE)
Each arm runs in PARALLEL. The aggregate step will wait for all to complete.
3. **Check beads progress**:
```bash
bd hook --agent <rig>/polecats/<name> # What step are they on?
```
- Has their step changed since you last looked?
- How long on current step? (Check step timestamps)
If no polecats are found, this step completes immediately with no children."""
id = "survey-workers"
needs = ["load-state"]
title = "Survey all polecats (fanout)"
4. **Decide action** (fresh judgment each cycle, no counters):
| Observation | Action |
|-------------|--------|
| Actively working | None |
| Just started step (<5 min) | None |
| Idle 5-15 min, same step | Gentle nudge |
| Idle 15+ min, same step | Direct nudge with deadline |
| Idle 30+ min despite nudges | Escalate to Mayor |
| Showing errors | Assess severity, help or escalate |
| Says "done" but no POLECAT_DONE | Nudge to send completion mail |
5. **Execute nudges**:
```bash
gt nudge <rig>/polecats/<name> "How's progress on <step>? Need help?"
```
6. **Escalate stuck workers**:
```bash
gt mail send mayor/ -s "Escalation: <polecat> stuck" \
-m "Polecat <name> has been idle on <step> for <duration>.
Nudges ineffective. Please intervene."
```
**Parallelism**: Use Task tool subagents to inspect multiple polecats concurrently.
Launch one subagent per polecat for capture/assess/decide/act cycle.
**No persistent state**: Each cycle is a fresh observation.
"Nudge count" is replaced by "how long stuck on same step" which is discoverable from beads timestamps."""
[[steps]]
description = """
Collect outcomes from all polecat inspection arms.
This is a **fanout gate** - it cannot proceed until ALL dynamically-bonded polecat arms have completed their inspection cycles.
Once all arms complete, collect their outcomes:
- Actions taken per polecat (nudge, kill, escalate, none)
- Updated nudge counts
- Any errors or issues discovered
Build the consolidated state for save-state."""
id = "aggregate"
id = "context-check"
title = "Check own context limit"
needs = ["survey-workers"]
title = "Aggregate arm results"
waits_for = "all-children"
[[steps]]
description = """
Update handoff bead with new states.
Persist state to the witness handoff bead:
- Updated worker statuses from all arms
- Current nudge counts per worker
- Nudge timestamps
- Actions taken this cycle
- Pending items for next cycle
```bash
bd update <handoff-bead-id> --description=\"<serialized state>\"
```
This state survives wisp burns and session cycles."""
id = "save-state"
needs = ["aggregate"]
title = "Persist patrol state"
[[steps]]
description = """
Summarize this patrol cycle for digest.
Include:
- Workers inspected (count, names)
- Nudges sent (count, to whom)
- Sessions killed (count, names)
- Escalations (count, issues)
- Issues found (brief descriptions)
- Actions pending for next cycle
This becomes the digest when the patrol wisp is squashed."""
id = "generate-summary"
needs = ["save-state"]
title = "Generate handoff summary"
[[steps]]
description = """
Check own context usage.
If context is HIGH (>80%):
- Ensure state is saved to handoff bead
- Prepare for burn/respawn
- Ensure any notes are written to handoff mail
- Prepare for session restart
If context is LOW:
- Can continue patrolling"""
id = "context-check"
needs = ["generate-summary"]
title = "Check own context limit"
[[steps]]
id = "loop-or-exit"
title = "Loop or exit for respawn"
needs = ["context-check"]
description = """
End of patrol cycle decision.
If context is LOW:
- Burn this wisp (no audit trail needed for patrol cycles)
**If context LOW**:
- Sleep briefly to avoid tight loop (30-60 seconds)
- Return to inbox-check step
- Continue patrolling
If context is HIGH:
- Burn wisp with summary digest
- Exit cleanly (daemon will respawn fresh Witness)
**If context HIGH**:
- Write handoff mail to self with any notable observations:
```bash
bd mol burn # Destroy ephemeral wisp
gt handoff -s "Witness patrol handoff" -m "<observations>"
```
- Exit cleanly (daemon respawns fresh Witness)
The daemon ensures Witness is always running."""
id = "burn-or-loop"
needs = ["context-check"]
title = "Burn and respawn or loop"

File diff suppressed because it is too large Load Diff