fix: Use rig's configured prefix for agent bead IDs (gt-kdy77, gt-ihvq0)
Added WithPrefix variants to agent bead ID functions: - AgentBeadIDWithPrefix(prefix, rig, role, name) - WitnessBeadIDWithPrefix, RefineryBeadIDWithPrefix - CrewBeadIDWithPrefix, PolecatBeadIDWithPrefix Updated callers to use rig's configured prefix: - crew_add.go: reads r.Config.Prefix for crew worker beads - rig/manager.go: uses prefix param for witness/refinery beads - doctor/agent_beads_check.go: uses prefix from routes.jsonl This allows non-gastown rigs (like beads with bd- prefix) to have properly-prefixed agent beads. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -719,21 +719,28 @@ func (b *Beads) GetAgentBead(id string) (*Issue, *AgentFields, error) {
|
|||||||
// - gt-gastown-crew-max (rig-level named agent)
|
// - gt-gastown-crew-max (rig-level named agent)
|
||||||
// - gt-gastown-polecat-Toast (rig-level named agent)
|
// - gt-gastown-polecat-Toast (rig-level named agent)
|
||||||
|
|
||||||
// AgentBeadID generates the canonical agent bead ID.
|
// AgentBeadIDWithPrefix generates an agent bead ID using the specified prefix.
|
||||||
|
// The prefix should NOT include the hyphen (e.g., "gt", "bd", not "gt-", "bd-").
|
||||||
// For town-level agents (mayor, deacon), pass empty rig and name.
|
// For town-level agents (mayor, deacon), pass empty rig and name.
|
||||||
// For rig-level singletons (witness, refinery), pass empty name.
|
// For rig-level singletons (witness, refinery), pass empty name.
|
||||||
// For named agents (crew, polecat), pass all three.
|
// For named agents (crew, polecat), pass all three.
|
||||||
func AgentBeadID(rig, role, name string) string {
|
func AgentBeadIDWithPrefix(prefix, rig, role, name string) string {
|
||||||
if rig == "" {
|
if rig == "" {
|
||||||
// Town-level agent: gt-mayor, gt-deacon
|
// Town-level agent: prefix-mayor, prefix-deacon
|
||||||
return "gt-" + role
|
return prefix + "-" + role
|
||||||
}
|
}
|
||||||
if name == "" {
|
if name == "" {
|
||||||
// Rig-level singleton: gt-gastown-witness, gt-gastown-refinery
|
// Rig-level singleton: prefix-rig-witness, prefix-rig-refinery
|
||||||
return "gt-" + rig + "-" + role
|
return prefix + "-" + rig + "-" + role
|
||||||
}
|
}
|
||||||
// Rig-level named agent: gt-gastown-crew-max, gt-gastown-polecat-Toast
|
// Rig-level named agent: prefix-rig-role-name
|
||||||
return "gt-" + rig + "-" + role + "-" + name
|
return prefix + "-" + rig + "-" + role + "-" + name
|
||||||
|
}
|
||||||
|
|
||||||
|
// AgentBeadID generates the canonical agent bead ID using "gt" prefix.
|
||||||
|
// For non-gastown rigs, use AgentBeadIDWithPrefix with the rig's configured prefix.
|
||||||
|
func AgentBeadID(rig, role, name string) string {
|
||||||
|
return AgentBeadIDWithPrefix("gt", rig, role, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MayorBeadID returns the Mayor agent bead ID.
|
// MayorBeadID returns the Mayor agent bead ID.
|
||||||
@@ -746,24 +753,44 @@ func DeaconBeadID() string {
|
|||||||
return "gt-deacon"
|
return "gt-deacon"
|
||||||
}
|
}
|
||||||
|
|
||||||
// WitnessBeadID returns the Witness agent bead ID for a rig.
|
// WitnessBeadIDWithPrefix returns the Witness agent bead ID for a rig using the specified prefix.
|
||||||
|
func WitnessBeadIDWithPrefix(prefix, rig string) string {
|
||||||
|
return AgentBeadIDWithPrefix(prefix, rig, "witness", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// WitnessBeadID returns the Witness agent bead ID for a rig using "gt" prefix.
|
||||||
func WitnessBeadID(rig string) string {
|
func WitnessBeadID(rig string) string {
|
||||||
return AgentBeadID(rig, "witness", "")
|
return WitnessBeadIDWithPrefix("gt", rig)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RefineryBeadID returns the Refinery agent bead ID for a rig.
|
// RefineryBeadIDWithPrefix returns the Refinery agent bead ID for a rig using the specified prefix.
|
||||||
|
func RefineryBeadIDWithPrefix(prefix, rig string) string {
|
||||||
|
return AgentBeadIDWithPrefix(prefix, rig, "refinery", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// RefineryBeadID returns the Refinery agent bead ID for a rig using "gt" prefix.
|
||||||
func RefineryBeadID(rig string) string {
|
func RefineryBeadID(rig string) string {
|
||||||
return AgentBeadID(rig, "refinery", "")
|
return RefineryBeadIDWithPrefix("gt", rig)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CrewBeadID returns a Crew worker agent bead ID.
|
// CrewBeadIDWithPrefix returns a Crew worker agent bead ID using the specified prefix.
|
||||||
|
func CrewBeadIDWithPrefix(prefix, rig, name string) string {
|
||||||
|
return AgentBeadIDWithPrefix(prefix, rig, "crew", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CrewBeadID returns a Crew worker agent bead ID using "gt" prefix.
|
||||||
func CrewBeadID(rig, name string) string {
|
func CrewBeadID(rig, name string) string {
|
||||||
return AgentBeadID(rig, "crew", name)
|
return CrewBeadIDWithPrefix("gt", rig, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PolecatBeadID returns a Polecat agent bead ID.
|
// PolecatBeadIDWithPrefix returns a Polecat agent bead ID using the specified prefix.
|
||||||
|
func PolecatBeadIDWithPrefix(prefix, rig, name string) string {
|
||||||
|
return AgentBeadIDWithPrefix(prefix, rig, "polecat", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PolecatBeadID returns a Polecat agent bead ID using "gt" prefix.
|
||||||
func PolecatBeadID(rig, name string) string {
|
func PolecatBeadID(rig, name string) string {
|
||||||
return AgentBeadID(rig, "polecat", name)
|
return PolecatBeadIDWithPrefix("gt", rig, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseAgentBeadID parses an agent bead ID into its components.
|
// ParseAgentBeadID parses an agent bead ID into its components.
|
||||||
|
|||||||
@@ -81,7 +81,12 @@ func runCrewAdd(cmd *cobra.Command, args []string) error {
|
|||||||
// Create agent bead for the crew worker
|
// Create agent bead for the crew worker
|
||||||
rigBeadsPath := filepath.Join(r.Path, "mayor", "rig")
|
rigBeadsPath := filepath.Join(r.Path, "mayor", "rig")
|
||||||
bd := beads.New(rigBeadsPath)
|
bd := beads.New(rigBeadsPath)
|
||||||
crewID := beads.CrewBeadID(rigName, name)
|
// Use the rig's configured prefix, defaulting to "gt" for backward compatibility
|
||||||
|
prefix := "gt"
|
||||||
|
if r.Config != nil && r.Config.Prefix != "" {
|
||||||
|
prefix = r.Config.Prefix
|
||||||
|
}
|
||||||
|
crewID := beads.CrewBeadIDWithPrefix(prefix, rigName, name)
|
||||||
if _, err := bd.Show(crewID); err != nil {
|
if _, err := bd.Show(crewID); err != nil {
|
||||||
// Agent bead doesn't exist, create it
|
// Agent bead doesn't exist, create it
|
||||||
fields := &beads.AgentFields{
|
fields := &beads.AgentFields{
|
||||||
|
|||||||
@@ -16,10 +16,7 @@ import (
|
|||||||
// - Crew workers - 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) and gt crew add.
|
// Agent beads are created by gt rig add (see gt-h3hak, gt-pinkq) and gt crew add.
|
||||||
//
|
// Each rig uses its configured prefix (e.g., "gt-" for gastown, "bd-" for beads).
|
||||||
// NOTE: Currently, the beads library validates that agent IDs must start
|
|
||||||
// with 'gt-'. Rigs with different prefixes (like 'bd-') cannot have agent
|
|
||||||
// beads created until that validation is fixed in the beads repo.
|
|
||||||
type AgentBeadsCheck struct {
|
type AgentBeadsCheck struct {
|
||||||
FixableCheck
|
FixableCheck
|
||||||
}
|
}
|
||||||
@@ -86,22 +83,14 @@ func (c *AgentBeadsCheck) Run(ctx *CheckContext) *CheckResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check each rig for its agents
|
// Check each rig for its agents
|
||||||
var skipped []string
|
|
||||||
for prefix, rigName := range prefixToRig {
|
for prefix, rigName := range prefixToRig {
|
||||||
// Skip non-gt prefixes - beads library currently requires gt- prefix for agents
|
|
||||||
// TODO: Remove this once beads validation is fixed to accept any prefix
|
|
||||||
if prefix != "gt" {
|
|
||||||
skipped = append(skipped, fmt.Sprintf("%s (%s-*)", rigName, prefix))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get beads client for this rig
|
// Get beads client for this rig
|
||||||
rigBeadsPath := filepath.Join(ctx.TownRoot, rigName, "mayor", "rig")
|
rigBeadsPath := filepath.Join(ctx.TownRoot, rigName, "mayor", "rig")
|
||||||
bd := beads.New(rigBeadsPath)
|
bd := beads.New(rigBeadsPath)
|
||||||
|
|
||||||
// Check rig-specific agents (using canonical naming: prefix-rig-role-name)
|
// Check rig-specific agents (using canonical naming: prefix-rig-role-name)
|
||||||
witnessID := beads.WitnessBeadID(rigName)
|
witnessID := beads.WitnessBeadIDWithPrefix(prefix, rigName)
|
||||||
refineryID := beads.RefineryBeadID(rigName)
|
refineryID := beads.RefineryBeadIDWithPrefix(prefix, rigName)
|
||||||
|
|
||||||
if _, err := bd.Show(witnessID); err != nil {
|
if _, err := bd.Show(witnessID); err != nil {
|
||||||
missing = append(missing, witnessID)
|
missing = append(missing, witnessID)
|
||||||
@@ -116,7 +105,7 @@ func (c *AgentBeadsCheck) Run(ctx *CheckContext) *CheckResult {
|
|||||||
// Check crew worker agents
|
// Check crew worker agents
|
||||||
crewWorkers := listCrewWorkers(ctx.TownRoot, rigName)
|
crewWorkers := listCrewWorkers(ctx.TownRoot, rigName)
|
||||||
for _, workerName := range crewWorkers {
|
for _, workerName := range crewWorkers {
|
||||||
crewID := beads.CrewBeadID(rigName, workerName)
|
crewID := beads.CrewBeadIDWithPrefix(prefix, rigName, workerName)
|
||||||
if _, err := bd.Show(crewID); err != nil {
|
if _, err := bd.Show(crewID); err != nil {
|
||||||
missing = append(missing, crewID)
|
missing = append(missing, crewID)
|
||||||
}
|
}
|
||||||
@@ -141,31 +130,18 @@ func (c *AgentBeadsCheck) Run(ctx *CheckContext) *CheckResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(missing) == 0 {
|
if len(missing) == 0 {
|
||||||
msg := fmt.Sprintf("All %d agent beads exist", checked)
|
|
||||||
var details []string
|
|
||||||
if len(skipped) > 0 {
|
|
||||||
details = append(details, fmt.Sprintf("Skipped %d rig(s) with non-gt prefix (beads library limitation): %s",
|
|
||||||
len(skipped), strings.Join(skipped, ", ")))
|
|
||||||
}
|
|
||||||
return &CheckResult{
|
return &CheckResult{
|
||||||
Name: c.Name(),
|
Name: c.Name(),
|
||||||
Status: StatusOK,
|
Status: StatusOK,
|
||||||
Message: msg,
|
Message: fmt.Sprintf("All %d agent beads exist", checked),
|
||||||
Details: details,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
details := missing
|
|
||||||
if len(skipped) > 0 {
|
|
||||||
details = append(details, fmt.Sprintf("Skipped %d rig(s) with non-gt prefix: %s",
|
|
||||||
len(skipped), strings.Join(skipped, ", ")))
|
|
||||||
}
|
|
||||||
|
|
||||||
return &CheckResult{
|
return &CheckResult{
|
||||||
Name: c.Name(),
|
Name: c.Name(),
|
||||||
Status: StatusError,
|
Status: StatusError,
|
||||||
Message: fmt.Sprintf("%d agent bead(s) missing", len(missing)),
|
Message: fmt.Sprintf("%d agent bead(s) missing", len(missing)),
|
||||||
Details: details,
|
Details: missing,
|
||||||
FixHint: "Run 'gt doctor --fix' to create missing agent beads",
|
FixHint: "Run 'gt doctor --fix' to create missing agent beads",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -207,16 +183,11 @@ func (c *AgentBeadsCheck) Fix(ctx *CheckContext) error {
|
|||||||
|
|
||||||
// Create missing agents for each rig
|
// Create missing agents for each rig
|
||||||
for prefix, rigName := range prefixToRig {
|
for prefix, rigName := range prefixToRig {
|
||||||
// Skip non-gt prefixes - beads library currently requires gt- prefix for agents
|
|
||||||
if prefix != "gt" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
rigBeadsPath := filepath.Join(ctx.TownRoot, rigName, "mayor", "rig")
|
rigBeadsPath := filepath.Join(ctx.TownRoot, rigName, "mayor", "rig")
|
||||||
bd := beads.New(rigBeadsPath)
|
bd := beads.New(rigBeadsPath)
|
||||||
|
|
||||||
// Create rig-specific agents if missing (using canonical naming: prefix-rig-role-name)
|
// Create rig-specific agents if missing (using canonical naming: prefix-rig-role-name)
|
||||||
witnessID := beads.WitnessBeadID(rigName)
|
witnessID := beads.WitnessBeadIDWithPrefix(prefix, rigName)
|
||||||
if _, err := bd.Show(witnessID); err != nil {
|
if _, err := bd.Show(witnessID); err != nil {
|
||||||
fields := &beads.AgentFields{
|
fields := &beads.AgentFields{
|
||||||
RoleType: "witness",
|
RoleType: "witness",
|
||||||
@@ -230,7 +201,7 @@ func (c *AgentBeadsCheck) Fix(ctx *CheckContext) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
refineryID := beads.RefineryBeadID(rigName)
|
refineryID := beads.RefineryBeadIDWithPrefix(prefix, rigName)
|
||||||
if _, err := bd.Show(refineryID); err != nil {
|
if _, err := bd.Show(refineryID); err != nil {
|
||||||
fields := &beads.AgentFields{
|
fields := &beads.AgentFields{
|
||||||
RoleType: "refinery",
|
RoleType: "refinery",
|
||||||
@@ -247,7 +218,7 @@ func (c *AgentBeadsCheck) Fix(ctx *CheckContext) error {
|
|||||||
// Create crew worker agents if missing
|
// Create crew worker agents if missing
|
||||||
crewWorkers := listCrewWorkers(ctx.TownRoot, rigName)
|
crewWorkers := listCrewWorkers(ctx.TownRoot, rigName)
|
||||||
for _, workerName := range crewWorkers {
|
for _, workerName := range crewWorkers {
|
||||||
crewID := beads.CrewBeadID(rigName, workerName)
|
crewID := beads.CrewBeadIDWithPrefix(prefix, rigName, workerName)
|
||||||
if _, err := bd.Show(crewID); err != nil {
|
if _, err := bd.Show(crewID); err != nil {
|
||||||
fields := &beads.AgentFields{
|
fields := &beads.AgentFields{
|
||||||
RoleType: "crew",
|
RoleType: "crew",
|
||||||
|
|||||||
@@ -417,13 +417,13 @@ func (m *Manager) initAgentBeads(rigPath, rigName, prefix string, isFirstRig boo
|
|||||||
// Always create rig-specific agents (using canonical naming: prefix-rig-role-name)
|
// Always create rig-specific agents (using canonical naming: prefix-rig-role-name)
|
||||||
agents = append(agents,
|
agents = append(agents,
|
||||||
agentDef{
|
agentDef{
|
||||||
id: beads.WitnessBeadID(rigName),
|
id: beads.WitnessBeadIDWithPrefix(prefix, 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.RefineryBeadID(rigName),
|
id: beads.RefineryBeadIDWithPrefix(prefix, 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),
|
||||||
|
|||||||
Reference in New Issue
Block a user