Authoritative field list for a delivery brief and the linkage fields it stamps on derived specs. A brief lives at docs/product/briefs/<slug>.md. Use author-delivery-brief create to author a Draft from bounded source material; use author-delivery-brief continue to review an existing repository brief and offer confirmed slices. For the workflows, see Intake an external brief into a product brief and Continue a delivery brief and confirm delivery slices; for why the layer exists, see Why a brief layer.
Brief header fields
Section titled “Brief header fields”| Field | Required? | Meaning |
|---|---|---|
Slug | yes | Kebab-case identifier; matches the filename. |
Received | recommended | The date the brief was handed over (YYYY-MM-DD). |
Owner | recommended | Who owns delivering this repo’s slice. |
Epic | optional | Id or link of an external coordinator (a tracker epic, an integration repo) when this repo’s work is one slice of a cross-repo effort. Omit when there is none. This is the only pointer to the wider effort — the repo owns its slice, not a coordination hub. |
Parent intent | optional | The intent this brief was cut from. Write it as the target intent’s registered kind and Slug:, such as outcome:service-reliability or intent:account-self-service. An absent value, or a value that begins with the word none, records no pointer. Distinct from Epic, which names an external coordinator. |
Cut-closed | required only when Status: Shipped; refused when Status: Draft | Records that the cut — the set of delivery slices this brief will ever have — is finalised and no further slices are coming. ISO 8601 date followed by non-empty evidence text (e.g. 2026-08-25 All nine slices are Shipped.); a value in any other shape is refused. Like every field in this table it must sit above the brief’s first ## heading: written below one, or inside an HTML comment, it reads as absent, so a refusal can name a file that visibly contains the line. A template row whose value is only a comment or is empty counts as absent rather than malformed, which is why the shipped template does not trip the gate. |
Brief body sections
Section titled “Brief body sections”| Section | Required? | Meaning |
|---|---|---|
Outcome | yes (load-bearing) | The problem and the user-facing outcome, in the user’s terms. The one field a brief cannot do without — it’s what every slice is measured against. |
Success metrics | optional | Observable signals that the outcome landed (not activities). E.g. “p95 checkout under 400ms”, “reset tickets down 60%”. Stays at brief altitude — see below. |
Scope / Non-goals | yes | The boundary of this repo’s slice. Non-goals are as load-bearing as scope — they stop the decomposition from sprawling. |
Appetite | optional | A constraint, not an estimate: how much time/effort the outcome is worth (“a few weeks, not a quarter”). Bounds the decomposition. |
User stories | optional (Shape B) | Stories with ids (US-1, US-2, …). Present → decomposition groups stories into specs and coverage is story-granular. Absent → Shape A, spec-granular coverage. |
Assumptions / Risks | optional until Ready | Named assumptions or risks that could change the outcome or delivery boundary. At least one is required to reach Ready. |
Spec map | section required for Ready; rows optional | The coverage table. One row per materialized spec; the Status column is auto-derived by the coverage lint (never hand-edited). Shape B adds a Story column. A Ready brief may have zero rows. |
Rabbit holes | optional | Named design traps, constraints, or out-of-bounds explorations to avoid. |
Source | optional until Ready | Durable source provenance. Tracker-origin work also records the reviewed source revision. |
Status | set by the owning workflow | One of Draft, Ready, Executing, Shipped, Withdrawn, or Cancelled. create sets Draft; continue may set Ready; terminal transitions go through close-work. Setting Shipped also requires a Cut-closed record — see § Lifecycle states. |
Keeping Success metrics at brief altitude
Section titled “Keeping Success metrics at brief altitude”A brief sits between the roadmap and a spec, and Success metrics inherits that
altitude. Write each one as an outcome-level observation that can fail, and say
in the section itself that the falsifiable criteria which operationalise them
are spec-owned.
Make each metric bind in both directions. A metric worth keeping is one an over-restrictive implementation fails as surely as a permissive one. “A placement path that escapes its root refuses; one that merely leaves the repository asks” fails both ways. “Unsafe paths are rejected” fails only one.
The tell that the section has dropped below brief altitude is a review finding that asks for a checker name, an exit code, a read boundary, or a fixture cohort. Those are spec-owned details. When a finding asks for one, the section has gone too far down, not too little.
Rebuild rather than patch. Answering a “one-sided contract” finding by adding another criterion makes the section grow, and each addition tends to contradict scope or non-goals somewhere else — so the next round finds more. If the section has taken two rounds of additions, replace it with a handful of outcome-level observations instead of amending it a third time.
Sweep every section the rule touches. Repairing only the section a finding
names leaves the same defect in its siblings — a fixed count removed from
Non-goals can survive in a later section and return as a fresh finding.
DoR gate
Section titled “DoR gate”A brief is Ready — eligible for slice selection by author-delivery-brief continue — only
when the human confirms the canonical gate below. These fields are required to
reach Ready, not required for a Draft:
| Field | Requirement |
|---|---|
Outcome | Present and non-empty |
| In-scope and out-of-scope boundaries | Both explicit |
| Constraints or appetite | Present and non-empty |
| Named assumptions or risks | At least one |
| Durable source provenance | Present; tracker-origin work includes the reviewed source revision |
Spec map | Section present; placeholder rows are not required |
author-delivery-brief create may elicit these fields but always sets Status: Draft and does
not certify readiness. author-delivery-brief continue owns this gate and is the only mode that
sets Status: Ready, after human confirmation. A Ready brief may have zero
materialized specs and remains non-executable until the user confirms a slice.
Lifecycle states
Section titled “Lifecycle states”The tables below and the lint cannot disagree: both are derived from one module, scripts/brief_shape.py in the author-delivery-brief skill, which is the single source of the vocabulary, the coherence rules and the transition set.
| Status | Child-scope rule | Cut-closed: |
|---|---|---|
Draft | No child is Implementing or Shipped. | Refused — Draft means the cut is still open, and a material edit returns a brief here. |
Ready | No child is Implementing or Shipped. | Permitted. |
Executing | At least one child is Implementing or Shipped. | Permitted — a cut may be declared while a slice is running. |
Shipped | Non-empty child set; every child is Shipped. | Required. |
Withdrawn | No child is Implementing or Shipped. | Permitted, not required. |
Cancelled | At least one child is Implementing or Shipped. | Permitted, not required. |
All currently mapped children being Shipped does not close the brief. Keep it
Executing when a later slice is still expected or has not been materialized.
Closeout changes the brief and its matching workspace collection together; it
does not rewrite child specs.
Legal status transitions
Section titled “Legal status transitions”| From | To |
|---|---|
Draft | Ready, Withdrawn |
Ready | Draft, Executing, Withdrawn |
Executing | Ready, Shipped, Cancelled |
Shipped | — terminal |
Withdrawn | — terminal |
Cancelled | — terminal |
A pair of two different states absent from this table is an illegal move. A state paired with itself is not a move. Two edges carry a record obligation: Executing → Shipped must add the Cut-closed: record (required on Shipped, and the state is terminal), and Ready → Draft must clear it (a material edit reopens the cut).
The Spec map
Section titled “The Spec map”A markdown table whose rows the coverage lint reconciles against the specs:
| Spec | Status | ← Shape A (no stories)| --- | --- || `password-reset-request` | Shipped |
| Spec | Story | Status | ← Shape B (story list)| --- | --- | --- || `billing-plan-management` | US-1 | Shipped |- The first column is the spec slug (
docs/specs/<slug>/). - The last column is the auto-derived status — leave it to the lint.
- A brief is delivered only when its own status is explicitly
Shipped, its map is non-empty, and every mapped spec isShipped. A Ready brief with an empty map is valid but not delivered; an Executing brief with an all-shipped current map is also not delivered.
Linkage fields on derived specs
Section titled “Linkage fields on derived specs”author-delivery-brief continue stamps these on the specs it scaffolds (both are additive and optional — a directly-authored spec omits them and stays valid):
| Field / marker | Where | Meaning |
|---|---|---|
Brief: brief:<slug> | spec header (sibling to Constrained by: / Contract:) | Product provenance — the brief this spec was derived from. Write it as brief:<slug>. Readers still accept a legacy repository path in older specs, so nothing written under the old convention breaks. A bare slug is accepted by traceability and the coverage join, but dispatch reconciliation refuses it, so a bare slug still blocks dispatch. Distinct from Constrained by:, which cites the ADRs/RFCs that govern the spec. The coverage map rolls up from these back-links. |
Satisfies: US-n | appended to an acceptance criterion | Story trace (Shape B only). Marks the AC that satisfies story US-n, giving story-granular coverage. Omitted in Shape A. |
How pointer fields are checked
Section titled “How pointer fields are checked”Write a brief’s Parent intent: as the target intent’s registered kind and Slug:, such as outcome:service-reliability or intent:account-self-service. Write a spec’s Brief: as brief:<slug>. New and changed artifacts are checked: each typed pointer must name an existing target of the field’s type. The check is forward-only, so an older artifact you do not touch is not checked. Readers keep accepting legacy repository paths in those older artifacts. An absent value or a value beginning with the word none records no pointer.
The coverage lint
Section titled “The coverage lint”scripts/lint-brief-coverage.py (bundled with author-delivery-brief) reads every spec’s Status: field, follows the Brief: back-links, and rolls each brief’s Spec map up from its children. Behavior:
- Reports each brief as delivered only for explicit
Shippedcloseout with a non-empty all-shipped map; every other state reports not delivered. - Fails when the brief status is absent, unknown, or contradicts child execution evidence — the § Lifecycle states table states the rule per status.
- A spec that back-links a brief but isn’t in that brief’s map is reported untracked (informational) — add the row; it’s not an error.
- A
Shippedbrief carrying noCut-closedrecord is a failure (exit 1). Add the field to the preamble — an ISO 8601 date then evidence text, for example2026-08-25 All nine slices are Shipped. - A
Draftbrief carrying aCut-closedrecord is a failure (exit 1); a material edit reopens the cut, so the declaration is no longer true. Remove it, or move the brief out ofDraft. - A
Cut-closedvalue that is not an ISO 8601 date followed by evidence text is a failure (exit 1). - A brief’s Spec-map Status cell that contradicts the spec’s real status (a hand-edited, stale cell) is a failure (exit 1) — the column is auto-derived and must not be hand-maintained.
- It no-ops (exit 0, silent) when no brief exists.
- The shipped
_template.mdis skipped — it’s the template, not a brief.