From f3a6ef6ca5e2a2ef29b6a5fa78cfa9526605fd6c Mon Sep 17 00:00:00 2001 From: Steve Yegge Date: Sun, 28 Dec 2025 09:41:44 -0800 Subject: [PATCH] feat: Witness reads polecat state from agent beads (gt-gizsv) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changes: 1. Fix reportAgentState in prime.go to use beads API directly instead of non-existent `bd agent state` command. Agents now properly self-report their state to their agent beads on startup. 2. Update witness patrol survey-workers step to use agent beads: - List polecats via `bd list --type=agent --json` - Filter by role_type: polecat in description - Check agent_state field (running/idle/stuck/done) - Trust agent-reported state (ZFC principle) No more PID/tmux inference for polecat state - agents self-report. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .../formulas/mol-witness-patrol.formula.toml | 74 +++++++++++-------- internal/cmd/prime.go | 19 +++-- 2 files changed, 51 insertions(+), 42 deletions(-) diff --git a/.beads/formulas/mol-witness-patrol.formula.toml b/.beads/formulas/mol-witness-patrol.formula.toml index b647e66b..1eecbbde 100644 --- a/.beads/formulas/mol-witness-patrol.formula.toml +++ b/.beads/formulas/mol-witness-patrol.formula.toml @@ -133,61 +133,71 @@ id = "survey-workers" title = "Inspect all active polecats" needs = ["check-refinery"] description = """ -Survey all polecats and take action on stuck workers. +Survey all polecats using agent beads (ZFC: trust what agents report). + +**Step 1: List polecat agent beads** ```bash -gt polecat list +bd list --type=agent --json ``` -**For each polecat, assess:** +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: ` -1. **Capture tmux state**: +**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 | + +**Step 3: For running polecats, assess progress** + +Check the hook_bead field to see what they're working on: ```bash -tmux capture-pane -t gt-- -p | tail -50 +bd show # See current step/issue ``` -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) - -3. **Check beads progress**: +You can also verify they're responsive: ```bash -bd hook --agent /polecats/ # What step are they on? +tmux capture-pane -t gt-- -p | tail -20 ``` - - Has their step changed since you last looked? - - How long on current step? (Check step timestamps) -4. **Decide action** (fresh judgment each cycle, no counters): +Look for: +- Recent tool activity → making progress +- Idle at prompt → may need nudge +- Error messages → may need help + +**Step 4: Decide action** | 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 | +| 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, cleanup pending | Verify cleanup wisp exists | -5. **Execute nudges**: +**Step 5: Execute nudges** ```bash -gt nudge /polecats/ "How's progress on ? Need help?" +gt nudge /polecats/ "How's progress? Need help?" ``` -6. **Escalate stuck workers**: +**Step 6: Escalate if needed** ```bash -gt mail send mayor/ -s "Escalation: stuck" \ - -m "Polecat has been idle on for . - Nudges ineffective. Please intervene." +gt mail send mayor/ -s "Escalation: stuck" \\ + -m "Polecat reports stuck. 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.""" +**ZFC Principle**: Trust agent_state from beads. Don't infer state from PID/tmux.""" [[steps]] id = "context-check" diff --git a/internal/cmd/prime.go b/internal/cmd/prime.go index df0a18de..050af2ad 100644 --- a/internal/cmd/prime.go +++ b/internal/cmd/prime.go @@ -1052,7 +1052,7 @@ func acquireIdentityLock(ctx RoleContext) error { return nil } -// reportAgentState calls bd agent state to report the agent's current state. +// reportAgentState updates the agent bead to report the agent's current state. // This implements ZFC-compliant self-reporting of agent state. // Agents call this on startup (running) and shutdown (stopped). func reportAgentState(ctx RoleContext, state string) { @@ -1061,15 +1061,14 @@ func reportAgentState(ctx RoleContext, state string) { return } - // Call bd agent state - // Use --no-daemon to avoid issues when daemon isn't running - cmd := exec.Command("bd", "--no-daemon", "agent", "state", agentBeadID, state) - cmd.Dir = ctx.WorkDir - cmd.Stdout = nil - cmd.Stderr = nil - - // Run silently - don't fail prime if state reporting fails - _ = cmd.Run() + // Use the beads API directly to update agent state + // This is more reliable than shelling out to bd + bd := beads.New(ctx.WorkDir) + if err := bd.UpdateAgentState(agentBeadID, state, nil); err != nil { + // Silently ignore errors - don't fail prime if state reporting fails + // This can fail if beads isn't set up or agent bead doesn't exist + return + } } // getAgentBeadID returns the agent bead ID for the current role.