feat: Add polecat agent bead lifecycle (gt-rxa7v)
Create ephemeral agent beads for ZFC-compliant polecat state tracking. - Add AgentFields struct and helpers to beads package - CreateAgentBead: Creates agent bead with role_type/rig/agent_state - UpdateAgentState: Updates agent_state and hook_bead fields - DeleteAgentBead: Hard-deletes ephemeral agent bead - GetAgentBead: Retrieves and parses agent bead - Integrate lifecycle in polecat manager: - Add(): Creates gt-polecat-<rig>-<name> bead with state=spawning - Recreate(): Deletes old bead, creates fresh with state=spawning - RemoveWithOptions(): Deletes agent bead on nuke This enables Witness to read polecat state from beads instead of tmux scraping. State updates (spawning→working→done) are done by polecats via bd agent state (separate beads CLI enhancement). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -82,6 +82,12 @@ func (m *Manager) assigneeID(name string) string {
|
||||
return fmt.Sprintf("%s/%s", m.rig.Name, name)
|
||||
}
|
||||
|
||||
// agentBeadID returns the agent bead ID for a polecat.
|
||||
// Format: "gt-polecat-<rig>-<name>" (e.g., "gt-polecat-gastown-Toast")
|
||||
func (m *Manager) agentBeadID(name string) string {
|
||||
return fmt.Sprintf("gt-polecat-%s-%s", m.rig.Name, name)
|
||||
}
|
||||
|
||||
// repoBase returns the git directory and Git object to use for worktree operations.
|
||||
// Prefers the shared bare repo (.repo.git) if it exists, otherwise falls back to mayor/rig.
|
||||
// The bare repo architecture allows all worktrees (refinery, polecats) to share branch visibility.
|
||||
@@ -155,6 +161,19 @@ func (m *Manager) Add(name string) (*Polecat, error) {
|
||||
fmt.Printf("Warning: could not set up shared beads: %v\n", err)
|
||||
}
|
||||
|
||||
// Create agent bead for ZFC compliance (self-report state).
|
||||
// State starts as "spawning" - will be updated to "working" when Claude starts.
|
||||
agentID := m.agentBeadID(name)
|
||||
_, err = m.beads.CreateAgentBead(agentID, agentID, &beads.AgentFields{
|
||||
RoleType: "polecat",
|
||||
Rig: m.rig.Name,
|
||||
AgentState: "spawning",
|
||||
})
|
||||
if err != nil {
|
||||
// Non-fatal - log warning but continue
|
||||
fmt.Printf("Warning: could not create agent bead: %v\n", err)
|
||||
}
|
||||
|
||||
// Return polecat with derived state (no issue assigned yet = idle)
|
||||
// State is derived from beads, not stored in state.json
|
||||
now := time.Now()
|
||||
@@ -228,6 +247,15 @@ func (m *Manager) RemoveWithOptions(name string, force, nuclear bool) error {
|
||||
m.namePool.Release(name)
|
||||
_ = m.namePool.Save()
|
||||
|
||||
// Delete agent bead (non-fatal: may not exist or beads may not be available)
|
||||
agentID := m.agentBeadID(name)
|
||||
if err := m.beads.DeleteAgentBead(agentID); err != nil {
|
||||
// Only log if not "not found" - it's ok if it doesn't exist
|
||||
if !errors.Is(err, beads.ErrNotFound) {
|
||||
fmt.Printf("Warning: could not delete agent bead %s: %v\n", agentID, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -286,6 +314,14 @@ func (m *Manager) Recreate(name string, force bool) (*Polecat, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// Delete old agent bead before recreation (non-fatal)
|
||||
agentID := m.agentBeadID(name)
|
||||
if err := m.beads.DeleteAgentBead(agentID); err != nil {
|
||||
if !errors.Is(err, beads.ErrNotFound) {
|
||||
fmt.Printf("Warning: could not delete old agent bead %s: %v\n", agentID, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the worktree (use force for git worktree removal)
|
||||
if err := repoGit.WorktreeRemove(polecatPath, true); err != nil {
|
||||
// Fall back to direct removal
|
||||
@@ -313,6 +349,16 @@ func (m *Manager) Recreate(name string, force bool) (*Polecat, error) {
|
||||
fmt.Printf("Warning: could not set up shared beads: %v\n", err)
|
||||
}
|
||||
|
||||
// Create fresh agent bead for ZFC compliance
|
||||
_, err = m.beads.CreateAgentBead(agentID, agentID, &beads.AgentFields{
|
||||
RoleType: "polecat",
|
||||
Rig: m.rig.Name,
|
||||
AgentState: "spawning",
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Printf("Warning: could not create agent bead: %v\n", err)
|
||||
}
|
||||
|
||||
// Return fresh polecat
|
||||
now := time.Now()
|
||||
return &Polecat{
|
||||
|
||||
Reference in New Issue
Block a user