Merge PR #32: fix(beads): fix agent bead creation during rig add
Merged with conflict resolution after PR #34. Key fixes: - Remove invalid --no-agents flag from bd init - Agent beads now created in town beads (gt-* prefix) using NewWithBeadsDir - Use canonical WitnessBeadID/RefineryBeadID functions - Update test to verify town beads usage Original PR by @PepijnSenders, conflict resolution applied. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -451,9 +451,21 @@ func (m *Manager) initBeads(rigPath, prefix string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run bd init if available, with --no-agents to skip AGENTS.md creation
|
// Build environment with explicit BEADS_DIR to prevent bd from
|
||||||
cmd := exec.Command("bd", "init", "--prefix", prefix, "--no-agents")
|
// finding a parent directory's .beads/ database
|
||||||
|
env := os.Environ()
|
||||||
|
filteredEnv := make([]string, 0, len(env)+1)
|
||||||
|
for _, e := range env {
|
||||||
|
if !strings.HasPrefix(e, "BEADS_DIR=") {
|
||||||
|
filteredEnv = append(filteredEnv, e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
filteredEnv = append(filteredEnv, "BEADS_DIR="+beadsDir)
|
||||||
|
|
||||||
|
// Run bd init if available
|
||||||
|
cmd := exec.Command("bd", "init", "--prefix", prefix)
|
||||||
cmd.Dir = rigPath
|
cmd.Dir = rigPath
|
||||||
|
cmd.Env = filteredEnv
|
||||||
_, err := cmd.CombinedOutput()
|
_, err := cmd.CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// bd might not be installed or failed, create minimal structure
|
// bd might not be installed or failed, create minimal structure
|
||||||
@@ -470,6 +482,7 @@ func (m *Manager) initBeads(rigPath, prefix string) error {
|
|||||||
// Without fingerprint, the bd daemon fails to start silently.
|
// Without fingerprint, the bd daemon fails to start silently.
|
||||||
migrateCmd := exec.Command("bd", "migrate", "--update-repo-id")
|
migrateCmd := exec.Command("bd", "migrate", "--update-repo-id")
|
||||||
migrateCmd.Dir = rigPath
|
migrateCmd.Dir = rigPath
|
||||||
|
migrateCmd.Env = filteredEnv
|
||||||
// Ignore errors - fingerprint is optional for functionality
|
// Ignore errors - fingerprint is optional for functionality
|
||||||
_, _ = migrateCmd.CombinedOutput()
|
_, _ = migrateCmd.CombinedOutput()
|
||||||
|
|
||||||
@@ -477,33 +490,19 @@ func (m *Manager) initBeads(rigPath, prefix string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// initAgentBeads creates agent beads for this rig and optionally global agents.
|
// initAgentBeads creates agent beads for this rig and optionally global agents.
|
||||||
// - Always creates: <prefix>-witness-<rig>, <prefix>-refinery-<rig>
|
// - Always creates: gt-<rig>-witness, gt-<rig>-refinery
|
||||||
// - First rig only: <prefix>-deacon, <prefix>-mayor
|
// - First rig only: gt-deacon, gt-mayor
|
||||||
|
//
|
||||||
|
// Agent beads are stored in the TOWN beads (not rig beads) because they use
|
||||||
|
// the canonical gt-* prefix for cross-rig coordination. The town beads must
|
||||||
|
// be initialized with 'gt' prefix for this to work.
|
||||||
//
|
//
|
||||||
// Agent beads track lifecycle state for ZFC compliance (gt-h3hak, gt-pinkq).
|
// Agent beads track lifecycle state for ZFC compliance (gt-h3hak, gt-pinkq).
|
||||||
func (m *Manager) initAgentBeads(rigPath, rigName, prefix string, isFirstRig bool) error {
|
func (m *Manager) initAgentBeads(rigPath, rigName, prefix string, isFirstRig bool) error {
|
||||||
// Run bd commands from the canonical beads location.
|
// Agent beads go in town beads (gt-* prefix), not rig beads.
|
||||||
// - If source repo has .beads/ tracked (mayor/rig/.beads exists), use that
|
// This enables cross-rig agent coordination via canonical IDs.
|
||||||
// - Otherwise use rig root .beads/ (created by initBeads during rig add)
|
townBeadsDir := filepath.Join(m.townRoot, ".beads")
|
||||||
mayorRigBeads := filepath.Join(rigPath, "mayor", "rig", ".beads")
|
bd := beads.NewWithBeadsDir(m.townRoot, townBeadsDir)
|
||||||
var beadsDir string
|
|
||||||
if _, err := os.Stat(mayorRigBeads); err == nil {
|
|
||||||
beadsDir = mayorRigBeads
|
|
||||||
} else {
|
|
||||||
beadsDir = filepath.Join(rigPath, ".beads")
|
|
||||||
}
|
|
||||||
prevBeadsDir, hadBeadsDir := os.LookupEnv("BEADS_DIR")
|
|
||||||
if err := os.Setenv("BEADS_DIR", beadsDir); err != nil {
|
|
||||||
return fmt.Errorf("setting BEADS_DIR: %w", err)
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
if hadBeadsDir {
|
|
||||||
_ = os.Setenv("BEADS_DIR", prevBeadsDir)
|
|
||||||
} else {
|
|
||||||
_ = os.Unsetenv("BEADS_DIR")
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
bd := beads.New(rigPath)
|
|
||||||
|
|
||||||
// Define agents to create
|
// Define agents to create
|
||||||
type agentDef struct {
|
type agentDef struct {
|
||||||
@@ -515,16 +514,18 @@ func (m *Manager) initAgentBeads(rigPath, rigName, prefix string, isFirstRig boo
|
|||||||
|
|
||||||
var agents []agentDef
|
var agents []agentDef
|
||||||
|
|
||||||
// Always create rig-specific agents (using canonical naming: prefix-rig-role-name)
|
// Always create rig-specific agents using canonical gt- prefix.
|
||||||
|
// Agent bead IDs use the gastown namespace (gt-) regardless of the rig's
|
||||||
|
// beads prefix. Format: gt-<rig>-<role> (e.g., gt-tribal-witness)
|
||||||
agents = append(agents,
|
agents = append(agents,
|
||||||
agentDef{
|
agentDef{
|
||||||
id: beads.WitnessBeadIDWithPrefix(prefix, rigName),
|
id: beads.WitnessBeadID(rigName),
|
||||||
roleType: "witness",
|
roleType: "witness",
|
||||||
rig: rigName,
|
rig: rigName,
|
||||||
desc: fmt.Sprintf("Witness for %s - monitors polecat health and progress.", rigName),
|
desc: fmt.Sprintf("Witness for %s - monitors polecat health and progress.", rigName),
|
||||||
},
|
},
|
||||||
agentDef{
|
agentDef{
|
||||||
id: beads.RefineryBeadIDWithPrefix(prefix, rigName),
|
id: beads.RefineryBeadID(rigName),
|
||||||
roleType: "refinery",
|
roleType: "refinery",
|
||||||
rig: rigName,
|
rig: rigName,
|
||||||
desc: fmt.Sprintf("Refinery for %s - processes merge queue.", rigName),
|
desc: fmt.Sprintf("Refinery for %s - processes merge queue.", rigName),
|
||||||
|
|||||||
@@ -329,13 +329,16 @@ exit 1
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInitAgentBeadsUsesRigBeadsDir(t *testing.T) {
|
func TestInitAgentBeadsUsesTownBeadsDir(t *testing.T) {
|
||||||
rigPath := t.TempDir()
|
// Agent beads use town beads (gt-* prefix) for cross-rig coordination.
|
||||||
beadsDir := filepath.Join(rigPath, ".beads")
|
// The Manager.townRoot determines where agent beads are created.
|
||||||
|
townRoot := t.TempDir()
|
||||||
|
townBeadsDir := filepath.Join(townRoot, ".beads")
|
||||||
|
rigPath := filepath.Join(townRoot, "testrip")
|
||||||
mayorRigPath := filepath.Join(rigPath, "mayor", "rig")
|
mayorRigPath := filepath.Join(rigPath, "mayor", "rig")
|
||||||
|
|
||||||
if err := os.MkdirAll(beadsDir, 0755); err != nil {
|
if err := os.MkdirAll(townBeadsDir, 0755); err != nil {
|
||||||
t.Fatalf("mkdir beads dir: %v", err)
|
t.Fatalf("mkdir town beads dir: %v", err)
|
||||||
}
|
}
|
||||||
if err := os.MkdirAll(mayorRigPath, 0755); err != nil {
|
if err := os.MkdirAll(mayorRigPath, 0755); err != nil {
|
||||||
t.Fatalf("mkdir mayor rig: %v", err)
|
t.Fatalf("mkdir mayor rig: %v", err)
|
||||||
@@ -386,10 +389,10 @@ esac
|
|||||||
|
|
||||||
binDir := writeFakeBD(t, script)
|
binDir := writeFakeBD(t, script)
|
||||||
t.Setenv("PATH", binDir+string(os.PathListSeparator)+os.Getenv("PATH"))
|
t.Setenv("PATH", binDir+string(os.PathListSeparator)+os.Getenv("PATH"))
|
||||||
t.Setenv("EXPECT_BEADS_DIR", beadsDir)
|
t.Setenv("EXPECT_BEADS_DIR", townBeadsDir)
|
||||||
t.Setenv("BEADS_DIR", "")
|
t.Setenv("BEADS_DIR", "")
|
||||||
|
|
||||||
manager := &Manager{}
|
manager := &Manager{townRoot: townRoot}
|
||||||
if err := manager.initAgentBeads(rigPath, "demo", "gt", false); err != nil {
|
if err := manager.initAgentBeads(rigPath, "demo", "gt", false); err != nil {
|
||||||
t.Fatalf("initAgentBeads: %v", err)
|
t.Fatalf("initAgentBeads: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user