Files
beads/docs/LABELS.md
Steve Yegge 48dca4ea33 feat: add bd state and bd set-state helper commands (bd-7l67)
Implements convenience commands for the labels-as-state pattern:

- `bd state <id> <dimension>` - Query current state value from labels
- `bd state list <id>` - List all state dimensions on an issue
- `bd set-state <id> <dimension>=<value> --reason "..."` - Atomically:
  1. Create event bead (source of truth)
  2. Remove old dimension label
  3. Add new dimension:value label (cache)

Common dimensions: patrol, mode, health, status
Convention: <dimension>:<value> (e.g., patrol:active, mode:degraded)

Updated docs/CLI_REFERENCE.md with new State section.
Updated docs/LABELS.md to reflect implemented helpers.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-30 15:57:08 -08:00

19 KiB

Labels in Beads

Labels provide flexible, multi-dimensional categorization for issues beyond the structured fields (status, priority, type). Use labels for cross-cutting concerns, technical metadata, and contextual tagging without schema changes.

Design Philosophy

When to use labels vs. structured fields:

  • Structured fields (status, priority, type) → Core workflow state

    • Status: Where the issue is in the workflow (open, in_progress, blocked, closed)
    • Priority: How urgent (0-4)
    • Type: What kind of work (bug, feature, task, epic, chore)
  • Labels → Everything else

    • Technical metadata (backend, frontend, api, database)
    • Domain/scope (auth, payments, search, analytics)
    • Effort estimates (small, medium, large)
    • Quality gates (needs-review, needs-tests, breaking-change)
    • Team/ownership (team-infra, team-product)
    • Release tracking (v1.0, v2.0, backport-candidate)

Quick Start

# Add labels when creating issues
bd create "Fix auth bug" -t bug -p 1 -l auth,backend,urgent

# Add labels to existing issues
bd label add bd-42 security
bd label add bd-42 breaking-change

# List issue labels
bd label list bd-42

# Remove a label
bd label remove bd-42 urgent

# List all labels in use
bd label list-all

# Filter by labels (AND - must have ALL)
bd list --label backend,auth

# Filter by labels (OR - must have AT LEAST ONE)
bd list --label-any frontend,backend

# Combine filters
bd list --status open --priority 1 --label security

Common Label Patterns

1. Technical Component Labels

Identify which part of the system:

backend
frontend
api
database
infrastructure
cli
ui
mobile

Example:

bd create "Add GraphQL endpoint" -t feature -p 2 -l backend,api
bd create "Update login form" -t task -p 2 -l frontend,auth,ui

2. Domain/Feature Area

Group by business domain:

auth
payments
search
analytics
billing
notifications
reporting
admin

Example:

bd list --label payments --status open  # All open payment issues
bd list --label-any auth,security       # Security-related work

3. Size/Effort Estimates

Quick effort indicators:

small     # < 1 day
medium    # 1-3 days
large     # > 3 days

Example:

# Find small quick wins
bd ready --json | jq '.[] | select(.labels[] == "small")'

4. Quality Gates

Track what's needed before closing:

needs-review
needs-tests
needs-docs
breaking-change

Example:

bd label add bd-42 needs-review
bd list --label needs-review --status in_progress

5. Release Management

Track release targeting:

v1.0
v2.0
backport-candidate
release-blocker

Example:

bd list --label v1.0 --status open    # What's left for v1.0?
bd label add bd-42 release-blocker

6. Team/Ownership

Indicate ownership or interest:

team-infra
team-product
team-mobile
needs-triage
help-wanted

Example:

bd list --assignee alice --label team-infra
bd create "Memory leak in cache" -t bug -p 1 -l team-infra,help-wanted

7. Special Markers

Process or workflow flags:

auto-generated     # Created by automation
discovered-from    # Found during other work (also a dep type)
technical-debt
good-first-issue
duplicate
wontfix

Example:

bd create "TODO: Refactor parser" -t chore -p 3 -l technical-debt,auto-generated

Filtering by Labels

AND Filtering (--label)

All specified labels must be present:

# Issues that are BOTH backend AND urgent
bd list --label backend,urgent

# Open bugs that need review AND tests
bd list --status open --type bug --label needs-review,needs-tests

OR Filtering (--label-any)

At least one specified label must be present:

# Issues in frontend OR backend
bd list --label-any frontend,backend

# Security or auth related
bd list --label-any security,auth

Combining AND/OR

Mix both filters for complex queries:

# Backend issues that are EITHER urgent OR a blocker
bd list --label backend --label-any urgent,release-blocker

