feat: add structured labels for agent beads (bd-g7eq)
Add role_type and rig labels to agent beads for filtering queries. Changes: - Add RoleType/Rig to CreateArgs and UpdateArgs in RPC protocol - Auto-add role_type:<value> and rig:<value> labels when creating/updating agents - Add --role-type and --agent-rig flags to bd create (requires --type=agent) - Add bd agent backfill-labels command to update existing agent beads This enables queries like: bd list --type=agent --label=role_type:witness bd list --type=agent --label=rig:gastown 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -97,6 +97,9 @@ type CreateArgs struct {
|
||||
CreatedBy string `json:"created_by,omitempty"` // Who created the issue
|
||||
// Molecule type (for swarm coordination)
|
||||
MolType string `json:"mol_type,omitempty"` // swarm, patrol, or work (default)
|
||||
// Agent identity fields (only valid when IssueType == "agent")
|
||||
RoleType string `json:"role_type,omitempty"` // polecat|crew|witness|refinery|mayor|deacon
|
||||
Rig string `json:"rig,omitempty"` // Rig name (empty for town-level agents)
|
||||
}
|
||||
|
||||
// UpdateArgs represents arguments for the update operation
|
||||
@@ -134,6 +137,9 @@ type UpdateArgs struct {
|
||||
// Agent state fields
|
||||
AgentState *string `json:"agent_state,omitempty"` // Agent state (idle|running|stuck|stopped|dead)
|
||||
LastActivity *bool `json:"last_activity,omitempty"` // If true, update last_activity to now
|
||||
// Agent identity fields
|
||||
RoleType *string `json:"role_type,omitempty"` // polecat|crew|witness|refinery|mayor|deacon
|
||||
Rig *string `json:"rig,omitempty"` // Rig name (empty for town-level agents)
|
||||
}
|
||||
|
||||
// CloseArgs represents arguments for the close operation
|
||||
|
||||
@@ -115,6 +115,13 @@ func updatesFromArgs(a UpdateArgs) map[string]interface{} {
|
||||
if a.LastActivity != nil && *a.LastActivity {
|
||||
u["last_activity"] = time.Now()
|
||||
}
|
||||
// Agent identity fields
|
||||
if a.RoleType != nil {
|
||||
u["role_type"] = *a.RoleType
|
||||
}
|
||||
if a.Rig != nil {
|
||||
u["rig"] = *a.Rig
|
||||
}
|
||||
return u
|
||||
}
|
||||
|
||||
@@ -198,6 +205,9 @@ func (s *Server) handleCreate(req *Request) Response {
|
||||
CreatedBy: createArgs.CreatedBy,
|
||||
// Molecule type
|
||||
MolType: types.MolType(createArgs.MolType),
|
||||
// Agent identity fields
|
||||
RoleType: createArgs.RoleType,
|
||||
Rig: createArgs.Rig,
|
||||
}
|
||||
|
||||
// Check if any dependencies are discovered-from type
|
||||
@@ -283,6 +293,28 @@ func (s *Server) handleCreate(req *Request) Response {
|
||||
}
|
||||
}
|
||||
|
||||
// Auto-add role_type/rig labels for agent beads (enables filtering queries)
|
||||
if issue.IssueType == types.TypeAgent {
|
||||
if issue.RoleType != "" {
|
||||
label := "role_type:" + issue.RoleType
|
||||
if err := store.AddLabel(ctx, issue.ID, label, s.reqActor(req)); err != nil {
|
||||
return Response{
|
||||
Success: false,
|
||||
Error: fmt.Sprintf("failed to add role_type label: %v", err),
|
||||
}
|
||||
}
|
||||
}
|
||||
if issue.Rig != "" {
|
||||
label := "rig:" + issue.Rig
|
||||
if err := store.AddLabel(ctx, issue.ID, label, s.reqActor(req)); err != nil {
|
||||
return Response{
|
||||
Success: false,
|
||||
Error: fmt.Sprintf("failed to add rig label: %v", err),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add dependencies if specified
|
||||
for _, depSpec := range createArgs.Dependencies {
|
||||
depSpec = strings.TrimSpace(depSpec)
|
||||
@@ -482,6 +514,29 @@ func (s *Server) handleUpdate(req *Request) Response {
|
||||
}
|
||||
}
|
||||
|
||||
// Auto-add role_type/rig labels for agent beads when these fields are set
|
||||
// This enables filtering queries like: bd list --type=agent --label=role_type:witness
|
||||
if issue.IssueType == types.TypeAgent {
|
||||
if updateArgs.RoleType != nil && *updateArgs.RoleType != "" {
|
||||
label := "role_type:" + *updateArgs.RoleType
|
||||
if err := store.AddLabel(ctx, updateArgs.ID, label, actor); err != nil {
|
||||
return Response{
|
||||
Success: false,
|
||||
Error: fmt.Sprintf("failed to add role_type label: %v", err),
|
||||
}
|
||||
}
|
||||
}
|
||||
if updateArgs.Rig != nil && *updateArgs.Rig != "" {
|
||||
label := "rig:" + *updateArgs.Rig
|
||||
if err := store.AddLabel(ctx, updateArgs.ID, label, actor); err != nil {
|
||||
return Response{
|
||||
Success: false,
|
||||
Error: fmt.Sprintf("failed to add rig label: %v", err),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle reparenting
|
||||
if updateArgs.Parent != nil {
|
||||
newParentID := *updateArgs.Parent
|
||||
|
||||
Reference in New Issue
Block a user