feat: Complete agent bead lifecycle for ZFC compliance

Changes:
1. prime.go: Create agent beads on first prime for all roles including crew
2. done.go: Update agent state to done/stuck/idle when work completes
3. sling.go: Populate hook_bead when work is assigned to agents
4. mol-witness-patrol.formula.toml: Document dead and spawning states

Closes: gt-hymm0, gt-0lop3, gt-59k2x, gt-c4j4j

🤖 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-28 09:56:59 -08:00
parent 76b969fb2e
commit 34ccd121e8
4 changed files with 187 additions and 3 deletions

View File

@@ -223,5 +223,55 @@ func runDone(cmd *cobra.Command, args []string) error {
// Log done event
LogDone(townRoot, sender, issueID)
// Update agent bead state (ZFC: self-report completion)
updateAgentStateOnDone(cwd, townRoot, exitType, issueID)
return nil
}
// updateAgentStateOnDone updates the agent bead state when work is complete.
// Maps exit type to agent state:
// - COMPLETED → "done"
// - ESCALATED → "stuck"
// - DEFERRED → "idle"
func updateAgentStateOnDone(cwd, townRoot, exitType, issueID string) {
// Get role context
roleInfo, err := GetRoleWithContext(cwd, townRoot)
if err != nil {
return
}
ctx := RoleContext{
Role: roleInfo.Role,
Rig: roleInfo.Rig,
Polecat: roleInfo.Polecat,
TownRoot: townRoot,
WorkDir: cwd,
}
agentBeadID := getAgentBeadID(ctx)
if agentBeadID == "" {
return
}
// Map exit type to agent state
var newState string
switch exitType {
case ExitCompleted:
newState = "done"
case ExitEscalated:
newState = "stuck"
case ExitDeferred:
newState = "idle"
default:
return
}
// Update agent bead with new state and clear hook_bead (work is done)
bd := beads.New(cwd)
emptyHook := ""
if err := bd.UpdateAgentState(agentBeadID, newState, &emptyHook); err != nil {
// Silently ignore - beads might not be configured
return
}
}