# Frontend work that needs BOTH review and tests, but in any component
bd list --label needs-review,needs-tests --label-any frontend,ui,mobile

Workflow Examples

Triage Workflow

# Create untriaged issue
bd create "Crash on login" -t bug -p 1 -l needs-triage

# During triage, add context
bd label add bd-42 auth
bd label add bd-42 backend
bd label add bd-42 urgent
bd label remove bd-42 needs-triage

# Find untriaged issues
bd list --label needs-triage

Quality Gate Workflow

# Start work
bd update bd-42 --status in_progress

# Mark quality requirements
bd label add bd-42 needs-tests
bd label add bd-42 needs-docs

# Before closing, verify
bd label list bd-42
# ... write tests and docs ...
bd label remove bd-42 needs-tests
bd label remove bd-42 needs-docs

# Close when gates satisfied
bd close bd-42

Release Planning

# Tag issues for v1.0
bd label add bd-42 v1.0
bd label add bd-43 v1.0
bd label add bd-44 v1.0

# Track v1.0 progress
bd list --label v1.0 --status closed    # Done
bd list --label v1.0 --status open      # Remaining
bd stats  # Overall progress

# Mark critical items
bd label add bd-45 v1.0
bd label add bd-45 release-blocker

Component-Based Work Distribution

# Backend team picks up work
bd ready --json | jq '.[] | select(.labels[]? == "backend")'

# Frontend team finds small tasks
bd list --status open --label frontend,small

# Find help-wanted items for new contributors
bd list --label help-wanted,good-first-issue

Label Management

Listing Labels

# Labels on a specific issue
bd label list bd-42

# All labels in database with usage counts
bd label list-all

# JSON output for scripting
bd label list-all --json

Output:

[
  {"label": "auth", "count": 5},
  {"label": "backend", "count": 12},
  {"label": "frontend", "count": 8}
]

Bulk Operations

Add labels in batch during creation:

bd create "Issue" -l label1,label2,label3

Script to add label to multiple issues:

# Add "needs-review" to all in_progress issues
bd list --status in_progress --json | jq -r '.[].id' | while read id; do
  bd label add "$id" needs-review
done

Remove label from multiple issues:

# Remove "urgent" from closed issues
bd list --status closed --label urgent --json | jq -r '.[].id' | while read id; do
  bd label remove "$id" urgent
done

Integration with Git Workflow

Labels are automatically synced to .beads/issues.jsonl along with all issue data:

# Make changes
bd create "Fix bug" -l backend,urgent
bd label add bd-42 needs-review

# Auto-exported after 5 seconds (or use git hooks for immediate export)
git add .beads/issues.jsonl
git commit -m "Add backend issue"

# After git pull, labels are auto-imported
git pull
bd list --label backend  # Fresh data including labels

Markdown Import/Export

Labels are preserved when importing from markdown:

# Fix Authentication Bug

### Type
bug

### Priority
1

### Labels
auth, backend, urgent, needs-review

### Description
Users can't log in after recent deployment.
bd create -f issue.md
# Creates issue with all four labels

Best Practices

1. Establish Conventions Early

Document your team's label taxonomy:

# Add to project README or CONTRIBUTING.md
- Use lowercase, hyphen-separated (e.g., `good-first-issue`)
- Prefix team labels (e.g., `team-infra`, `team-product`)
- Use consistent size labels (`small`, `medium`, `large`)

2. Don't Overuse Labels

Labels are flexible, but too many can cause confusion. Prefer:

  • 5-10 core technical labels (backend, frontend, api, etc.)
  • 3-5 domain labels per project
  • Standard process labels (needs-review, needs-tests)
  • Release labels as needed

3. Clean Up Unused Labels

Periodically review:

bd label list-all
# Remove obsolete labels from issues

Labels are for categorization, not free-text search:

  • Good: backend, auth, urgent
  • Bad: fix-the-login-bug, john-asked-for-this

5. Combine with Dependencies

Labels + dependencies = powerful organization:

# Epic with labeled subtasks
bd create "Auth system rewrite" -t epic -p 1 -l auth,v2.0
bd create "Implement JWT" -t task -p 1 -l auth,backend --deps parent-child:bd-42
bd create "Update login UI" -t task -p 1 -l auth,frontend --deps parent-child:bd-42

# Find all v2.0 auth work
bd list --label auth,v2.0

AI Agent Usage

Labels are especially useful for AI agents managing complex workflows:

