Complete Guide to Issue Statuses in Beads: Built-in and Custom Workflows
Beads defines seven built-in issue statuses—open, in_progress, blocked, deferred, closed, pinned, and hooked—organized into four behavioral categories that control visibility in work queues, alongside a configurable system for adding custom statuses via the status.custom configuration key.
The gastownhall/beads project implements a strict, workflow-driven status model through its bd CLI tool. These statuses are not merely labels; they are strongly typed values defined in internal/types/types.go that determine how issues surface in filtered views like bd list and bd ready.
The Seven Built-in Issue Statuses in Beads
According to the source code in internal/types/types.go (lines 27–34), Beads provides the following built-in statuses, each mapped to a specific behavioral category:
open— Category: active. The default status for new issues, indicating they are available for work and appear in standard list views.in_progress— Category: wip (work in progress). Indicates active development and qualifies the issue for thebd readywork-queue.blocked— Category: wip. Marks an issue as stalled by external dependencies, remaining in workflow queues but flagged.deferred— Category: frozen. Deliberately shelved work that is hidden from defaultbd listandbd readyviews.closed— Category: done. Represents completed or resolved issues, filtered out of active work queues.pinned— Category: frozen. A persistent status that stays open indefinitely, excluded from standard workflow automation.hooked— Category: wip. An internal status attached to an agent’s hook, typically managed programmatically rather than manually.
The BuiltInStatusCategory mapping in internal/types/types.go drives this categorization logic, ensuring the CLI filters views correctly based on these groupings.
How Status Categories Drive Workflow Logic
The category assigned to each status determines its visibility and behavior across the Beads interface. The bd CLI uses these categories to decide which issues appear in specific contexts:
active— Issues appear in defaultbd listoutput.wip— Issues qualify for thebd readywork-queue, representing the pool of actively progressing work.frozen— Issues are hidden from both default lists and the ready queue, effectively paused.done— Issues are treated as resolved and excluded from active workflow views.
This implementation allows the system to maintain clean separation between backlog items, active work, and archived issues without requiring complex query syntax.
Adding Custom Issue Statuses in Beads
Beyond the built-in set, Beads allows users to define custom statuses through configuration. These are stored in the status.custom config key and must follow the strict pattern name:category, where the category must be one of the four valid behaviors (active, wip, frozen, done).
The cmd/bd/statuses.go file (lines 13–26) implements the retrieval logic, while ParseCustomStatusConfig in internal/types/types.go handles the parsing of these configuration strings into CustomStatus structs. Custom statuses appear alongside built-in ones when running bd statuses --json and participate in the same category-based filtering logic.
# Add a custom status called "in_review" that appears in active lists
bd config set status.custom "in_review:active"
# Verify the custom status appears in the enumerated list
bd statuses --json | jq '.custom_statuses[] | select(.name=="in_review")'
Validating and Using Statuses via the CLI
Beads enforces status validity through the IsValid and IsValidWithCustom functions in internal/types/types.go. These validators ensure that only recognized built-in statuses or properly configured custom statuses can be assigned to issues, preventing typographical errors or invalid workflow states.
The bd statuses command (implemented in cmd/bd/statuses.go) exposes all available statuses, rendering a human-readable table with icons by default or machine-readable JSON when passed the --json flag.
# Display all statuses in an interactive table
bd statuses
# List statuses as JSON for scripting
bd statuses --json
You can apply these statuses when creating or updating issues:
# Create an issue with a custom status
bd create "Add CI pipeline" --type task --status in_review
# Update an existing issue to closed
bd update bd-1a2b3c --status closed
Summary
- Seven built-in statuses (
open,in_progress,blocked,deferred,closed,pinned,hooked) are defined ininternal/types/types.goand mapped to four behavioral categories (active,wip,frozen,done). - Category-driven visibility determines whether issues appear in
bd list,bd ready, or are hidden from view. - Custom statuses can be added via
status.customconfiguration using thename:categorypattern, parsed byParseCustomStatusConfig. - Validation occurs through
IsValidandIsValidWithCustomto ensure only recognized statuses are assigned. - CLI exposure happens through
bd statuses, with JSON output available for automation.
Frequently Asked Questions
What are the default issue statuses in Beads?
Beads ships with seven built-in statuses defined as constants in internal/types/types.go: open, in_progress, blocked, deferred, closed, pinned, and hooked. Each is categorized as active, wip, frozen, or done to control its behavior in workflow views.
How do I create a custom issue status in Beads?
Configure a custom status using the status.custom config key with the pattern name:category, such as bd config set status.custom "in_review:active". The category must be active, wip, frozen, or done, and the status will immediately appear in bd statuses output.
What is the difference between active, wip, and frozen categories?
The active category makes issues appear in default bd list views; wip (work in progress) includes them in the bd ready queue; frozen hides them from both views, effectively pausing the work. These mappings are handled by BuiltInStatusCategory in the types definition.
How does Beads validate issue status assignments?
Validation occurs through the IsValid and IsValidWithCustom functions in internal/types/types.go, which check assigned statuses against the built-in constants and any user-defined custom statuses loaded from configuration. This prevents invalid or misspelled statuses from being applied to issues.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →