fix(daemon,beads): use correct agent bead ID format and bd create flags

Two fixes in this commit:

1. daemon/lifecycle.go: Fix agent bead ID pattern for GUPP/orphaned work checks
   - Wrong: gt-polecat-<rig>-<name> (e.g., gt-polecat-gastown-nux)
   - Correct: <prefix>-<rig>-polecat-<name> (e.g., gt-gastown-polecat-nux)
   - Use config.GetRigPrefix() instead of hardcoding gt prefix
   - Use beads.ParseAgentBeadID() in extractRigFromAgentID

2. beads/beads.go: Fix invalid --add-label flag in bd create calls
   - bd create uses --labels, not --add-label
   - bd update uses --add-label (unchanged, was correct)
   - Fixed Create, CreateWithID, CreateAgentBead, CreateRigBead

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
nux
2026-01-09 21:40:30 -08:00
committed by beads/crew/giles
parent c94d59dca7
commit c4fcdd88c8
2 changed files with 20 additions and 20 deletions

View File

@@ -666,7 +666,7 @@ func (b *Beads) Create(opts CreateOptions) (*Issue, error) {
} }
// Type is deprecated: convert to gt:<type> label // Type is deprecated: convert to gt:<type> label
if opts.Type != "" { if opts.Type != "" {
args = append(args, "--add-label=gt:"+opts.Type) args = append(args, "--labels=gt:"+opts.Type)
} }
if opts.Priority >= 0 { if opts.Priority >= 0 {
args = append(args, fmt.Sprintf("--priority=%d", opts.Priority)) args = append(args, fmt.Sprintf("--priority=%d", opts.Priority))
@@ -710,7 +710,7 @@ func (b *Beads) CreateWithID(id string, opts CreateOptions) (*Issue, error) {
} }
// Type is deprecated: convert to gt:<type> label // Type is deprecated: convert to gt:<type> label
if opts.Type != "" { if opts.Type != "" {
args = append(args, "--add-label=gt:"+opts.Type) args = append(args, "--labels=gt:"+opts.Type)
} }
if opts.Priority >= 0 { if opts.Priority >= 0 {
args = append(args, fmt.Sprintf("--priority=%d", opts.Priority)) args = append(args, fmt.Sprintf("--priority=%d", opts.Priority))
@@ -1137,7 +1137,7 @@ func (b *Beads) CreateAgentBead(id, title string, fields *AgentFields) (*Issue,
"--id=" + id, "--id=" + id,
"--title=" + title, "--title=" + title,
"--description=" + description, "--description=" + description,
"--add-label=gt:agent", "--labels=gt:agent",
} }
// Default actor from BD_ACTOR env var for provenance tracking // Default actor from BD_ACTOR env var for provenance tracking
@@ -1941,7 +1941,7 @@ func (b *Beads) CreateRigBead(id, title string, fields *RigFields) (*Issue, erro
"--id=" + id, "--id=" + id,
"--title=" + title, "--title=" + title,
"--description=" + description, "--description=" + description,
"--add-label=gt:rig", "--labels=gt:rig",
} }
// Default actor from BD_ACTOR env var for provenance tracking // Default actor from BD_ACTOR env var for provenance tracking

View File

@@ -748,7 +748,7 @@ func (d *Daemon) checkGUPPViolations() {
// checkRigGUPPViolations checks polecats in a specific rig for GUPP violations. // checkRigGUPPViolations checks polecats in a specific rig for GUPP violations.
func (d *Daemon) checkRigGUPPViolations(rigName string) { func (d *Daemon) checkRigGUPPViolations(rigName string) {
// List polecat agent beads for this rig // List polecat agent beads for this rig
// Pattern: gt-polecat-<rig>-<name> // Pattern: <prefix>-<rig>-polecat-<name> (e.g., gt-gastown-polecat-Toast)
cmd := exec.Command("bd", "list", "--type=agent", "--json") cmd := exec.Command("bd", "list", "--type=agent", "--json")
cmd.Dir = d.config.TownRoot cmd.Dir = d.config.TownRoot
@@ -770,7 +770,10 @@ func (d *Daemon) checkRigGUPPViolations(rigName string) {
return return
} }
prefix := "gt-polecat-" + rigName + "-" // Use the rig's configured prefix (e.g., "gt" for gastown, "bd" for beads)
rigPrefix := config.GetRigPrefix(d.config.TownRoot, rigName)
// Pattern: <prefix>-<rig>-polecat-<name>
prefix := rigPrefix + "-" + rigName + "-polecat-"
for _, agent := range agents { for _, agent := range agents {
// Only check polecats for this rig // Only check polecats for this rig
if !strings.HasPrefix(agent.ID, prefix) { if !strings.HasPrefix(agent.ID, prefix) {
@@ -784,7 +787,7 @@ func (d *Daemon) checkRigGUPPViolations(rigName string) {
} }
// Per gt-zecmc: derive running state from tmux, not agent_state // Per gt-zecmc: derive running state from tmux, not agent_state
// Extract polecat name from agent ID (gt-polecat-<rig>-<name> -> <name>) // Extract polecat name from agent ID (<prefix>-<rig>-polecat-<name> -> <name>)
polecatName := strings.TrimPrefix(agent.ID, prefix) polecatName := strings.TrimPrefix(agent.ID, prefix)
sessionName := fmt.Sprintf("gt-%s-%s", rigName, polecatName) sessionName := fmt.Sprintf("gt-%s-%s", rigName, polecatName)
@@ -860,7 +863,10 @@ func (d *Daemon) checkRigOrphanedWork(rigName string) {
return return
} }
prefix := "gt-polecat-" + rigName + "-" // Use the rig's configured prefix (e.g., "gt" for gastown, "bd" for beads)
rigPrefix := config.GetRigPrefix(d.config.TownRoot, rigName)
// Pattern: <prefix>-<rig>-polecat-<name>
prefix := rigPrefix + "-" + rigName + "-polecat-"
for _, agent := range agents { for _, agent := range agents {
// Only check polecats for this rig // Only check polecats for this rig
if !strings.HasPrefix(agent.ID, prefix) { if !strings.HasPrefix(agent.ID, prefix) {
@@ -890,21 +896,15 @@ func (d *Daemon) checkRigOrphanedWork(rigName string) {
} }
// extractRigFromAgentID extracts the rig name from a polecat agent ID. // extractRigFromAgentID extracts the rig name from a polecat agent ID.
// Example: gt-polecat-gastown-max → gastown // Example: gt-gastown-polecat-max → gastown
func (d *Daemon) extractRigFromAgentID(agentID string) string { func (d *Daemon) extractRigFromAgentID(agentID string) string {
// Pattern: gt-polecat-<rig>-<name> // Use the beads package helper to correctly parse agent bead IDs.
if !strings.HasPrefix(agentID, "gt-polecat-") { // Pattern: <prefix>-<rig>-polecat-<name> (e.g., gt-gastown-polecat-Toast)
rig, role, _, ok := beads.ParseAgentBeadID(agentID)
if !ok || role != "polecat" {
return "" return ""
} }
return rig
rest := strings.TrimPrefix(agentID, "gt-polecat-")
// Find the rig name (everything before the last dash)
lastDash := strings.LastIndex(rest, "-")
if lastDash == -1 {
return ""
}
return rest[:lastDash]
} }
// notifyWitnessOfOrphanedWork sends a mail to the rig's witness about orphaned work. // notifyWitnessOfOrphanedWork sends a mail to the rig's witness about orphaned work.