How to author a feature using the L7 single-file model
This guide teaches you how to write or migrate a feature to the lean L7 single-file model: one feature-delta.md per feature with schema-typed section headings.
Prerequisites
- A text editor or IDE (VS Code, vim, etc.)
- Basic markdown knowledge
- Familiarity with the Feature directory format reference
- Understanding of nWave's six waves: DISCOVER, DISCUSS, DESIGN, DEVOPS, DISTILL, DELIVER
- New to nWave? Read Wave Directory Structure first to understand how artifacts are organized.
Quick start: The L7 section heading pattern
Every section in a lean feature-delta.md follows this pattern:
## Wave: <WAVE> / [<TYPE>] <Section name>
Examples:
## Wave: DISCUSS / [REF] User stories
## Wave: DISCUSS / [WHY] JTBD narrative
## Wave: DESIGN / [REF] Component decomposition
## Wave: DESIGN / [HOW] Migration playbook
## Wave: DISTILL / [REF] Acceptance scenarios
Rules:
| Part | Valid values | Example |
|---|---|---|
<WAVE> |
DISCOVER, DISCUSS, DESIGN, DEVOPS, DISTILL, DELIVER | DISCUSS |
<TYPE> |
[REF], [WHY], [HOW] |
[REF] = reference/factual; [WHY] = rationale/explanation; [HOW] = procedure/instruction |
<Section name> |
Human-readable title | User stories, Decisions, Acceptance scenarios |
Understanding section types
[REF] — Reference / Factual content
Use [REF] for specification, requirements, facts, and outcomes that do not explain rationale.
What belongs here:
- Persona definitions
- Job-to-be-done elevator pitch
- User stories (elevator pitch + AC only; rationale goes in
[WHY]) - Acceptance criteria
- Locked decisions and decision tables
- Acceptance scenarios (gherkin)
- Architecture diagrams and component lists
- API specs
- Test execution results
- Definition of done
Example:
## Wave: DISCUSS / [REF] User stories
### US-1: Lean-by-default wave output
**Elevator Pitch**: Marco runs `/nw-discuss` on a small feature and gets a feature-delta.md containing only `[REF]` sections so the wave hands off ≤30% of legacy token volume to DESIGN.
**Acceptance criteria**:
- AC-1: `/nw-discuss` produces feature-delta.md with only [REF] sections
- AC-2: Token count ≤60% of legacy baseline
- AC-3: All Tier-1 fields are present
[WHY] — Rationale / Explanation
Use [WHY] for context, justification, alternatives weighed, and lessons learned.
What belongs here:
- Persona narrative (extended goals, frustrations, environment)
- Full JTBD analysis (four forces: push, pull, anxiety, habit)
- Design alternatives considered and why rejected
- Architecture rationale and trade-offs
- Research findings and synthesis
- Risk analysis
- Lessons learned and retrospectives
Example:
## Wave: DISCUSS / [WHY] JTBD narrative
**Push forces** (pain in status quo):
- Legacy multi-file docs create token bloat for downstream agents
- Merge conflicts in parallel waves slow coordination
**Pull forces** (attraction to new state):
- Consolidated single file → agent grep efficiency
- Wave-owned sections → auto-merge friendly
**Anxiety** (resistance to change):
- Learning curve for authors unfamiliar with L7 schema
- Migration burden on existing 10+ features
**Habit** (inertia):
- Team used to `discuss/`, `design/` subdirectory pattern
[HOW] — Procedure / Instruction
Use [HOW] for steps, procedures, integration guides, and operational tasks.
What belongs here:
- Migration playbooks
- Integration steps
- Manual procedures
- Troubleshooting guides
- Operational run-books
- Configuration steps
- Deployment procedures
Example:
## Wave: DELIVER / [HOW] Migration playbook
1. Back up the legacy feature directory: `git checkout -b backup/my-feature`
2. Run the migration script: `python scripts/migrate_to_l7.py docs/feature/my-feature`
3. Review the generated `feature-delta.md` for accuracy
4. Commit: `git add docs/feature/my-feature/feature-delta.md && git commit -m "..."`
5. Verify: `python scripts/validation/validate_feature_delta.py docs/feature/my-feature/feature-delta.md`
Migrating from legacy layout
Use the automated migration script to convert existing features to L7.
Step 1: Backup
git checkout -b backup/my-feature
Step 2: Run the migration script
python scripts/migrate_to_l7.py docs/feature/my-feature
What it does:
- Reads all files from
docs/feature/my-feature/{discover,discuss,design,devops,distill,deliver}/ - Classifies each artifact by type (user story, decision, scenario, etc.)
- Writes
feature-delta.mdwith proper## Wave: ... / [TYPE]headings - Demotes optional content (JTBD narrative, persona essays, migration guides) to
[WHY]/[HOW]sections (lean-compatible) - Creates a
FORMATmarker containing"lean"
Step 3: Review
# See what was migrated
git diff docs/feature/my-feature/feature-delta.md
# Check for migration warnings
cat docs/feature/my-feature/feature-delta.md | grep "review-needed"
If you see <!-- review-needed --> comments, sections with unclear classification are marked. Review and manually organize as needed.
Step 4: Validate
python scripts/validation/validate_feature_delta.py docs/feature/my-feature/feature-delta.md
Exit code 0 = valid. Exit code 1 = malformed headings (see error details).
Step 5: Commit
git add docs/feature/my-feature/
git commit -m "docs(feature/my-feature): migrate to lean L7 single-file format"
Step 6: Rollback (if needed)
If anything goes wrong:
git reset --hard origin/master
Legacy subdirectories are untouched by the script, so you can inspect and retry.
Migration script options
python scripts/migrate_to_l7.py --help
--dry-run
Preview what would be migrated without writing:
python scripts/migrate_to_l7.py docs/feature/my-feature --dry-run
--force
Overwrite an existing feature-delta.md:
python scripts/migrate_to_l7.py docs/feature/my-feature --force
--preserve-legacy
Keep legacy discuss/, design/, etc. subdirectories after migration (default; shown for clarity):
python scripts/migrate_to_l7.py docs/feature/my-feature --preserve-legacy
--no-preserve-legacy
Delete legacy subdirectories after migration:
python scripts/migrate_to_l7.py docs/feature/my-feature --no-preserve-legacy
Schema validation troubleshooting
Error: "Malformed heading: missing [TYPE] prefix"
Cause: You wrote:
## Wave: DISCUSS / User stories
Fix: Add the type:
## Wave: DISCUSS / [REF] User stories
Error: "Invalid wave name: ANALYSE"
Cause: Typo in wave name.
Fix: Use one of: DISCOVER, DISCUSS, DESIGN, DEVOPS, DISTILL, DELIVER.
Error: "Invalid type: [EXPLANATION]"
Cause: Wrong type token.
Fix: Use one of: [REF], [WHY], [HOW].
Error: "Section appears twice under Wave DISCUSS"
Cause: Two headings with the same wave and section name:
## Wave: DISCUSS / [REF] Decisions
...
## Wave: DISCUSS / [REF] Decisions
...
Fix: Merge into one heading or rename the duplicate.
Density control and section types
The density setting controls which section types are auto-produced:
| Density | Auto-produced | Available via --expand |
|---|---|---|
lean |
[REF] only |
[WHY], [HOW] (per expansion ID) |
full |
[REF] + [WHY] + [HOW] |
All (already present) |
Example: When density is lean, DISCUSS produces:
## Wave: DISCUSS / [REF] Persona
## Wave: DISCUSS / [REF] Job-to-be-done
## Wave: DISCUSS / [REF] User stories
If you request --expand jtbd-narrative, DISCUSS adds:
## Wave: DISCUSS / [WHY] JTBD narrative
Expansion catalog: Making optional content discoverable
Each wave lists available expansions in an [REF] section called Expansion catalog:
## Wave: DISCUSS / [REF] Expansion catalog
| Expansion ID | Type | One-line description |
|---|---|---|
| `jtbd-narrative` | [WHY] | Full Job-to-be-Done analysis with four forces |
| `persona-narrative` | [WHY] | Extended persona (goals, frustrations, environment) |
| `alternatives-considered` | [WHY] | Design alternatives weighed and rejected |
| `migration-playbook` | [HOW] | Procedural notes for migrating existing surfaces |
When authoring expansions:
- Add the expansion section to
feature-delta.md(e.g.,## Wave: DISCUSS / [WHY] JTBD narrative) - Register it in the Expansion catalog table with a one-line description
- Test with the validator:
python scripts/validation/validate_feature_delta.py ...
Grep cookbook for downstream agents
Wave agents consume feature-delta files via grep. Use these patterns to find what you need:
# Find all decisions for a wave
grep "^## Wave: DESIGN / \[REF\] Decisions" -A 50 feature-delta.md | head -100
# Find all acceptance scenarios
grep "^## Wave: DISTILL / \[REF\] Acceptance scenarios" -A 100 feature-delta.md
# Find all rationale sections
grep "^## Wave: .* / \[WHY\]" feature-delta.md
# Find all procedural sections
grep "^## Wave: .* / \[HOW\]" feature-delta.md
# Extract just the Expansion catalog
grep "^## Wave: DISCUSS / \[REF\] Expansion catalog" -A 20 feature-delta.md