# How the Priority System Works in Beads: P0-P4 Implementation Explained

> Understand the Beads priority system P0-P4 with clear explanations. Learn how to implement this validated, color-coded system for effective task management.

- Repository: [Gas Town Hall/beads](https://github.com/gastownhall/beads)
- Tags: deep-dive
- Published: 2026-04-27

---

**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`](https://github.com/gastownhall/beads/blob/main/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.

```go
// 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.

```go
// 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`](https://github.com/gastownhall/beads/blob/main/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`:

```go
// 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:

```go
// 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:

```go
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:

```bash

# 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=0` survives export/import round-trips without being dropped or converted to null values
- **Escalation testing**: Updating from non-critical values to `0` works 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`](https://github.com/gastownhall/beads/blob/main/tests/regression/scenarios_test.go), [`tests/regression/discovery_test.go`](https://github.com/gastownhall/beads/blob/main/tests/regression/discovery_test.go), and [`internal/validation/bead_test.go`](https://github.com/gastownhall/beads/blob/main/internal/validation/bead_test.go).

## Working with Priorities in Code

Here's how to programmatically parse and render priorities using the Beads internal API:

```go
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.go`](https://github.com/gastownhall/beads/blob/main/internal/validation/bead.go) prevents invalid inputs through `ParsePriority` and `ValidatePriority` functions
- **Color-coded rendering** in [`internal/ui/styles.go`](https://github.com/gastownhall/beads/blob/main/internal/ui/styles.go) assigns 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`](https://github.com/gastownhall/beads/blob/main/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.