diff --git a/internal/cmd/crew_add.go b/internal/cmd/crew_add.go index 5a1d5c7e..6e4f9bff 100644 --- a/internal/cmd/crew_add.go +++ b/internal/cmd/crew_add.go @@ -5,6 +5,7 @@ import ( "path/filepath" "github.com/spf13/cobra" + "github.com/steveyegge/gastown/internal/beads" "github.com/steveyegge/gastown/internal/config" "github.com/steveyegge/gastown/internal/crew" "github.com/steveyegge/gastown/internal/git" @@ -77,6 +78,27 @@ func runCrewAdd(cmd *cobra.Command, args []string) error { fmt.Printf(" Branch: %s\n", worker.Branch) fmt.Printf(" Mail: %s/mail/\n", worker.ClonePath) + // Create agent bead for the crew worker + rigBeadsPath := filepath.Join(r.Path, "mayor", "rig") + bd := beads.New(rigBeadsPath) + crewID := fmt.Sprintf("gt-crew-%s-%s", rigName, name) + if _, err := bd.Show(crewID); err != nil { + // Agent bead doesn't exist, create it + fields := &beads.AgentFields{ + RoleType: "crew", + Rig: rigName, + AgentState: "idle", + RoleBead: crewID + "-role", + } + desc := fmt.Sprintf("Crew worker %s in %s - human-managed persistent workspace.", name, rigName) + if _, err := bd.CreateAgentBead(crewID, desc, fields); err != nil { + // Non-fatal: warn but don't fail the add + fmt.Printf(" %s\n", style.Dim.Render(fmt.Sprintf("Warning: could not create agent bead: %v", err))) + } else { + fmt.Printf(" Agent bead: %s\n", crewID) + } + } + fmt.Printf("\n%s\n", style.Dim.Render("Start working with: cd "+worker.ClonePath)) return nil diff --git a/internal/doctor/agent_beads_check.go b/internal/doctor/agent_beads_check.go index 4400e6a2..ed7d425e 100644 --- a/internal/doctor/agent_beads_check.go +++ b/internal/doctor/agent_beads_check.go @@ -2,6 +2,7 @@ package doctor import ( "fmt" + "os" "path/filepath" "strings" @@ -12,8 +13,9 @@ import ( // This includes: // - Global agents (deacon, mayor) - stored in first rig's beads // - Per-rig agents (witness, refinery) - stored in each rig's beads +// - Crew workers - stored in each rig's beads // -// Agent beads are created by gt rig add (see gt-h3hak, gt-pinkq). +// Agent beads are created by gt rig add (see gt-h3hak, gt-pinkq) and gt crew add. // // NOTE: Currently, the beads library validates that agent IDs must start // with 'gt-'. Rigs with different prefixes (like 'bd-') cannot have agent @@ -113,6 +115,16 @@ func (c *AgentBeadsCheck) Run(ctx *CheckContext) *CheckResult { } checked++ + // Check crew worker agents + crewWorkers := listCrewWorkers(ctx.TownRoot, rigName) + for _, workerName := range crewWorkers { + crewID := fmt.Sprintf("%s-crew-%s-%s", prefix, rigName, workerName) + if _, err := bd.Show(crewID); err != nil { + missing = append(missing, crewID) + } + checked++ + } + // Check global agents in first rig if rigName == firstRigName { deaconID := firstPrefix + "-deacon" @@ -236,6 +248,24 @@ func (c *AgentBeadsCheck) Fix(ctx *CheckContext) error { } } + // Create crew worker agents if missing + crewWorkers := listCrewWorkers(ctx.TownRoot, rigName) + for _, workerName := range crewWorkers { + crewID := fmt.Sprintf("%s-crew-%s-%s", prefix, rigName, workerName) + if _, err := bd.Show(crewID); err != nil { + fields := &beads.AgentFields{ + RoleType: "crew", + Rig: rigName, + AgentState: "idle", + RoleBead: crewID + "-role", + } + desc := fmt.Sprintf("Crew worker %s in %s - human-managed persistent workspace.", workerName, rigName) + if _, err := bd.CreateAgentBead(crewID, desc, fields); err != nil { + return fmt.Errorf("creating %s: %w", crewID, err) + } + } + } + // Create global agents in first rig if missing if rigName == firstRigName { deaconID := firstPrefix + "-deacon" @@ -270,3 +300,20 @@ func (c *AgentBeadsCheck) Fix(ctx *CheckContext) error { return nil } + +// listCrewWorkers returns the names of all crew workers in a rig. +func listCrewWorkers(townRoot, rigName string) []string { + crewDir := filepath.Join(townRoot, rigName, "crew") + entries, err := os.ReadDir(crewDir) + if err != nil { + return nil // No crew directory or can't read it + } + + var workers []string + for _, entry := range entries { + if entry.IsDir() && !strings.HasPrefix(entry.Name(), ".") { + workers = append(workers, entry.Name()) + } + } + return workers +}