Skip to content

PRD Format Reference ​

Complete format documentation for prd.md.

Story Heading Format ​

Each user story is defined by a level-3 (or level-4) markdown heading with an ID and title:

markdown
### ID: Title

The ID must match the pattern LETTERS-NUMBERS (one or more letters, a hyphen, then one or more digits). Headings whose ID doesn't fit this pattern are treated as regular prose, not stories.

Examples:

markdown
### US-001: User Registration
### AUTH-003: Password Reset Flow
### BUG-012: Fix Login Redirect
#### US-042: Also works as a level-4 heading

Recommended: give each PRD its own prefix. IDs only need to be unique within a PRD, and numbering restarts per PRD — so two PRDs that both use the generic US- prefix will each have a US-001. Prefer a short prefix derived from the PRD's feature/domain (AUTH-, BILL-, PRIO-) so stories read unambiguously across PRDs. This is only a readability convention: Chief already namespaces each story's commit as feat: <prd-name>/<ID> - <title> (where <prd-name> is the PRD's directory under .chief/prds/), so it never confuses same-numbered stories from different PRDs even if the prefixes collide.

Story Fields ​

Below each story heading, Chief recognizes these bold-label fields:

FieldFormatRequiredDefaultDescription
Status**Status:** valueNotodoCurrent state: done, in-progress, todo, needs-review, or blocked
Blocked reason**Blockiert (Ben):** textNo—Written by Chief under a blocked status: what blocks the story and what to do about it. Removed when the status changes
Priority**Priority:** NNoDocument orderExecution order (lower = higher priority)
Blocked by**Blocked by:** ID, IDNononeStory IDs that must be done before this story may start
Braucht**Braucht:** OS (why)Noany systemThe operating system the story can only be done on, e.g. macOS (Xcode, signing) or Linux (systemd). See needs
Description**Description:** textNo—Story description (or use freeform prose)

Acceptance Criteria ​

Acceptance criteria use markdown checkboxes:

markdown
- [ ] Criterion not yet met
- [x] Criterion completed

Chief reads checkbox state to track progress. The agent checks boxes as it completes each criterion.

Status Values ​

ValueAliases (also accepted)Meaning
donecomplete, completed, passedStory is complete — Chief skips it
in-progressin progress, startedAgent is actively working on this story
todo(anything unrecognized falls back to this)Story is pending (also the default if Status is absent)
needs-reviewneeds reviewChief parked the story (e.g. after repeated failed attempts). Skipped by the loop and flagged with ◆ in the TUI until a human resets it.
blocked—The agent stopped on something only a person can resolve and said why with <chief-blocked>. Chief writes the reason under the status as **Blockiert (Ben):** …. Skipped by the loop, and so is every story that depends on it, until a person sets it back to todo — chief prep asks about each one. Flagged with ⊘ in the TUI.

Status matching is case-insensitive. Any value Chief doesn't recognize is treated as todo rather than raising an error.

Full Example ​

markdown
# User Authentication

## Overview
Complete auth system with login, registration, and password reset.

## Technical Context
- Backend: Express.js with TypeScript
- Database: PostgreSQL with Prisma ORM
- Auth: JWT tokens in httpOnly cookies

## User Stories

### US-001: User Registration

**Status:** done
**Priority:** 1
**Description:** As a new user, I want to register an account so that I can access the application.

- [x] Registration form with email and password fields
- [x] Email format validation
- [x] Password minimum 8 characters
- [x] Confirmation email sent on registration
- [x] User redirected to login after registration

### US-002: User Login

**Status:** todo
**Priority:** 2
**Description:** As a registered user, I want to log in so that I can access my account.

- [ ] Login form with email and password fields
- [ ] Error message for invalid credentials
- [ ] Remember me checkbox
- [ ] Redirect to dashboard on success

Field Details ​

id (from heading) ​

Parsed from the story heading: ### US-001: Title → id is US-001.

Format: LETTERS-NUMBERS (one or more letters, a hyphen, one or more digits). Headings that don't match aren't parsed as stories.

Example: US-001, US-042, AUTH-001

title (from heading) ​

Parsed from the story heading: ### US-001: User Registration → title is User Registration.

Length: Keep under 50 characters for clean commit messages.

description ​

The text after **Description:**, or freeform prose between the heading and the first checkbox list.

Format: "As a [user], I want [feature] so that [benefit]." recommended but not required.

acceptanceCriteria (checkboxes) ​

The - [ ] / - [x] items under each story heading. The agent uses these to know when the story is complete.

Guidelines:

  • Specific and testable
  • One requirement per item
  • 3-7 items per story

priority ​

Lower numbers = higher priority. Chief always picks the incomplete story with the lowest priority number first. If omitted, stories are selected in document order.

Range: Any positive number (integers or decimals). A value that isn't a positive number is ignored, and the story falls back to document order.

needs ​

The operating system a story can only be done on, and why: **Braucht:** macOS (Xcode, signing), **Braucht:** Linux (systemd), **Braucht:** Windows (installer). **Needs:** and **Requires:** are read as well. Internally the parsed field is needs.

Only the system is compared, deterministically, with the one Chief runs on. It is found as a word anywhere in the value, in any case — macOS 14+, macOS/Xcode, Xcode (macOS) all name macOS (macOS, Mac, Mac OS X, OS X, OSX, darwin → macOS; Linux, Ubuntu, Debian → Linux; Windows); the rest is for the reader. A story for another system is skipped like a parked one — on a box, which runs Linux, every macOS story is — and so is every story that depends on it. Locally on a Mac the same stories run normally. A value naming no system Chief knows, or more than one, is ignored, so a typo never keeps a story from running at all — but chief start, chief box up and the box's run log warn about it, since the story then runs everywhere.

chief prep writes these lines for you and offers to split a story whose code runs anywhere from the part that needs one system, so the stories after it are not held back.

blockedBy ​

A comma-separated list of story IDs that must be done before this story may start. Omit the line entirely for stories with no dependencies. Internally the parsed field is blockedBy.

Format: **Blocked by:** US-001, US-002 — one or more story IDs separated by commas.

Effect on selection: Chief selects the next story from the frontier — the stories that are not done, not needs-review, and whose every Blocked by ID is already done. A blocked story stays off the frontier (and is never picked) until all of its blockers complete, regardless of its priority. Priority only orders stories that are already on the frontier. See Story Selection Logic for the full algorithm.

Robustness rules: parsing is lenient so an authoring mistake can't deadlock the loop.

  • An unknown or misspelled blocker ID (matching no story in the PRD) is treated as satisfied and ignored.
  • A self-reference (a story listing its own ID) is ignored.
  • Duplicate IDs are harmless.
  • If a dependency cycle (or a chain of stories all blocked by a parked needs-review story) leaves the frontier empty while unfinished, non-parked work still remains, Chief falls back to the lowest-priority unfinished, non-parked story so the loop always makes progress.
  • A story that depends on a blocked story — directly or through others — is never picked, not even by that fallback: it waits until the blocked story is released and done.

status ​

Tracked by Chief. Set to in-progress when work begins, done when the agent outputs <chief-done/> and a matching commit lands, needs-review when a story is parked after repeated failed attempts, and blocked at once when the agent outputs <chief-blocked>reason</chief-blocked>.

Values: done, in-progress, todo (default if absent), needs-review, blocked — plus the case-insensitive aliases listed under Status Values

Parsing Behavior ​

Chief parses prd.md leniently rather than validating it against a strict schema. It reads the markdown structure and extracts whatever it recognizes; it does not reject a PRD for missing or malformed fields. Concretely:

  • Only file-read errors fail. If prd.md can be read, parsing succeeds. There's no separate validation step that exits with an error for structural problems.
  • Unrecognized headings are skipped. A heading whose ID doesn't match LETTERS-NUMBERS is treated as prose, not a story — so a typo silently drops the story rather than raising an error.
  • Unknown status values fall back to todo instead of erroring.
  • Non-positive or non-numeric priorities are ignored, leaving the story in document order.
  • Duplicate IDs are not detected. Chief keeps every parsed story as-is; it does not deduplicate or warn.
  • Blocked by parsing is lenient. Unknown or misspelled blocker IDs are ignored rather than raising an error, and a story can't block itself — so a typo in a Blocked by line can't deadlock the loop.

Because of this, the most common "why isn't my story being picked up?" cause is a heading whose ID doesn't fit the LETTERS-NUMBERS pattern. See Common Issues → Invalid PRD Format for how to spot it.