Writing BDD Scenarios
The agent builds exactly what’s in BDD.md — nothing more, nothing less. Writing good scenarios is the most important thing you do.
Structure of BDD.md
Section titled “Structure of BDD.md”---language: typescript # rust | python | go | node | typescript | javaframework: react-vite # informational — helps the agent pick the right toolsbuild_cmd: npm run buildtest_cmd: npm testlint_cmd: npm run lintfmt_cmd: npm run formatbirth_date: 2026-01-01 # project start date (used for day counter)---Below the frontmatter, write plain Gherkin:
System: A REST API for task management
Feature: Task CRUD As an API consumer I want to create, read, update and delete tasks So that I can manage work items programmatically
Scenario: Create a task Given the API is running When I POST /tasks with {"title": "Buy milk"} Then I receive a 201 response And the response body contains the task with an IDScenario priority
Section titled “Scenario priority”Top of the file = highest priority. The agent works top-to-bottom, picking the first uncovered or failing scenario.
If you want something built first, put it at the top of BDD.md.
Tips for effective scenarios
Section titled “Tips for effective scenarios”Be specific — one behaviour per scenario
Section titled “Be specific — one behaviour per scenario”# Good — testable, focusedScenario: Empty search returns no results Given the database has 10 tasks When I search for "nonexistent" Then I receive an empty list
# Bad — too vagueScenario: Search works Given some tasks When I search Then I get resultsMake Then clauses observable
Section titled “Make Then clauses observable”The agent needs to write an assertion. If your Then clause isn’t testable, the agent will struggle.
# Good — clear assertionThen the response status is 404Then the task list contains exactly 3 itemsThen the error message includes "not found"
# Bad — how does the agent test this?Then the system is in a good stateThen the user is happyKeep scenarios independent
Section titled “Keep scenarios independent”Each scenario should stand on its own. Don’t rely on state from previous scenarios.
# Good — self-containedScenario: Delete a task Given I have created a task with ID 1 When I DELETE /tasks/1 Then I receive a 204 response
# Bad — depends on "Create a task" running firstScenario: Delete a task When I DELETE /tasks/1 Then I receive a 204 responseUse Background for shared setup
Section titled “Use Background for shared setup”Feature: Task management Background: Given the database is empty And I have a valid auth token
Scenario: Create a task When I POST /tasks with {"title": "Buy milk"} Then I receive a 201 response
Scenario: List tasks When I GET /tasks Then I receive an empty listSupported languages
Section titled “Supported languages”The language field in frontmatter tells poppins which toolchain to set up:
| Language | What gets installed |
|---|---|
typescript | Node.js, npm, TypeScript compiler |
python | Python venv, pip |
rust | Cargo, rustc, clippy |
go | Go toolchain |
java | JDK, Maven or Gradle |
node | Node.js, npm |