Spec-driven planning files (schema 1.0.0)
This is the file-level reference for spec-driven mode: what the planr-spec,
planr-plan, and planr-ship skills write under .planr/specs/, and what the
openplanr spec commands validate. The canonical JSON Schemas live in
packages/protocol/schemas/v1.0.0;
the CLI and the planr-pipeline package read the same contract with no
conversion layer.
When authoring these files by hand, use the templates below verbatim.
Schema version:
1.0.0Pinning rule: theschemaVersionfield on every artifact MUST match the reader's expected version. Breaking changes start in the Protocol schema source and are mirrored here before release.
Directory layout
Every spec is a self-contained directory under .planr/specs/:
.planr/specs/SPEC-NNN-{slug}/
├── SPEC-NNN-{slug}.md # the functional spec (one per directory)
├── design/ # optional — UI mockups + design-spec
│ ├── *.png # PNG mockups attached via `openplanr spec attach-design`
│ └── design-spec.md # written by the designer agent
├── stories/
│ └── US-NNN-{slug}.md # user stories scoped to this spec
├── tasks/
│ └── T-NNN-{slug}.md # tasks scoped to this spec
├── qa-report.md # written by the QA agent after planr-ship
├── error-report.md # written if a task fails 3 iterations
└── .pipeline-shipped # written by planr-ship — proof of executionID scoping rule: in spec-driven mode, US-NNN and T-NNN are scoped to
their parent SPEC, not project-globally unique. Two specs can each have
their own US-001. Disambiguate via path or via the specId frontmatter field.
SPEC frontmatter
---
id: "SPEC-001" # required · format: SPEC-\d{3}
title: "User authentication" # required · human-readable title
slug: "auth" # required · URL-safe lowercase, used in path
schemaVersion: "1.0.0" # required · pinned to reader version
status: "pending" # required · pending | shaping | shaped | decomposing | decomposed | in-pipeline | done
priority: "P0" # required · P0 | P1 | P2 | P3
milestone: "v1.0" # optional · links to a milestone or release
po: "product-owner" # optional · spec owner (Product Owner)
created: "2026-04-26" # required · ISO date (YYYY-MM-DD)
updated: "2026-04-26" # required · ISO date, bumped on edit
ui_files: [] # required · array of PNG paths under design/ (empty if none)
tech_dependencies: [] # required · array of strings; informational only
---Field meanings
| Field | Type | Meaning |
|---|---|---|
id | string | Project-globally unique. Format SPEC-NNN (3-digit). The directory MUST be SPEC-NNN-{slug}/. |
title | string | Display title. Human-readable. |
slug | string | URL-safe lowercase. Used in the directory name and in story and task slugs. |
schemaVersion | string | Pinned schema version. 1.0.0 currently. Readers MUST refuse mismatched versions. |
status | enum | Lifecycle marker: pending (just created) → shaping (questions in progress) → shaped (body authored) → decomposing (planning in progress) → decomposed (stories and tasks written) → in-pipeline (ship in progress) → done (shipped). |
priority | enum | P0 (must) / P1 (should) / P2 (nice) / P3 (defer). |
milestone | string? | Optional release/milestone tag. |
po | string? | Optional Product Owner identifier (email or username). |
created / updated | string | ISO 8601 date. Bumped automatically by openplanr spec commands. |
ui_files | array | List of PNG file paths under design/. Non-empty lists route the designer agent. |
tech_dependencies | array | Free-form list of upstream tech dependencies. Informational; not consumed automatically. |
SPEC body sections (in order)
The spec body uses the following H2 sections. openplanr spec shape writes them
from interactive questions; the planr-plan skill reads them.
## Context & Goal— 2-5 sentences on the user need + outcome## Functional Requirements— bullet list, action verbs## Business Rules— constraints and validations## User Flows— numbered step-by-step flows## Out of Scope— explicit non-goals## Acceptance Criteria— Given/When/Then bullets## Notes for Decomposition(optional) — hints for planning, NOT requirements
The ## Notes for Decomposition section is freeform prose hinting at the
intended story split, special attention areas, or files to preserve. The
planr-plan skill reads it to bias its output. Example:
- Suggested US split: auth flow (UI), session management (Tech)
- Special attention: the delete flow needs a confirmation dialog
- Preserve: do not modify the existing UserServiceStory frontmatter
Stories live at .planr/specs/SPEC-NNN-{slug}/stories/US-NNN-{story-slug}.md.
---
id: "US-001" # required · format: US-\d{3} (scoped to parent SPEC)
title: "Login form" # required
specId: "SPEC-001" # required · MUST match parent spec id
slug: "login-form" # required · URL-safe; matches filename suffix
schemaVersion: "1.0.0" # required
status: "pending" # required · pending | in-progress | done
priority: "P0" # required · P0 | P1 | P2 | P3
created: "2026-04-26" # required
updated: "2026-04-26" # required
---Story body sections
# US-001 — Login form
> **Spec:** SPEC-001
## Story
As a **<role>** I want **<action>** so that **<benefit>**.
## Scope
<2-3 sentences describing what's in scope for this story>
## Acceptance Criteria
- [ ] Given <context>, when <action>, then <observable outcome>.
- [ ] Given …, when …, then …
## Dependencies
<Optional: tasks or stories this depends on, by id>Task frontmatter
Tasks live at .planr/specs/SPEC-NNN-{slug}/tasks/T-NNN-{task-slug}.md.
---
id: "T-001" # required · format: T-\d{3} (scoped to parent SPEC)
title: "Build login form component" # required
storyId: "US-001" # required · MUST match a story id under the same spec
specId: "SPEC-001" # required · MUST match the parent spec id
slug: "login-form-component" # required · URL-safe; matches filename suffix
schemaVersion: "1.0.0" # required
type: "UI" # required · "UI" | "Tech"
agent: "frontend-agent" # required · subagent that owns this task
status: "pending" # required · pending | in-progress | done
created: "2026-04-26" # required
updated: "2026-04-26" # required
---Type → agent mapping
type | Default agent | Notes |
|---|---|---|
UI | frontend-agent | UI-focused work: components, pages, styles |
Tech | backend-agent | Backend, services, controllers, DTOs, migrations |
The frontend-agent reads tasks where type: UI; the
backend-agent reads tasks where type: Tech. Setting agent to a different
value (e.g. a custom subagent name) overrides the default routing.
Task body sections
# T-001 — Build login form component
> **User Story:** US-001
> **Spec:** SPEC-001
> **Type:** UI
> **Agent:** `frontend-agent`
## Objective
<1-2 sentences: what does this task accomplish?>
## Files
### Create
- `src/components/auth/LoginForm.tsx`
- `src/components/auth/LoginForm.test.tsx`
### Modify
- `src/app/login/page.tsx` (mount the component)
### Preserve
- `src/app/layout.tsx` (do not touch)
- `package.json` (do not add dependencies)
## Technical Spec
<Implementation detail: libraries, patterns, integration points.
The frontend or backend agent reads this verbatim.>
## Test Requirements
<Build / test commands and DoD checks. The qa-agent reads this to
verify completion.>
## Definition of Done
- [ ] Code compiles (`npm run build`)
- [ ] Tests pass (`npm test`)
- [ ] Lint clean
- [ ] All Create files exist
- [ ] All Modify files updated only as described
- [ ] All Preserve files unchanged (verified via `git diff`)The ### Create / ### Modify / ### Preserve lists are NOT optional —
the qa-agent verifies them via git diff before accepting the task as done.
A task that touches files outside these lists fails QA.
.pipeline-shipped marker
Written by the planr-ship skill at the end of a successful (or
partially successful) run. This is the canonical proof that the work was
shipped through the workflow, not a hand-authored Markdown file.
shipped_at: "2026-04-26T22:30:00Z"
pipeline_version: "0.4.0"
mode: "spec-driven"
feature: "auth"
tasks_executed: 3
tasks_failed: 0
qa_gate_status: "passed"
duration_seconds: 287
agents_invoked:
- frontend-agent
- backend-agent
- qa-agent
- devops-agent
- doc-gen-agent
devops_status: "generated"
docs_status: "generated"
snapshot_status: "refreshed"
error_reports: []If the marker is absent, the work was not shipped through the workflow. Audit
trails reference this file by path: .planr/specs/SPEC-NNN-{slug}/.pipeline-shipped.
Status lifecycle (the full path)
A spec moves through these states, in order:
pending → shaping → shaped → decomposing → decomposed → in-pipeline → done| State | Set by | Meaning |
|---|---|---|
pending | openplanr spec create | Spec directory exists; body is the empty template |
shaping | openplanr spec shape (in progress) | Q&A flow active |
shaped | openplanr spec shape (complete) | Spec body has Context/FRs/Rules/AC sections filled |
decomposing | planr-plan skill (in progress) | Stories and tasks are being written |
decomposed | planr-plan skill (complete) | stories/ and tasks/ are populated |
in-pipeline | planr-ship skill (in progress) | Implementation running |
done | planr-ship skill (complete) | Tasks executed, QA passed, marker written |
Schema version compatibility
The CLI, the skills, and the planr-pipeline package produce and consume schema
1.0.0. Breaking changes bump schemaVersion in lockstep. Keep them aligned:
npm install -g openplanr@latest
openplanr setup
openplanr upgrade status