Customizing the spec scaffold
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
Section titled “Template discovery”The bundled canonical scaffold lives at ${PLUGIN_ROOT}/templates/spec.md. In Flow-Next 1.1.3+, /flow-next:capture, /flow-next:interview, and /flow-next:plan resolve the scaffold through a three-tier cascade, and since fn-220 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:
<repo_root>/SPEC.md<repo_root>/spec.md- 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. A leftover .flow/templates/spec.md from an older install is no longer consulted - delete it.
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
Section titled “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.
# from your repo rootcp "$CLAUDE_PLUGIN_ROOT/templates/spec.md" SPEC.md$EDITOR SPEC.mdgit 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:
## 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 interview 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<n>:** 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<n>:** markers stay English so the tooling keeps reading them. |
Composable with 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 | The business interview pass loses a write target. |
## Decision Context | Flat-versus-substructured detection for ### Motivation / ### Implementation Tradeoffs. |
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.
Mark your sections so the interview can fill them. flowctl scope write-policy enumerates the seven canonical sections only, so a section you add sits in neither its writable nor its preserved list. Ownership of a project-added section therefore comes from the section’s own scope-owner marker, and /flow-next:interview applies a three-way rule:
| Marker on your section | What an interview pass does |
|---|---|
names the pass’s own scope, e.g. <!-- scope: business --> under --scope=business | writes it, filling and refining it like a canonical section |
| names the other scope | preserves it byte-for-byte |
<!-- scope: both --> | writable under any pass |
| absent or unparseable | preserves it byte-for-byte and says so in the read-back |
The marker is the difference between a section that gets filled and one that stays frozen. Add one when you want the interview to do the work, leave it off when the section is yours to hand-write. Two consequences: a marked section is rewritable, so hand-authored content under a marker you own will be refined by the next pass of that scope, and scope-owner markers must be kept on project-added sections rather than stripped, because for those the marker is the only ownership signal a later pass has.
/flow-next:capture and /flow-next: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.
Setup template copy
Section titled “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:
Copy template / Skip / abortOn 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:
Keep mine / Overwrite with canonical / abortThe 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, the interview passes) is in Writing specs.