Feature directory format reference
nWave supports two directory layouts for feature documentation: legacy (multi-file per wave) and lean (single L7 file).
Quick reference
| Aspect | Legacy | Lean L7 |
|---|---|---|
| Layout | docs/feature/{id}/discuss/, design/, distill/, deliver/ subdirs with separate files |
Single feature-delta.md per feature |
| Identifier | No marker (implicit legacy) | FORMAT: lean in dir or file frontmatter |
| Section typing | No explicit type labels | ## Wave: <WAVE> / [REF|WHY|HOW] <Section> headings |
| Concurrent waves | Manual conflict resolution | Git auto-resolves via wave-owned section ownership |
| Density control | Not applicable | lean (refs only) or full (all sections) |
| Tooling | Existing scripts, agents familiar | Validator: scripts/validation/validate_feature_delta.py |
| Status | In-place; no migration required | Greenfield new features; opt-in migration available |
Legacy layout (multi-file)
The legacy layout organizes wave outputs into separate files grouped by wave.
Directory structure
docs/feature/{feature-id}/
├── discover/
│ ├── research-notes.md
│ ├── evidence.md
│ └── opportunity-statement.md
├── discuss/
│ ├── elevator-pitch.md
│ ├── job-statement.md
│ ├── user-stories.md
│ ├── acceptance-criteria.md
│ ├── definition-of-done.md
│ └── dor-validation.md
├── design/
│ ├── component-decomposition.md
│ ├── decisions.md
│ ├── driving-ports.md
│ └── adr-001.md
├── distill/
│ ├── acceptance-scenarios.feature
│ ├── test-strategy.md
│ └── edge-cases.md
├── deliver/
│ ├── implementation-notes.md
│ ├── commits.md
│ └── retrospective.md
└── wave-decisions.md (optional, consolidated decisions across all waves)
Characteristics
- File-per-concern: Each artifact (user stories, decisions, scenarios, etc.) is a separate
.mdfile. - Wave-grouped: Files live in subdirectories named after the wave they belong to.
- No sectioning discipline: Headings are free-form within each file.
- Merge conflicts: Parallel waves writing to the same file can create merge conflicts in git.
- Existing features: All currently-tracked features in the repo use this layout.
When to use
- Existing features that are already documented in legacy layout.
- Teams with established conventions for file organization.
- Features where per-file separation helps with parallel authoring (e.g., separate writer per wave).
Lean L7 layout (single-file)
The lean L7 layout consolidates all wave outputs into a single feature-delta.md file with schema-typed section headings.
Directory structure
docs/feature/{feature-id}/
├── feature-delta.md # Single file, all waves, schema-typed headings
└── FORMAT # Optional marker containing "lean"
Alternatively, the FORMAT information can be recorded in YAML frontmatter at the top of feature-delta.md:
---
format: lean
---
# feature-delta — {feature-id}
## Wave: DISCOVER / [REF] Research findings
...
Single narrative + machine companions (R5, 2026-04-28)
The lean contract is not "one file ever". It is "one narrative file plus declared machine companions plus SSOT integration". Some waves legitimately emit machine-parseable companions alongside feature-delta.md:
| Wave | Machine companion(s) | Why declared |
|---|---|---|
| DEVOPS | environments.yaml |
DISTILL parses environment matrix to parametrize acceptance scenarios |
| DISTILL | *.feature files + steps/** modules |
Executable Gherkin specs; pytest-bdd discovery requires per-file layout |
| DELIVER | roadmap.json, execution-log.json |
DES self-host runtime parses these for phase tracking |
| All waves | slices/slice-NN-*.md (when used) |
Per-slice briefs are inherently per-file; PO reviewer enforces composition |
| All waves | spike/findings.md, spike/wave-decisions.md |
Spike isolation; promoted into feature-delta.md only on PROMOTE verdict |
| Bug fixes | bugfix/rca.md |
RCA artifacts kept separate from feature-delta narrative |
Machine companion rule: only files whose downstream consumer is a parser (validator, agent, runtime) qualify. Loose human-readable markdown does NOT qualify and MUST live inside feature-delta.md as a ## Wave: <NAME> / [REF|WHY|HOW] <Section> block.
Validator: scripts/validation/validate_feature_layout.py enforces the whitelist. See docs/analysis/investigation-overtesting-hypothesis-2026-04-28.md for audit findings that motivated this rule.
SSOT integration (separate concern): each wave back-propagates to docs/product/ (jobs.yaml, journeys/, personas/, architecture/, kpi-contracts.yaml). See each wave skill's "SSOT updates" subsection for paths.
Section heading schema
Every section heading in a lean L7 file follows this pattern:
## Wave: <WAVE> / [<TYPE>] <Section name>
Components:
<WAVE>: One ofDISCOVER,DISCUSS,DESIGN,devOPS,DISTILL,DELIVER<TYPE>: One of three:[REF]: Reference/factual content — definitions, specs, acceptance criteria, locked decisions, user stories (Elevator Pitch only), scenarios, deliverables.[WHY]: Explanatory/rationale content — persona narrative, JTBD analysis, design alternatives weighed, architecture rationale, retrospective insights.[HOW]: Procedural/instructional content — migration guides, integration steps, manual processes, troubleshooting guides.
<Section name>: Human-readable title (e.g.,User stories,Acceptance scenarios,Decisions,Persona narrative).
Examples
Lean output (default, when density is lean):
## Wave: DISCUSS / [REF] Persona
Marco — solo developer iterating on nWave.
## Wave: DISCUSS / [REF] Job-to-be-done
When I run /nw-discuss on a small feature, I want the wave to produce only load-bearing content so my session stays under token budget.
## Wave: DISCUSS / [REF] User stories
### US-1: Lean-by-default wave output
Elevator Pitch: Marco runs /nw-discuss and gets a feature-delta.md with only [REF] sections.
...
## Wave: DESIGN / [REF] Component decomposition
| # | Component | Path | Change type | Owner wave consumer |
|---|---|---|---|---|
| C1 | Wave skill — DISCUSS | nWave/skills/nw-discuss/SKILL.md | Edit | DISCUSS |
Full output (when density is full):
## Wave: DISCUSS / [REF] Persona
Marco — solo developer iterating on nWave.
## Wave: DISCUSS / [WHY] Persona narrative
Marco's goals: fast iteration, low token cost, scale to bigger features...
## Wave: DISCUSS / [REF] Job-to-be-done
When I run /nw-discuss on a small feature...
## Wave: DISCUSS / [WHY] JTBD narrative
Four forces analysis: push (token bloat), pull (context efficiency), anxiety (missing decisions), habit (legacy multi-file)...
Wave-owned section ownership (D3)
Critical rule for concurrent waves: each wave owns its own wave heading. No wave appends sections to another wave's heading.
Valid concurrent edits:
## Wave: DISCUSS / [REF] Decisions (wave A writes here)
...
## Wave: DESIGN / [REF] Decisions (wave B writes here)
...
Invalid (violates D3):
## Wave: DISCUSS / [REF] Decisions
... (initial content by DISCUSS)
More content added by DESIGN ← WRONG: DESIGN cannot append to DISCUSS's section
When two waves write independently under their own headings, git auto-resolves the merge cleanly.
Characteristics
- Single file: All wave outputs consolidated.
- Schema-typed headings: Every heading declares its content type via
[REF]/[WHY]/[HOW]prefix. - Density-aware: Lean mode emits only
[REF]; full mode emits[REF]+[WHY]+[HOW]. - Expansion-ready: Optional
[WHY]and[HOW]sections can be added post-wave via--expandflag. - Auto-merge friendly: Wave-owned sections in separate headings avoid conflicts.
- Agent-grep friendly: Downstream agents can grep for specific section types and waves.
When to use
- New features: All greenfield features should use lean L7.
- Token-conscious workflows: Teams minimizing context bloat.
- Parallel wave execution: Features running multiple waves on separate worktrees.
- Audit compliance: Teams requiring clear traceability of who wrote what in which wave.
Migration: legacy to lean L7
An opt-in migration script is available to convert existing legacy features to lean L7 format.
Automatic migration
python scripts/migrate_to_l7.py docs/feature/my-feature
The script:
- Reads files from
docs/feature/my-feature/{discover,discuss,design,devops,distill,deliver}/ - Classifies each artifact (user story, decision, scenario, etc.) by heuristic rules.
- Writes
docs/feature/my-feature/feature-delta.mdwith proper## Wave: ... / [TYPE]headings. - Demotes optional expansions (JTBD narrative, persona narrative, migration playbooks) to
[WHY]/[HOW]sections (not auto-included in lean mode). - Creates a
FORMATfile or adds frontmatter tofeature-delta.mdmarking the feature aslean. - Leaves legacy subdirectories in place for git diff inspection (not deleted automatically).
Run python scripts/migrate_to_l7.py --help for full usage, including:
--dry-run: See what would be migrated without writing.--force: Overwrite an existingfeature-delta.md.--preserve-legacy: Keep legacy subdirectories (default); append--no-preserve-legacyto delete them after migration.
Rollback
If migration produces unexpected results:
git checkout docs/feature/my-feature/
This restores the directory to its last-committed state. The script leaves legacy subdirectories untouched, so you can inspect and re-run.
Schema validation (developer)
nWave provides a validator to ensure lean L7 files conform to the heading schema.
Running the validator
python scripts/validation/validate_feature_delta.py docs/feature/my-feature/feature-delta.md
Exit codes:
0: Valid. Headings match the schema.1: Invalid. Malformed headings detected (see stderr for details).
Output: Validator reports the count of [REF], [WHY], and [HOW] sections per wave, plus any errors.
Common validation failures
| Error | Cause | Fix |
|---|---|---|
Malformed heading: missing [TYPE] prefix |
## Wave: DISCUSS / User stories (missing [REF]) |
Add the type: ## Wave: DISCUSS / [REF] User stories |
Invalid wave name: ANALYSE |
## Wave: ANALYSE / ... (typo) |
Correct to one of: DISCOVER, DISCUSS, DESIGN, DEVOPS, DISTILL, DELIVER |
Invalid type: [EXPLANATION] |
## Wave: DISTILL / [EXPLANATION] ... (wrong token) |
Use [REF], [WHY], or [HOW] |
Section appears twice |
Two ## Wave: DISCUSS / [REF] Decisions headings |
Merge or rename one heading |
Future extensions (roadmap)
- Automatic density inheritance: Features created with
rigor: "lean"default to lean L7; features withrigor: "thorough"default to full density. - Per-feature density override: Override global density on a per-feature basis without editing
global-config.json. - Migration automation: Detect legacy features at CI time and suggest migration.
- IDE support: VS Code extension for lean L7 syntax highlighting and schema validation.