Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

bdd greenfield

Run the full orchestrated loop from an empty directory to an implemented requirement, with exactly two human gates: approving the spec wording, and approving the generated tests before they run. Everything else — scaffolding, validation, scenario authoring, step generation, test execution, phase tracking — is automated.

Usage: bdd greenfield [OPTIONS]

Flags

FlagDescription
--root <ROOT>Project root. Defaults to ..
--model <MODEL>LLM model for the generation steps, this run only.

The orchestrated flow

 1. inspect / init      scaffold if the root is empty (asks for language)
 2. describe            you describe what to build in plain words; the
                        model splits it into requirement proposals
 3. pick + wizard       you pick a proposal; every field arrives
                        pre-filled - Enter accepts, typing replaces
 4. spec validate       structure gate; findings loop back to rewording
 5. spec refine         wording gate; each finding comes with a "try:" fix
    ── HUMAN GATE 1 ──  approve the requirement's wording
 6. scenario + steps    Gherkin scenario tagged @REQ-...; step definitions
    ── HUMAN GATE 2 ──  approve the generated tests
 7. test → RED          the scenario fails honestly
 8. implement           Enter lets the model attempt the implementation;
                        a number, e.g. 5, buys that many hands-off attempts
 9. test → GREEN        loop back to 8 while failing
10. refactor            optional; only offered on GREEN
11. mark implemented    the requirement's status flips in the spec

The description-driven wizard

With a resolved model, drafting starts from a plain-words description instead of a blank title prompt:

Describe what to build in plain words (one or several requirements). Enter drafts manually instead:
sum numbers from a comma separated string, empty input means zero
Splitting the description into requirements with qwen3-coder-next:latest - working ...
The description holds 2 requirement(s):
  1. Comma separated numbers are summed
  2. Empty string returns zero
Which requirement first? [1-2, Enter for 1]:
2
Left for later runs: Comma separated numbers are summed. Draft them the same way afterwards.
Walking through REQ-001. Each prompt shows the proposal - Enter accepts it, or type your own wording.
REQ-001 title [Empty string returns zero] (Enter keeps it):
REQ-001 story (As a ..., I want ..., so that ...) [As a user, I want empty input to be 0 so that no input is a safe default.] (Enter keeps it):
REQ-001 criterion 1 [Given an empty string "", when add is called, then the result is 0] (Enter keeps it, '-' drops it):
REQ-001 criterion 2 (leave blank to finish the criteria):

The model must deliver each proposal complete — title, story, and at least one Given/When/Then criterion — or the proposal is dropped. Nothing is accepted silently: every field passes through your hands, and the validate + refine gates still run on whatever you accept.

Drafting falls back to the classic manual prompts whenever the description is left blank, no model is resolved, the model is unreachable, or its reply holds no complete requirement.

At each gate you can approve, decline (the run stops cleanly), or pause to resume later — the phase state and staged changes survive between invocations.

The implementation attempt

On a RED bar with a resolved model, Enter asks the model to make the failing tests pass, then reruns the suite and prints the counts:

RED: 2 tests, 1 failures, 1 errors.
  - Req001Test.empty_string_returns_zero: TODO: assert - ...
Press Enter to let the model attempt the implementation and rerun the tests, enter a number to attempt up to that many times without asking again, or type stop to pause here:

Generating an implementation attempt - working ...
Updated src/main/StringCalculator.java (llm).
Updated src/test/java/Req001Test.java (llm).
Running the tests - working ...
GREEN: 2 tests, 0 failures, 0 errors.

Every working ... line is live on a terminal: the trailing dots animate in light yellow — . .. ... and over again — while the model call or test run is in flight, then the line settles. Piped output prints the single static line.

The model receives the requirement, the full failing test details — stack traces and build output included — the project’s source files, every prior attempt on this requirement (which files it wrote, which failures it was addressing, and what the run after it actually reported), and the session language’s best practices — package naming for Java, snake_case modules for Rust, and so on — so a second attempt never starts blind or repeats an approach that already failed. It must reply with complete files: production code plus real bodies for the TODO placeholders in the generated tests and step definitions. Only paths already in the project (or the production file named after the spec’s project) are accepted; anything else in the reply is dropped. The rerun is the real validator — if the bar stays RED, press Enter for another attempt (the fresh failure details plus the attempt history go back to the model) or implement by hand and press Enter.

A number buys a hands-off stretch: answering 5 lets the model attempt, rerun, and attempt again up to five times without asking in between — each round announced as Attempt 2 of 5. — stopping early the moment the bar turns GREEN. When the budget runs out on RED, the prompt returns. Anything unreadable at the prompt behaves like Enter: one attempt.

An unusable reply is narrated (The model's reply held no usable file update. Implement by hand instead.) and the loop simply hands control back to you. Dead ends like this — model failures, missing runtimes, hand-offs back to manual work — print in red so they stand out from the loop’s narration. Without a model, Enter just reruns the tests.

Typing stop pauses the run; a paused project continues with the standalone bdd implement command, which runs the same attempt from the persisted failure details:

bdd implement REQ-001 && bdd changes commit && bdd test

Rewording loop details

When validation or refinement finds problems, each finding is printed with a concrete suggestion:

REQ-001: the outcome is not concrete
  try: end with the exact expected value, e.g. '..., then the result is 3'

With a model, the findings become its brief: the draft and the findings go to the model, and the re-prompts carry its corrected proposal — Enter accepts each fix. If the review rejects a wording again, the next model call also recounts every earlier wording and the findings each one produced, so the model never circles back to a wording the review already rejected:

Asking qwen3-coder-next:latest to address finding 1 of 1 - working ...
The model reworded the draft. Each prompt shows its proposal - Enter accepts it, or type your own wording.

With several findings, each one is its own model call — call 2 is briefed with the draft call 1 fixed, so the corrections accumulate one finding at a time instead of all at once.

On a color console the bracketed suggestion — the text Enter will use — renders green; the destructive '-' drops it hint on criterion prompts and dead-end messages render red; the animated dots on working ... lines render light yellow, and the Generating an implementation attempt announcement renders dark green. On a real terminal every answer is edited on a > line with full line editing: the arrow keys move the cursor anywhere in the typed text, Home/End jump, and the up arrow recalls earlier answers from this session.

If the model call fails or its rewording is unusable, the re-prompt falls back to the requirement id and your prior answer; Enter keeps it:

REQ-001 title [Two numbers separated by a comma are summed] (Enter keeps it):
REQ-001 criterion 1 [Given "1,2", when add is called, then the result is 3] (Enter keeps it, '-' drops it):
REQ-001 criterion 3 (leave blank to finish the criteria):

Reply

The final JSON reply summarizes where the run ended:

{
  "requirement": "REQ-001",
  "feature": "features/string_calculator.feature",
  "phase": "GREEN",
  "completed": true,
  "nextStep": "REQ-001 is implemented. Draft the next requirement with 'bdd spec draft'."
}

completed is false when a gate was declined, a runtime was missing, or the run was paused; nextStep always says how to continue.

Requirements for a full run

  • The language’s runtime must be present (mvn, node, dotnet, or cargo) — the orchestrator refuses to fake a test run.
  • An LLM is optional: with no reachable Ollama model the generation steps fall back to deterministic templates you edit yourself. The model this CLI is developed and run against is qwen3-coder-next:latest (ollama pull qwen3-coder-next:latest). Your mileage will vary with other models, especially those not trained for development work.

See also