# Auto-label discovered work
bd create "Found TODO in auth.go" -t task -p 2 -l auto-generated,technical-debt

# Filter for agent review
bd list --label needs-review --status in_progress --json

# Track automation metadata
bd label add bd-42 ai-generated
bd label add bd-42 needs-human-review

Example agent workflow:

# Agent discovers issues during refactor
bd create "Extract validateToken function" -t chore -p 2 \
  -l technical-debt,backend,auth,small \
  --deps discovered-from:bd-10

# Agent marks work for review
bd update bd-42 --status in_progress
# ... agent does work ...
bd label add bd-42 needs-review
bd label add bd-42 ai-generated

# Human reviews and approves
bd label remove bd-42 needs-review
bd label add bd-42 approved
bd close bd-42

Labels as State Cache

Labels can cache operational state for fast queries, enabling patterns where beads track both immutable history (events) and current state (labels).

The Pattern

Convention: <dimension>:<value>

Examples:

  • patrol:muted / patrol:active - patrol suppression state
  • mode:degraded / mode:normal - operational mode
  • status:idle / status:working - worker status
  • health:healthy / health:failing - component health

Implementation:

  1. Create an event bead (full context, immutable history)
  2. Update the role bead's labels (current state cache)
# Event: Full record of what happened and why
bd create "Muted patrol: user requested during debugging" -t event \
  -l event-type:patrol-muted,actor:witness,reason:user-request

# State: Update the role bead's label to reflect current state
bd label remove beads/witness patrol:active
bd label add beads/witness patrol:muted

Key principle: Events are the source of truth. Labels are a cache for fast queries.

Why This Pattern?

Fast queries without event scanning:

# Without labels-as-state: scan all events to find current patrol state
bd list --type event | grep "patrol" | tail -1  # Slow, fragile

# With labels-as-state: direct query
bd show beads/witness | grep "patrol:"  # Instant

History preserved:

# When was patrol muted? Why? Who did it?
bd list --label event-type:patrol-muted --type event

State recovery:

# If labels get corrupted, rebuild from events
bd list --type event --label event-type:patrol-muted | tail -1
# Then re-apply the label

Common State Dimensions

Dimension Values Use Case
patrol: active, muted Patrol cycle suppression
mode: normal, degraded, maintenance Operational mode
status: idle, working, blocked Worker activity
health: healthy, warning, failing Component health
lock: unlocked, locked Exclusive access control

State Transitions

Always create an event before changing state labels:

# Function to transition state with audit trail
transition_state() {
  local role="$1"
  local dimension="$2"
  local old_value="$3"
  local new_value="$4"
  local reason="$5"

  # Record the transition
  bd create "State change: $dimension $old_value$new_value" -t event \
    -l "event-type:state-change,dimension:$dimension,from:$old_value,to:$new_value"

  # Update the cache
  bd label remove "$role" "$dimension:$old_value"
  bd label add "$role" "$dimension:$new_value"
}

# Usage
transition_state beads/witness patrol active muted "User debugging session"

Querying State

# Current state of a role
bd label list beads/witness | grep ":"

# All roles in a specific state
bd list --label patrol:muted

# Roles NOT in expected state
bd list --label-any mode:degraded,health:failing

# History of state changes
bd list --type event --label event-type:state-change

Best Practices

  1. Use namespaced dimensions - Prefix with role type if ambiguous
  2. Keep value sets small - 2-4 values per dimension
  3. Document valid values - List allowed values in role docs
  4. Always create events first - Never update labels without history
  5. Treat labels as ephemeral - Rebuild from events if corrupted

Future Helpers

The pattern suggests helper commands (see bd-7l67):

# Query current state
bd state beads/witness patrol     # → "muted"

# Transition with automatic event creation
bd set-state beads/witness patrol=active --reason "Debugging complete"

Until helpers exist, use the manual pattern above.

Advanced Patterns

Component Matrix

Track issues across multiple dimensions:

# Backend + auth + high priority
bd list --label backend,auth --priority 1

# Any frontend work that's small
bd list --label-any frontend,ui --label small

# Critical issues across all components
bd list --priority 0 --label-any backend,frontend,infrastructure

Sprint Planning

# Label issues for sprint
for id in bd-42 bd-43 bd-44 bd-45; do
  bd label add "$id" sprint-12
done

# Track sprint progress
bd list --label sprint-12 --status closed    # Velocity
bd list --label sprint-12 --status open      # Remaining
bd stats | grep "In Progress"                # Current WIP

Technical Debt Tracking

