feat: gt rig add creates agent beads (gt-h3hak, gt-pinkq)
Bootstrap now creates agent beads for ZFC compliance: - Always: <prefix>-witness-<rig>, <prefix>-refinery-<rig> - First rig only: <prefix>-deacon, <prefix>-mayor Agent beads are created in the rig's beads database (not town beads) because the daemon looks up beads by prefix routing. Changes: - internal/rig/manager.go: Added initAgentBeads() function - internal/cmd/install.go: Added comment explaining why beads aren't created here (no rig exists yet at install time) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -174,6 +174,11 @@ func runInstall(cmd *cobra.Command, args []string) error {
|
||||
} else {
|
||||
fmt.Printf(" ✓ Initialized .beads/ (town-level beads with gm- prefix)\n")
|
||||
}
|
||||
|
||||
// NOTE: Agent beads (gt-deacon, gt-mayor) are created by gt rig add,
|
||||
// not here. This is because the daemon looks up beads by prefix routing,
|
||||
// and no rig exists yet at install time. The first rig added will get
|
||||
// these global agent beads in its beads database.
|
||||
}
|
||||
|
||||
// Initialize git if requested (--git or --github implies --git)
|
||||
@@ -246,3 +251,4 @@ func initTownBeads(townPath string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/steveyegge/gastown/internal/beads"
|
||||
"github.com/steveyegge/gastown/internal/config"
|
||||
"github.com/steveyegge/gastown/internal/git"
|
||||
"github.com/steveyegge/gastown/internal/templates"
|
||||
@@ -291,6 +292,14 @@ func (m *Manager) AddRig(opts AddRigOptions) (*Rig, error) {
|
||||
return nil, fmt.Errorf("initializing beads: %w", err)
|
||||
}
|
||||
|
||||
// Create agent beads for this rig (witness, refinery) and
|
||||
// global agents (deacon, mayor) if this is the first rig.
|
||||
isFirstRig := len(m.config.Rigs) == 0
|
||||
if err := m.initAgentBeads(rigPath, opts.Name, opts.BeadsPrefix, isFirstRig); err != nil {
|
||||
// Non-fatal: log warning but continue
|
||||
fmt.Printf(" Warning: Could not create agent beads: %v\n", err)
|
||||
}
|
||||
|
||||
// Seed patrol molecules for this rig
|
||||
if err := m.seedPatrolMolecules(rigPath); err != nil {
|
||||
// Non-fatal: log warning but continue
|
||||
@@ -376,6 +385,83 @@ func (m *Manager) initBeads(rigPath, prefix string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// initAgentBeads creates agent beads for this rig and optionally global agents.
|
||||
// - Always creates: <prefix>-witness-<rig>, <prefix>-refinery-<rig>
|
||||
// - First rig only: <prefix>-deacon, <prefix>-mayor
|
||||
//
|
||||
// Agent beads track lifecycle state for ZFC compliance (gt-h3hak, gt-pinkq).
|
||||
func (m *Manager) initAgentBeads(rigPath, rigName, prefix string, isFirstRig bool) error {
|
||||
// Run bd commands from mayor/rig which has the beads database
|
||||
mayorRigPath := filepath.Join(rigPath, "mayor", "rig")
|
||||
bd := beads.New(mayorRigPath)
|
||||
|
||||
// Define agents to create
|
||||
type agentDef struct {
|
||||
id string
|
||||
roleType string
|
||||
rig string
|
||||
desc string
|
||||
}
|
||||
|
||||
var agents []agentDef
|
||||
|
||||
// Always create rig-specific agents
|
||||
agents = append(agents,
|
||||
agentDef{
|
||||
id: fmt.Sprintf("%s-witness-%s", prefix, rigName),
|
||||
roleType: "witness",
|
||||
rig: rigName,
|
||||
desc: fmt.Sprintf("Witness for %s - monitors polecat health and progress.", rigName),
|
||||
},
|
||||
agentDef{
|
||||
id: fmt.Sprintf("%s-refinery-%s", prefix, rigName),
|
||||
roleType: "refinery",
|
||||
rig: rigName,
|
||||
desc: fmt.Sprintf("Refinery for %s - processes merge queue.", rigName),
|
||||
},
|
||||
)
|
||||
|
||||
// First rig also gets global agents (deacon, mayor)
|
||||
if isFirstRig {
|
||||
agents = append(agents,
|
||||
agentDef{
|
||||
id: prefix + "-deacon",
|
||||
roleType: "deacon",
|
||||
rig: "",
|
||||
desc: "Deacon (daemon beacon) - receives mechanical heartbeats, runs town plugins and monitoring.",
|
||||
},
|
||||
agentDef{
|
||||
id: prefix + "-mayor",
|
||||
roleType: "mayor",
|
||||
rig: "",
|
||||
desc: "Mayor - global coordinator, handles cross-rig communication and escalations.",
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
for _, agent := range agents {
|
||||
// Check if already exists
|
||||
if _, err := bd.Show(agent.id); err == nil {
|
||||
continue // Already exists
|
||||
}
|
||||
|
||||
fields := &beads.AgentFields{
|
||||
RoleType: agent.roleType,
|
||||
Rig: agent.rig,
|
||||
AgentState: "idle",
|
||||
HookBead: "",
|
||||
RoleBead: agent.id + "-role",
|
||||
}
|
||||
|
||||
if _, err := bd.CreateAgentBead(agent.id, agent.desc, fields); err != nil {
|
||||
return fmt.Errorf("creating %s: %w", agent.id, err)
|
||||
}
|
||||
fmt.Printf(" ✓ Created agent bead: %s\n", agent.id)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ensureGitignoreEntry adds an entry to .gitignore if it doesn't already exist.
|
||||
func (m *Manager) ensureGitignoreEntry(gitignorePath, entry string) error {
|
||||
// Read existing content
|
||||
|
||||
Reference in New Issue
Block a user