# Customizing the spec scaffold

Source: https://flow-next.dev/guides/spec-scaffold/

The template cascade, house-style overrides, the four headings flowctl parses, and what setup copies.

Most projects never touch this page. Read it once, when your team wants every spec to carry something the bundled scaffold does not: a risk register, a rollout runbook, user-story criteria, a compliance block.

## Template discovery

The bundled canonical scaffold lives at `${PLUGIN_ROOT}/templates/spec.md`. In Flow-Next 1.1.3+, `/flow-next:capture`, `/flow-next:refine`, and `/flow-next:plan` resolve the scaffold through a three-tier cascade, and since 4.15.0 `flowctl spec create` and `flowctl spec skeleton` apply the same cascade, so a repo `SPEC.md` shapes CLI-created specs too (the old six-heading CLI skeleton is gone). First match wins:

1. `<repo_root>/SPEC.md`
2. `<repo_root>/spec.md`
3. bundled `${PLUGIN_ROOT}/templates/spec.md`

Migrating from a pre-4.0.0 install: a customized `.flow/templates/spec.md` is no longer read - copy it to a repo-root `SPEC.md` (tier 1) to keep your scaffold, then delete the old file.

Use the repo-root `SPEC.md` or `spec.md` when a project needs a customized scaffold. That matches Flow-Next’s other repo-root guidance files such as `STRATEGY.md`, `CLAUDE.md`, `AGENTS.md`, and `GLOSSARY.md`.

The bundled plugin template is the fallback and source of truth when the repo has not opted into customization.

Case-insensitive filesystems such as macOS APFS and Windows NTFS collapse `SPEC.md` and `spec.md` to one inode, so Flow-Next treats that as a single tier-one hit. On case-sensitive filesystems where both files exist distinctly, `SPEC.md` wins and Flow-Next warns.

## Adding your own sections

The bundled section list is a default, not a requirement. Tier one exists so a project can impose its own spec shape without forking the plugin. If your team wants user stories on every spec, a risk register, a rollout runbook, a compliance block or a data-retention statement, add it and every spec that project authors carries it from then on.

```bash
# from your repo root
cp "$CLAUDE_PLUGIN_ROOT/templates/spec.md" SPEC.md
$EDITOR SPEC.md
git add SPEC.md && git commit -m "docs: project spec scaffold"
```

Commit it. The scaffold is a team artifact, and an uncommitted `SPEC.md` gives you a spec shape your teammates and your CI agents do not have.

**Free to change:** adding sections, reordering them, and rewriting the guidance prose under any heading. That prose is instruction to the authoring agent, so making it say what your project actually needs is the highest-leverage edit and the one most often skipped.

A worked example - **house style for acceptance criteria**. Want BDD-flavored criteria on every spec? Rewrite the guidance under `## Acceptance Criteria` in your copied `SPEC.md`:

```markdown
## Acceptance Criteria


<!-- House style: write each criterion as a BDD scenario - Given <context>,
     when <action>, then <observable outcome>. Keep the **R<n>:** marker;
     use sibling ids (R4a, R4b) for scenario variants of one requirement. -->


- **R1:** Given a signed-in user with an expired session, when they submit the form, then the draft is preserved and they are returned to it after re-auth.
```

Every refine and capture pass then writes criteria in that shape. Only the heading name and the `**R<n>:**` bullet marker are load-bearing - the criterion *text* is yours (the parser reads wrapped multi-line bullets, and anything unreadable surfaces as `acceptance_criteria_residue` rather than being silently dropped). The same move carries any house convention.

More house styles, same mechanism - each is one instruction comment (or one rewritten guidance line) in your copied `SPEC.md`, and every spec the project authors from then on obeys it:

| Team wants                              | Instruction to add under the relevant heading                                                                                                                                                                                            |
| --------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **User-story criteria** (product orgs)  | Under `## Acceptance Criteria`: *“Phrase each criterion as: As a \<role>, I can \<capability>, so that \<outcome> - observable outcome mandatory, keep the `**R&lt;n&gt;:**` marker.”*                                                   |
| **Observability mandate** (SRE-minded)  | Under `## Acceptance Criteria`: *“Every criterion names the signal that proves it in production - a metric, log line, or alert. A criterion with no signal is not accepted.”*                                                            |
| **Compliance traceability** (regulated) | Under `## Acceptance Criteria`: *“Tag each criterion with the control it satisfies (e.g. `[SOC2-CC6.1]`, `[GDPR-Art17]`).”* Plus an added `## Data & Compliance` section: classification of data touched, retention, audit-trail impact. |
| **Non-functional budgets**              | An added `## Budgets` section: *“State the numeric budgets this change must hold: p95 latency, bundle-size delta, WCAG level. ‘Fast’ is not a budget; ‘<200ms p95’ is.”*                                                                 |
| **Rollout & revert** (ops)              | An added `## Rollout` section: *“Feature flag or migration? Name the flag, the rollout stages, and the tested revert path. A migration with no revert statement is incomplete.”*                                                         |
| **Test-evidence rule**                  | Under `## Acceptance Criteria` or `## Boundaries`: *“Every criterion names the command or test file that will prove it - the worker baselines and re-runs exactly those.”*                                                               |
| **Specs in your language**              | Rewrite the guidance prose in German/French/Japanese/… - the authoring passes follow the instruction language, and the four parsed headings plus `**R&lt;n&gt;:**` markers stay English so the tooling keeps reading them.               |

