From beat
Reverse-engineers Gherkin feature files from existing code to adopt the Beat BDD workflow in an established codebase. Not for new feature design.
How this skill is triggered — by the user, by Claude, or both
Slash command
/beat:distillThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Distill — reverse-engineer Gherkin feature files from existing code.
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.
<decision_boundary>
Use for:
.feature files that describe what the code currently doesNOT for:
/beat:design)/beat:design)/beat:explore)Trigger examples:
</decision_boundary>
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.
| 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. |
/beat:verifybeat/CONTEXT.mddesign.md without running the three-condition ADR gate/beat:plan or /beat:apply on the distill change itself (there is nothing to implement)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
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."
Ensure worktree isolation
Invoke using-git-worktrees before reading or writing any files.
Read and understand the code
Read the specified code. Map out:
Scan existing features
Scan beat/features/**/*.feature and beat/changes/*/features/*.feature (excluding archive):
Feature: and Scenario: lines to map existing coverageCreate a change container
Create beat/changes/distill-<scope-name>/ with status.yaml (schema: references/status-schema.md):
name: distill-<scope-name>
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.
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):
user/account/member for the same entity)? Pick the canonical word, list the others as _Avoid_.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):
references/feature-writing.md for conventions on description blocks, scenario organization, and review checklist@distilled (always), plus @happy-path, @error-handling, @edge-case@e2e or @behavior, default @behavior)proposal.md (optional):
## Why, ## What Changes, ## Impactproposal: { status: skipped } in status.yaml — never leave it pending (archive warns on pending artifacts)design.md (optional):
## Approach, ## Key Decisions, ## Componentsreferences/adr-format.md:
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.design: { status: skipped } in status.yaml — never leave it pendingSpec self-review (after writing each artifact):
Re-read the artifact with fresh eyes and check:
TBD, TODO, incomplete sections, vague descriptions?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.
Commit artifacts
Commit all change artifacts: git add beat/changes/distill-<scope-name>/ && git commit
Use a descriptive message: "distill(): extract BDD specs from existing code"
Present to user for review
Show:
## Distill Complete: distill-<scope-name>
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)
Guides creation, editing, and verification of skills for AI coding agents using test-driven development with subagent scenarios. Use when authoring or debugging skills.
npx claudepluginhub kirkchen/beat --plugin beat