--- name: distill description: Use when extracting BDD specs from existing code — for adopting Beat in an established codebase or distilling a module into feature files --- Distill — reverse-engineer Gherkin feature files from existing code. Use this to bring existing codebases into the Beat workflow. The output is draft `.feature` files that describe **current behavior** (not aspirational), verified independently by `/beat:verify`. **Use for:** - Extracting BDD specs from an existing codebase that doesn't have feature files yet - Bringing a module, directory, or functionality into the Beat workflow retroactively - Generating draft `.feature` files that describe what the code currently does **NOT for:** - Designing new behavior or features (use `/beat:design`) - Writing aspirational specs for code that doesn't exist yet (use `/beat:design`) - Greenfield projects with no existing code to distill - Exploring ideas or thinking through a problem (use `/beat:explore`) **Trigger examples:** - "Distill the auth module into feature files" / "Extract specs from existing code" / "Bring this codebase into Beat" - Should NOT trigger: "design a new feature" / "write specs for something we want to build" / "explore this idea" Before writing any artifact files: you MUST invoke superpowers:using-git-worktrees. Distilled artifacts live in a change container that flows through verify → archive. Worktree isolation ensures they don't contaminate the main workspace. Before writing feature files: you MUST run the glossary check (see step 6) and ensure every project-specific term used in scenarios is defined in `beat/CONTEXT.md`. Create the glossary lazily — only when the first term is added. After writing each artifact: you MUST run the four-check spec self-review (placeholder / consistency / scope / ambiguity). Fix issues inline. While writing `design.md`: you MUST run the three-condition ADR gate (hard-to-reverse + surprising + real trade-off — see `references/adr-format.md`) on each Key Decision recovered from the code. When all three hold, offer to lift it into `docs/adr/`. The user may decline. NEVER invent rationale the code doesn't show — mark it unverified or ask the user. If a prerequisite skill is unavailable (not installed), continue with fallback — but NEVER skip because you judged it unnecessary. **Prerequisites** (invoke before proceeding) | Superpower | When | Priority | |-----------|------|----------| | using-git-worktrees | Before first file write | MUST | If a superpower is unavailable (skill not installed), skip and continue. ## Rationalization Prevention | Thought | Reality | |---------|---------| | "I don't need a worktree for just writing feature files" | Distilled artifacts flow through verify and archive. Without isolation, they won't carry forward correctly. | | "The code is simple, I can verify the scenarios myself" | Self-verification of distilled specs is explicitly forbidden. Always use `/beat:verify` for independent accuracy checking. | | "I'll skip scanning existing features, this is a new area" | Existing features may already cover this behavior. Distilling duplicates creates maintenance burden. | | "These scenarios are obviously correct, verification is overkill" | Distill extracts specs from code — the most likely error is describing aspirational behavior instead of current behavior. Verification catches this. | | "I'll commit later, let me just generate the files first" | Uncommitted artifacts can be lost. Commit before presenting to the user, matching design's behavior. | | "The terms are already in the code, no need for a glossary" | Code shows usage, not meaning. Distill is the moment an established codebase gets its glossary — entries are two lines, add them inline. | | "I can't know why this decision was made, so no ADR" | You can't invent the why, but you can record the what and ask. Run the gate; mark unverified rationale as unverified instead of skipping. | | "Spec self-review is overkill, the scenarios came straight from code" | Reading code ≠ describing it accurately. The four checks catch placeholders, contradictions, and ambiguities in 30 seconds. | ## Red Flags — STOP if you catch yourself: - Writing any file before invoking using-git-worktrees - Writing scenarios that describe desired behavior instead of current behavior - Skipping the existing feature scan - Claiming verification passed without running `/beat:verify` - Finishing without committing artifacts - Writing Gherkin scenarios that contain internal method names, numeric thresholds, or implementation constants - Writing scenarios that use project-specific domain terms not defined in `beat/CONTEXT.md` - Writing a Key Decision in `design.md` without running the three-condition ADR gate - Inventing rationale for a recovered decision instead of marking it unverified or asking - Skipping the spec self-review because the scenarios "came straight from the code" - Telling the user to run `/beat:plan` or `/beat:apply` on the distill change itself (there is nothing to implement) - Thinking "I know the code well enough to skip verification" ## Process Flow ```dot digraph distill { "Ask for scope" [shape=box]; "Invoke using-git-worktrees" [shape=box, style=bold]; "Read and understand code" [shape=box]; "Scan existing features" [shape=box]; "Scope already covered?" [shape=diamond]; "STOP: inform user" [shape=box, style=dashed]; "Create change container" [shape=box]; "Glossary check\n(terms → CONTEXT.md)" [shape=box, style=bold]; "Generate draft artifacts\n(self-review each)" [shape=box]; "design.md included?" [shape=diamond]; "ADR gate\n(design.md Key Decisions)" [shape=box, style=bold]; "Offer module README\n(Layer 3, optional)" [shape=box]; "Commit artifacts" [shape=box]; "Present to user" [shape=doublecircle]; "Ask for scope" -> "Invoke using-git-worktrees"; "Invoke using-git-worktrees" -> "Read and understand code"; "Read and understand code" -> "Scan existing features"; "Scan existing features" -> "Scope already covered?"; "Scope already covered?" -> "STOP: inform user" [label="yes"]; "Scope already covered?" -> "Create change container" [label="no"]; "Create change container" -> "Glossary check\n(terms → CONTEXT.md)"; "Glossary check\n(terms → CONTEXT.md)" -> "Generate draft artifacts\n(self-review each)"; "Generate draft artifacts\n(self-review each)" -> "design.md included?"; "design.md included?" -> "ADR gate\n(design.md Key Decisions)" [label="yes"]; "design.md included?" -> "Offer module README\n(Layer 3, optional)" [label="no"]; "ADR gate\n(design.md Key Decisions)" -> "Offer module README\n(Layer 3, optional)"; "Offer module README\n(Layer 3, optional)" -> "Commit artifacts"; "Commit artifacts" -> "Present to user"; } ``` **Input**: User specifies the code scope to distill (module, directory, or functionality). **Steps** 1. **Ask for scope** If not specified, use **AskUserQuestion tool**: > "What code do you want to distill into BDD specs? Specify a module, directory, or describe the functionality." 2. **Ensure worktree isolation** Invoke `using-git-worktrees` before reading or writing any files. 3. **Read and understand the code** Read the specified code. Map out: - User-visible behaviors (functionality) - Edge cases handled - Error conditions - Existing tests (if any) that reveal behavior 4. **Scan existing features** Scan `beat/features/**/*.feature` and `beat/changes/*/features/*.feature` (excluding archive): - Read `Feature:` and `Scenario:` lines to map existing coverage - Deep-read only features that overlap with the distill scope - Note which behaviors are already covered — do NOT distill duplicates - If the scope is entirely covered: inform user and STOP 5. **Create a change container** Create `beat/changes/distill-/` with `status.yaml` (schema: `references/status-schema.md`): ```yaml name: distill- created: YYYY-MM-DD phase: new source: distill pipeline: proposal: { status: pending } gherkin: { status: pending } design: { status: pending } tasks: { status: skipped } ``` `tasks` is `skipped` because a distill change describes current behavior — there is nothing to implement. Future changes to this area get their own change containers via the normal `/beat:design` → `/beat:plan` → `/beat:apply` flow. 6. **Generate draft artifacts** Read `beat/config.yaml` if it exists (schema: `references/config-schema.md`). Use `language` for artifact output language, inject `context` as project background, and apply matching `rules` per artifact type (e.g., `rules.gherkin`, `rules.proposal`, `rules.design`). **Glossary check (Layer 1) — before writing feature files:** Read `beat/CONTEXT.md` if it exists (schema: `references/context-format.md`). Create it lazily when the first term is added — never preemptively. Distill is often the first time an established codebase builds its glossary, and the code itself is the source. For each project-specific term that will appear in scenarios, adapt the four challenges from `references/context-format.md` and update `beat/CONTEXT.md` **inline** as terms resolve (never batch): 1. **Against the glossary** — the term conflicts with an existing entry? Surface, resolve, update. 2. **Sharpen fuzzy** — the code uses synonyms for one concept (e.g. `user`/`account`/`member` for the same entity)? Pick the canonical word, list the others as `_Avoid_`. 3. **Stress-test against code** — probe term boundaries with the edge cases the code actually handles; name the boundary. 4. **Cross-reference docs** — README/comments/docs use a term differently from the code? Surface it and ask the user which is canonical. Every project-specific term used in scenarios MUST exist in `beat/CONTEXT.md` before the scenario is written. Bold terms in scenarios are the canonical form (see `references/feature-writing.md`). If a term's meaning is genuinely uncertain from code alone, ask the user rather than guessing. **features/*.feature (mandatory):** - Read `references/feature-writing.md` for conventions on description blocks, scenario organization, and review checklist - Write feature files describing CURRENT behavior (not desired behavior) - Each scenario must accurately reflect what the code actually does - Use tags: `@distilled` (always), plus `@happy-path`, `@error-handling`, `@edge-case` - Every scenario MUST have a testing layer tag (`@e2e` or `@behavior`, default `@behavior`) - If behavior is ambiguous, note it as uncertain rather than guessing **proposal.md (optional):** - If the purpose is clear from code/docs: write a brief "why this exists" proposal - Sections: `## Why`, `## What Changes`, `## Impact` - If you choose not to write it: set `proposal: { status: skipped }` in status.yaml — never leave it `pending` (archive warns on pending artifacts) **design.md (optional):** - Document the current technical architecture and key decisions visible in the code - Sections: `## Approach`, `## Key Decisions`, `## Components` - **ADR gate** — for each Key Decision recovered from the code, run the three-condition check from `references/adr-format.md`: 1. Hard to reverse? 2. Surprising without context? 3. Result of a real trade-off? Recovered decisions are prime candidates — "surprising without context" is exactly what code archaeology surfaces. **Caveat**: the code shows *what* was decided, not *why*. Take rationale from evidence (commit history, comments, docs) or from the user; if neither is available, record the decision with rationale marked unverified (e.g. "Rationale unconfirmed — recovered from code"). Never invent a why. If **all three** hold, use **AskUserQuestion tool**: *"This recovered decision meets the ADR gate. Lift it into `docs/adr/`?"* On Yes, write a 1-3 sentence ADR per the template in `references/adr-format.md`, incrementing the highest existing number. On No, continue. Create `docs/adr/` lazily — only on first ADR. - If you choose not to write design.md: set `design: { status: skipped }` in status.yaml — never leave it `pending` **Spec self-review (after writing each artifact):** Re-read the artifact with fresh eyes and check: 1. **Placeholder scan** — any `TBD`, `TODO`, incomplete sections, vague descriptions? 2. **Internal consistency** — do sections contradict each other? Do scenarios contradict the proposal/design? 3. **Scope check** — does the artifact stay within the distill scope, or did it drift into adjacent behavior? 4. **Ambiguity check** — could any scenario be read two different ways? If so, pick the reading the code supports and make it explicit. Fix issues inline. No need to re-review the fix — just fix and move on. Update `status.yaml` for each artifact created, and mark optional artifacts you chose not to create as `skipped`. Set phase to the latest completed spec artifact. **Module README offer (Layer 3, optional):** If the distilled scope is a module (its own directory with a public interface) and it has no `README.md`, offer once to scaffold one per `references/architecture-format.md`. If `beat/ARCHITECTURE.md` exists and is missing this module's row, offer to add it. Advisory — the user may decline; never block. 7. **Commit artifacts** Commit all change artifacts: `git add beat/changes/distill-/ && git commit` Use a descriptive message: "distill(): extract BDD specs from existing code" 8. **Present to user for review** Show: - All generated feature files (summary of scenarios per feature) - Any remaining uncertainties about behavior - Existing features that overlap (from step 4 scan) ``` ## Distill Complete: distill- Created: - features/*.feature (N scenarios across M files) - proposal.md (or skipped) - design.md (or skipped) Glossary: N terms added to beat/CONTEXT.md (or "no new terms") ADRs: N written to docs/adr/ (or "none qualified") Uncertainties: [list any ambiguous behaviors] Next steps: - Review the draft feature files for accuracy - Run `/beat:verify` to independently verify scenarios match code behavior (accuracy mode) - Run `/beat:archive` to sync verified features into `beat/features/` living documentation - Future changes to this area use the normal flow: `/beat:design` → `/beat:plan` → `/beat:apply` ``` **Distill vs Normal Flow** ``` Normal: Spec -> Code (write spec first, then implement) Distill: Code -> Spec (extract spec from existing code) | /beat:verify confirms accuracy (source: distill → accuracy mode) | /beat:archive syncs features into living documentation | Future changes use normal BDD flow (new change container) ```