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 {
|
} else {
|
||||||
fmt.Printf(" ✓ Initialized .beads/ (town-level beads with gm- prefix)\n")
|
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)
|
// Initialize git if requested (--git or --github implies --git)
|
||||||
@@ -246,3 +251,4 @@ func initTownBeads(townPath string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/steveyegge/gastown/internal/beads"
|
||||||
"github.com/steveyegge/gastown/internal/config"
|
"github.com/steveyegge/gastown/internal/config"
|
||||||
"github.com/steveyegge/gastown/internal/git"
|
"github.com/steveyegge/gastown/internal/git"
|
||||||
"github.com/steveyegge/gastown/internal/templates"
|
"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)
|
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
|
// Seed patrol molecules for this rig
|
||||||
if err := m.seedPatrolMolecules(rigPath); err != nil {
|
if err := m.seedPatrolMolecules(rigPath); err != nil {
|
||||||
// Non-fatal: log warning but continue
|
// Non-fatal: log warning but continue
|
||||||
@@ -376,6 +385,83 @@ func (m *Manager) initBeads(rigPath, prefix string) error {
|
|||||||
return nil
|
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.
|
// ensureGitignoreEntry adds an entry to .gitignore if it doesn't already exist.
|
||||||
func (m *Manager) ensureGitignoreEntry(gitignorePath, entry string) error {
|
func (m *Manager) ensureGitignoreEntry(gitignorePath, entry string) error {
|
||||||
// Read existing content
|
// Read existing content
|
||||||
|
|||||||
Reference in New Issue
Block a user