How the Priority System Works in Beads: P0-P4 Implementation Explained
Beads implements a strict five-level priority system using numeric values 0-4 that map to human-readable P0-P4 labels, with built-in validation and color-coded terminal rendering.
The priority system in Beads serves as the backbone for issue urgency classification throughout the CLI application. According to the gastownhall/beads source code, this system treats priority as a first-class numeric field that drives both validation logic and visual presentation in the terminal interface.
Priority Levels and Numeric Mapping
Beads recognizes exactly five priority levels, where lower numeric values indicate higher urgency. The system rejects any value outside the 0-4 range.
| Numeric value | Symbol | Convention | UI Colour |
|---|---|---|---|
| 0 | P0 | Critical / blocker | Red (#f07171 / #f07178) |
| 1 | P1 | High priority | Orange (#ff8f40) |
| 2 | P2 | Medium priority | Yellow (#e6b450) |
| 3 | P3 | Low priority | Neutral (no colour) |
| 4 | P4 | Backlog / very low | Neutral (no colour) |
Values outside this range are considered invalid and trigger validation errors.
Parsing and Validation Logic
The priority system relies on two core functions located in internal/validation/bead.go to ensure data integrity.
ParsePriority Function
The ParsePriority function handles flexible user input by accepting both bare numbers and "P"-prefixed strings. It returns -1 for invalid values.
// internal/validation/bead.go:14-26
func ParsePriority(content string) int {
content = strings.TrimSpace(content)
if strings.HasPrefix(strings.ToUpper(content), "P") {
content = content[1:] // strip "P"
}
var p int
if _, err := fmt.Sscanf(content, "%d", &p); err == nil && p >= 0 && p <= 4 {
return p
}
return -1 // invalid
}
ValidatePriority Function
ValidatePriority wraps the parser and provides descriptive error messages for invalid inputs.
// internal/validation/bead.go:47-53
func ValidatePriority(priorityStr string) (int, error) {
priority := ParsePriority(priorityStr)
if priority == -1 {
return -1, fmt.Errorf("invalid priority %q (expected 0-4 or P0-P4, not words like high/medium/low)", priorityStr)
}
return priority, nil
}
These validation functions protect the system from invalid priority strings like "high", "medium", or out-of-range numbers.
UI Representation and Color Coding
The visual layer in internal/ui/styles.go transforms numeric priorities into color-coded terminal output using the Lipgloss library.
Color Constants
Only the three highest priority levels receive distinct colors. The initColors function defines these in internal/ui/styles.go:156-161:
// Priority colors — only P0/P1/P2 get color
ColorPriorityP0 = ld(lipgloss.Color("#f07171"), lipgloss.Color("#f07178"))
ColorPriorityP1 = lipgloss.Color("#ff8f40")
ColorPriorityP2 = lipgloss.Color("#e6b450")
ColorPriorityP3 = lipgloss.NoColor{} // neutral
ColorPriorityP4 = lipgloss.NoColor{} // neutral
Style Definitions
Styles apply these colors with special formatting for critical priorities. P0 receives bold formatting to emphasize urgency:
// internal/ui/styles.go:245-251
PriorityP0Style = lipgloss.NewStyle().Foreground(ColorPriorityP0).Bold(true)
PriorityP1Style = lipgloss.NewStyle().Foreground(ColorPriorityP1)
PriorityP2Style = lipgloss.NewStyle().Foreground(ColorPriorityP2)
PriorityP3Style = lipgloss.NewStyle().Foreground(ColorPriorityP3)
PriorityP4Style = lipgloss.NewStyle().Foreground(ColorPriorityP4)
Rendering Functions
The RenderPriority function in internal/ui/styles.go:516-534 combines a filled-circle icon (●) with the priority label:
const PriorityIcon = "●"
func RenderPriority(priority int) string {
label := fmt.Sprintf("%s P%d", PriorityIcon, priority)
switch priority {
case 0: return PriorityP0Style.Render(label)
case 1: return PriorityP1Style.Render(label)
case 2: return PriorityP2Style.Render(label)
case 3: return PriorityP3Style.Render(label)
case 4: return PriorityP4Style.Render(label)
default: return label
}
}
A compact variant (RenderPriorityCompact) renders the label without the icon for space-constrained UIs.
Command-Line Interface
Users interact with the priority system through the --priority flag when creating or updating issues. The CLI accepts both numeric values and P-prefixed labels:
# Numeric input
bd create --title "Fix login race" --type bug --priority 0
# P-prefixed input
bd create --title "Add dark theme" --type feature --priority P2
Both formats pass through the same validation layer, ensuring only priorities 0-4 are accepted.
Validation Edge Cases and Testing
The Beads regression suite enforces strict priority behavior through several test scenarios:
- Zero-value handling: Tests verify that
priority=0survives export/import round-trips without being dropped or converted to null values - Escalation testing: Updating from non-critical values to
0works correctly without silently discarding the field - Range validation: The discovery and query protocols validate that priority bounds fall within the 0-4 range
- Invalid input rejection: Text strings like "high" or "urgent" trigger the validation error pathway
These tests reside in tests/regression/scenarios_test.go, tests/regression/discovery_test.go, and internal/validation/bead_test.go.
Working with Priorities in Code
Here's how to programmatically parse and render priorities using the Beads internal API:
package main
import (
"fmt"
"github.com/steveyegge/beads/internal/validation"
"github.com/steveyegge/beads/internal/ui"
)
func main() {
// Parse user-supplied string
p, err := validation.ValidatePriority("P1")
if err != nil {
panic(err)
}
fmt.Println("Parsed priority:", p) // → 1
// Render for terminal display
fmt.Println("Styled:", ui.RenderPriority(p)) // coloured "● P1"
// Compact rendering without icon
fmt.Println("Compact:", ui.RenderPriorityCompact(p)) // "P1"
// Handle invalid input
if _, err := validation.ValidatePriority("high"); err != nil {
fmt.Println("Error:", err)
}
}
Summary
- The priority system in Beads uses numeric values 0-4 mapped to P0-P4 labels, with 0 representing the highest urgency
- Strict validation in
internal/validation/bead.goprevents invalid inputs throughParsePriorityandValidatePriorityfunctions - Color-coded rendering in
internal/ui/styles.goassigns red to P0, orange to P1, and yellow to P2, while P3 and P4 remain neutral - The CLI accepts both numeric (
--priority 0) and prefixed (--priority P0) formats, normalizing them through the validation layer - The system rejects values outside the 0-4 range and descriptive words like "high" or "critical" with explicit error messages
Frequently Asked Questions
What happens if I enter an invalid priority value like "high" or "5"?
The validator returns an error with the message: invalid priority "high" (expected 0-4 or P0-P4, not words like high/medium/low). Values outside the 0-4 range, including negative numbers or numbers greater than 4, trigger the same validation pathway and prevent the operation from proceeding.
Why do P3 and P4 priorities not have colors assigned?
The color scheme in internal/ui/styles.go intentionally limits colored output to the three highest urgency levels (P0-P2) to draw user attention to critical work. P3 and P4 use lipgloss.NoColor{}, which renders in the default terminal color. This design choice prevents visual clutter while maintaining the semantic distinction between medium and lower priorities.
Can I use the priority parsing functions in my own Go code?
Yes. The internal/validation package exposes ParsePriority for direct parsing (returns -1 for invalid inputs) and ValidatePriority for parsing with error handling. Both functions accept strings with optional "P" prefixes and whitespace, making them suitable for parsing user input from various sources beyond the CLI flags.
How does Beads handle priority zero in data exports?
The regression tests specifically verify that priority=0 survives export and import operations without being dropped or converted to a null value. This zero-value handling ensures that critical issues maintain their P0 classification across data persistence boundaries, preventing accidental loss of urgency information during backup or migration operations.
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 →