Composable with [additional role passes](https://flow-next.dev/guides/writing-specs/#additional-role-passes): a platform or quality role’s standing section is just another row of this table.

**Handle with care:** four headings are parsed by `flowctl`. Renaming or removing one does not raise an error, it silently drops a feature. Historical specs written with the older names (`## Overview` or `## Context`, `## Boundaries / non-goals`, any-case `## Decision context`) are still read through read-only synonyms, and `flowctl validate` prints one `legacy spec headings` warning per such spec as the nudge to migrate; text inside HTML comments and fenced code never counts as a heading or a criterion.

| Heading                  | What stops working                                                                                                                                                                                             |
| ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `## Acceptance Criteria` | R-ID extraction. Coverage tables come out empty, task `satisfies:` mapping breaks, unaddressed-R-ID verdict gating stops firing. Legacy `## Acceptance criteria` and bare `## Acceptance` are still tolerated. |
| `## Boundaries`          | The “Not in this PR” section of a generated PR body loses its source.                                                                                                                                          |
| `## Goal & Context`      | `flowctl brief` falls back to the body’s first line for the spec’s goal, and the PR briefing loses its goal.                                                                                                   |
| `## Decision Context`    | The PR briefing loses its list of recorded decisions.                                                                                                                                                          |

Keep R-ID bullets in the form `- **R1:** <criterion>`, with optional single-letter siblings such as `R4a`. Prose numbering like “Requirement 1” is not recognized.

**Your sections need no markers.** [`/flow-next:refine`](https://flow-next.dev/skills/refine/) writes each answer into the section it belongs in, custom or canonical, and leaves every section no answer belongs in byte-for-byte. The read-back before writing names every section the session changed, including yours. Older specs that still carry `<!-- scope: ... -->` markers load and refine unchanged.

[`/flow-next:capture`](https://flow-next.dev/skills/capture/) and [`/flow-next:plan`](https://flow-next.dev/skills/plan/) seed from the template directly and are unaffected.

We tested widening the bundled scaffold with user-story and test-seam sections. A first pass looked promising, a pre-registered replication did not hold up, and the wider scaffold ran roughly a third longer, which every worker and reviewer downstream pays to read. So the default stays lean and this override stays the place to express a project preference.

## Leaving a section out

Since 5.5.1, `/flow-next:capture` writes the sections your template names and adds none it leaves out. Before that, capture put a `## Conversation Evidence` block at the top of every spec and a `## Requirement coverage` table at the end, whatever your `SPEC.md` said.

The seven canonical sections are named as headings. The auxiliary sections (`Conversation Evidence`, `Strategy Alignment`, `Parked unknowns`, `Requirement coverage` and the rest) are named in the frontmatter `auxiliary_sections` list, and each still appears only when its own trigger fires. To stop one from landing in your specs, delete its entry from that list in your `SPEC.md`.

| Entry                   | What it is                                                                                              | What dropping it costs                                                                                                                                                                                                                      |
| ----------------------- | ------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Conversation Evidence` | The verbatim user quotes capture puts at the top of a spec, typically 15 to 20 lines. No tool reads it. | A reviewer who later doubts that an untagged line is the user’s own words can no longer look the quote up in the spec. Capture still collects the quotes during the run and still checks every untagged line against them before it writes. |
| `Requirement coverage`  | The placeholder table capture adds when the spec is headed for a plan.                                  | Nothing. [`/flow-next:plan`](https://flow-next.dev/skills/plan/) writes its own coverage table, so the table arrives with the plan.                                                                                                         |

Position follows the template as well. An auxiliary section you place as a heading in your `SPEC.md` lands where you put it. One named only in the list takes the placement its list entry states, which for the bundled entries is evidence at the top of the body and coverage at the end.

One consequence to know about. A `SPEC.md` written from scratch, with no `auxiliary_sections` list, gets no auxiliary sections from capture. A `SPEC.md` copied from the bundled file keeps the list and behaves as before. If you wrote yours by hand and want the strategy or parked-unknowns sections, copy the list across from the bundled template.

## Setup template copy

`/flow-next:setup` Step 4a offers a repo-root spec template when neither `<repo_root>/SPEC.md` nor `<repo_root>/spec.md` exists:

```txt
Copy template / Skip / abort
```

On consent, setup writes `<repo_root>/SPEC.md` from the bundled template. It always writes uppercase `SPEC.md`, preserves file mode `0644`, and never creates lowercase `spec.md`.

On re-setup, Flow-Next uses a byte-compare gate:

```txt
Keep mine / Overwrite with canonical / abort
```

The compare normalizes CRLF to LF and ignores trailing-newline differences, so real project customizations are not silently clobbered.

Authoring guidance for the spec itself (what to include, the ready flag, when to refine) is in [Writing specs](https://flow-next.dev/guides/writing-specs/).
