GitHub

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:

  1. Reads all files from docs/feature/my-feature/{discover,discuss,design,devops,distill,deliver}/
  2. Classifies each artifact by type (user story, decision, scenario, etc.)
  3. Writes feature-delta.md with proper ## Wave: ... / [TYPE] headings
  4. Demotes optional content (JTBD narrative, persona essays, migration guides) to [WHY]/[HOW] sections (lean-compatible)
  5. Creates a FORMAT marker 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

Authoring new features in L7

When you create a new feature from scratch, use L7 from the start.

Step 1: Create the directory

mkdir -p docs/feature/my-new-feature

Step 2: Create the file

Create docs/feature/my-new-feature/feature-delta.md with the L7 heading pattern.

Or use the template (if available):

cp docs/templates/feature-delta-template.md docs/feature/my-new-feature/feature-delta.md

Edit to fill in your feature details.

Step 3: Organize by wave

As each wave executes, add its sections under the appropriate ## Wave: ... heading.

Important rule (D3): Each wave owns its own heading. One wave does not append to another wave's ## Wave: heading.

## Wave: DISCUSS / [REF] User stories

... (DISCUSS adds content here)

## Wave: DISCUSS / [WHY] JTBD narrative

... (DISCUSS may add optional expansions here)

## Wave: DESIGN / [REF] Component decomposition

... (DESIGN adds its own wave heading — never appends to DISCUSS's heading)

Step 4: Validate

After each wave, validate the file:

python scripts/validation/validate_feature_delta.py docs/feature/my-new-feature/feature-delta.md

Step 5: Commit

git add docs/feature/my-new-feature/feature-delta.md
git commit -m "docs(feature/my-new-feature): DISCUSS wave"

Concurrent wave authoring (parallel worktrees)

When multiple waves run on separate worktrees, L7 handles merge cleanly via wave-owned sections.

Setup

# Create worktree for DESIGN wave
git worktree add ../feature-design feature/my-feature

# Create worktree for DISTILL wave
git worktree add ../feature-distill feature/my-feature

Wave A (DESIGN)

In ../feature-design:

## Wave: DESIGN / [REF] Component decomposition

| # | Component | Path | Change type |
|---|---|---|---|
| C1 | Wave skill — DISCUSS | nWave/skills/nw-discuss/SKILL.md | Edit |

Commit: git commit -m "docs(feature): DESIGN wave"

Wave B (DISTILL)

In ../feature-distill:

## Wave: DISTILL / [REF] Acceptance scenarios

Scenario: Lean wave produces only [REF] sections
  Given ...
  When ...
  Then ...

Commit: git commit -m "docs(feature): DISTILL wave"

Merge

In the main worktree:

git merge ../feature-design
git merge ../feature-distill

Result: Both ## Wave: DESIGN ... and ## Wave: DISTILL ... sections coexist cleanly with no conflicts. Git recognizes they're in separate headings.


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:

  1. Add the expansion section to feature-delta.md (e.g., ## Wave: DISCUSS / [WHY] JTBD narrative)
  2. Register it in the Expansion catalog table with a one-line description
  3. 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

Common authoring mistakes to avoid

  1. Mixing reference and rationale in one section: Separate [REF] from [WHY]. If a section has both, split it:

    Wrong:

    ## Wave: DISCUSS / [REF] User stories
    
    ### US-1: Lean output
    
    We chose lean because token bloat degrades context...

    Right:

    ## Wave: DISCUSS / [REF] User stories
    
    ### US-1: Lean output
    
    Elevator Pitch: Marco gets lean output...
    
    ## Wave: DISCUSS / [WHY] JTBD narrative
    
    We chose lean because token bloat degrades context...
  2. One wave appending to another wave's section: Each wave owns its heading. Do not append:

    Wrong:

    ## Wave: DISCUSS / [REF] User stories
    
    ... (DISCUSS content)
    
    ... (DESIGN appends here) ← VIOLATION

    Right: Create a separate heading:

    ## Wave: DISCUSS / [REF] User stories
    
    ...
    
    ## Wave: DESIGN / [REF] Design notes on US-1
    
    ...
  3. Inconsistent section naming: Use consistent names across waves. Do not create:

    ## Wave: DISCUSS / [REF] User stories
    ## Wave: DESIGN / [REF] User story analysis  ← different name, same concept

    Instead, reference the upstream section:

    ## Wave: DESIGN / [REF] Design decisions for User stories
    
    Based on DISCUSS / [REF] User stories (US-1, US-2, ...), we decided:
  4. **Too much procedure in [REF]: Procedures belong in [HOW]:

    Wrong:

    ## Wave: DELIVER / [REF] Implementation
    
    1. Update the skill file at nWave/skills/nw-discuss/SKILL.md
    2. Add the --expand argument parser
    ...

    Right:

    ## Wave: DELIVER / [HOW] Implementation guide
    
    1. Update the skill file at nWave/skills/nw-discuss/SKILL.md
    2. Add the --expand argument parser
    ...