# Mark debt
bd create "Refactor legacy parser" -t chore -p 3 -l technical-debt,large

# Find debt to tackle
bd list --label technical-debt --label small
bd list --label technical-debt --priority 1  # High-priority debt

Breaking Change Coordination

# Identify breaking changes
bd label add bd-42 breaking-change
bd label add bd-42 v2.0

# Find all breaking changes for next major release
bd list --label breaking-change,v2.0

# Ensure they're documented
bd list --label breaking-change --label needs-docs

Operational State Pattern (Labels as Cache)

For orchestration systems like Gas Town, labels can cache the current operational state of "role beads" (issues representing agents or system components). This enables fast state queries without scanning event history.

Convention: <dimension>:<value>

Use colon-separated labels with a dimension prefix and value suffix:

patrol:muted      patrol:active
mode:degraded     mode:normal
status:idle       status:working
health:healthy    health:failing

The Pattern

  1. Create an event bead with full context (immutable, audit trail)
  2. Update the role bead's labels to reflect current state (fast lookup)
# 1. Record the event (source of truth)
bd create "Muted patrol for witness-abc" -t event \
  --parent witness-abc \
  -d "Reason: investigating stuck polecat. Expected duration: 30m"

# 2. Update the cached state label
bd label remove witness-abc patrol:active
bd label add witness-abc patrol:muted

Why This Pattern?

Events are source of truth. Labels are cache.

Approach Events Only Labels as Cache
Query current state Scan all events, find latest bd list --label patrol:muted
Query state history Natural (all events exist) Query events
Audit trail Complete Complete (events still exist)
Performance O(n) events O(1) label lookup

The pattern gives you both: complete history via events, fast queries via labels.

Example: Agent Role States

# Create a role bead for an agent
bd create "witness-alpha" -t role -l patrol:active,mode:normal,health:healthy

# Agent enters degraded mode
bd create "Degraded: high error rate" -t event --parent witness-alpha \
  -d "Error rate exceeded 5%. Reducing poll frequency."
bd label remove witness-alpha mode:normal
bd label add witness-alpha mode:degraded

# Query current state
bd list --label mode:degraded --type role  # All degraded roles

# Agent recovers
bd create "Recovered: error rate normal" -t event --parent witness-alpha
bd label remove witness-alpha mode:degraded
bd label add witness-alpha mode:normal

Common Dimensions

Dimension Values Use Case
patrol active, muted, suspended Agent patrol cycles
mode normal, degraded, maintenance Operational modes
status idle, working, blocked Work state
health healthy, warning, failing Health checks
sync current, stale, syncing Sync state

Best Practices

  1. Always create the event first - Labels are cache; events are truth
  2. Remove old value before adding new - Prevents dimension:value1 + dimension:value2 conflicts
  3. Use consistent dimension names - Establish team conventions early
  4. Keep dimensions orthogonal - patrol and mode are independent concerns

Querying State

# Find all muted patrols
bd list --label patrol:muted

# Find healthy agents in normal mode
bd list --label health:healthy,mode:normal

# Find any non-healthy agents
bd list --label-any health:warning,health:failing

# Get state for a specific role
bd label list witness-alpha
# Output: patrol:active, mode:normal, health:healthy

Helper Commands

For convenience, use these helpers:

# Query a specific dimension
bd state witness-alpha patrol
# Output: active

# List all state dimensions
bd state list witness-alpha
# Output:
#   patrol: active
#   mode: normal
#   health: healthy

# Set state (creates event + updates label atomically)
bd set-state witness-alpha patrol=muted --reason "Investigating issue"

The set-state command atomically:

  1. Creates an event bead with the reason (source of truth)
  2. Removes the old dimension label if present
  3. Adds the new dimension:value label (cache)

See CLI_REFERENCE.md for full command reference.

Troubleshooting

Labels Not Showing in List

Labels require explicit fetching. The bd list command shows issues but not labels in human output (only in JSON).

# See labels in JSON
bd list --json | jq '.[] | {id, labels}'

# See labels for specific issue
bd show bd-42 --json | jq '.labels'
bd label list bd-42

Label Filtering Not Working

Check label names for exact matches (case-sensitive):

# These are different labels:
bd label add bd-42 Backend    # Capital B
bd list --label backend       # Won't match

# List all labels to see exact names
bd label list-all

Syncing Labels with Git

Labels are included in .beads/issues.jsonl export. If labels seem out of sync:

# Force export
bd export -o .beads/issues.jsonl

# After pull, force import
bd import -i .beads/issues.jsonl

See Also