Modern AI coding agents make implementation much cheaper. Because of that, planning matters more: if code is easy to generate, it is easy to move fast in the wrong direction.
That is why spec-driven development (SDD) workflows are getting attention. Tools like GitHub Spec Kit and OpenSpec put structured specs before code changes, so the agent has something better than a loose prompt.
I like that direction, but in my own work I prefer a BDD workflow instead. I’m biased here: I have been maintaining Playwright-BDD for three years, so Given / When / Then syntax is already a natural part of my toolbox.
In this post I share how I use a BDD workflow with coding agents, and why I like it more than other spec-driven development approaches.
Demo App
The demo app is a small React app that shows users in a table. The app fetches users from the JSONPlaceholder users API when it starts.
The project already has Playwright BDD configured. An existing feature file already covers this page, and the app already has passing BDD tests for the list and details view.
The Change
The change I want is small too: add pagination to the users list. The current app shows all 10 users at once. I want 5 users per page, plus Previous and Next buttons.
I use Codex in the VS Code extension, but the flow should work similarly with other coding agents and harnesses. I switch to Plan Mode and write a very simple prompt:
implement user paginationThat is the whole request. I leave the component structure, state model, button implementation, and test plan for the agent to derive from the repo and the approved scenario.
The repo has a playwright-bdd skill, so the agent starts with a BDD question instead of jumping straight into the code. It asks whether the pagination change should include a BDD scenario:

The skill shows this guardrail before any significant feature. In my experience, it is better to ask the user directly instead of guessing whether to apply the BDD approach. The agent is still in planning mode, and the skill pushes the conversation toward a .feature file diff instead of a generic markdown document.
Feature File Proposal
After I confirm that the change should be covered by BDD, the agent proposes this update to features/users.feature:
Feature: Users Page
Scenario: Display list of users Scenario: Display first page of users Given I am on the users list Then I see heading "Users" And I see 10 users in the table And I see 5 users in the table And I cannot go to the previous users page And I can go to the next users page
Scenario: Browse user pages Given I am on the users list When I go to the next users page Then I see 5 users in the table And I see user "Mrs. Dennis Schulist" in the table And I cannot go to the next users page When I go to the previous users page Then I see user "Leanne Graham" in the table And I cannot go to the previous users page
Scenario: Show user details Given I am on the users listThe agent does not write perfect Gherkin on the first try. That is fine. I can fine-tune the scenario later to make it cleaner and more readable.
The important point is that this diff becomes the working artifact of the session. It gives a structured surface for iteration. A markdown plan can mix requirements, implementation ideas, assumptions, and task lists in one document. A Gherkin diff keeps the discussion focused on the user flow: where the user starts, what they do, and what they should see.
Iteration
Writing good Gherkin scenarios is its own art. The first draft is technically reasonable, but it covers too much for this change. For example, positive and negative checks for the Previous and Next buttons add noisy steps:
And I cannot go to the previous users pageAnd I can go to the next users pageThose checks are valid, but they make the scenario feel heavy. I want feature files to be simple and easy to read.
Rule of thumb: make your feature files sound like you are explaining the feature to a friend.
I use a few follow-up prompts to simplify the change into one scenario and make it sound natural:
Keep a single scenario, just check the user count and the first user name.Then go to the next page, recheck the same, and return via the previous button.I enjoy planning with an agent through feature files: I can read the flow in one pass, spot what feels wrong, and ask the agent to change wording, steps, or scenario structure. I feel more in control here than with markdown, where I usually stop reading after a few paragraphs and just accept the plan.
Approved Scenario
After a few iterations, the approved diff looks like this:
Feature: Users Page
Scenario: Display list of users Scenario: Display list of users with pagination Given I am on the users list Then I see heading "Users" And I see 10 users in the table And I see 5 users in the table And the first user is "Leanne Graham" When I click the next page button Then I see 5 users in the table And the first user is "Mrs. Dennis Schulist" When I click the previous page button Then the first user is "Leanne Graham"
Scenario: Show user details Given I am on the users listThis change has value: it clearly shows the new behavior while keeping the scenario small.
At each iteration, the agent asks me to approve the scenario or continue editing. At this point, I approve it and proceed to implementation:

Implementation
Once the scenario is approved, the agent produces an implementation plan and applies the code changes.
The plan is straightforward because the scenario already defines the acceptance behavior.
Then I review the app diff. The feature file guides the work, but it does not replace engineering expertise.
The agent also implements the missing step definitions:
When('I click the next page button', async ({ page }) => { await page.getByRole('button', { name: 'Next page' }).click();});
When('I click the previous page button', async ({ page }) => { await page.getByRole('button', { name: 'Previous page' }).click();});
Then('the first user is {string}', async ({ page }, name: string) => { await expect(page.getByTestId('user-row').first()).toContainText(name);});Finally, the agent automatically runs the tests to verify that the feature works.
The test command is the usual Playwright BDD flow:
> npx bddgen && npx playwright test
Running 2 tests using 1 worker 2 passed (2.7s)Final App
With the code in place, the app shows five users per page and the page navigation buttons:
The updated scenario appears in the Cucumber HTML report:
Comparison With OpenSpec
To compare the workflows, I implement the same pagination feature with OpenSpec. It delivers the same working feature, but produces more artifacts along the way. The process starts with four markdown files:
After implementation and archiving, the workflow leaves six files in the repository:
openspec/├── changes/│ └── archive/│ └── 2026-07-10-add-users-pagination/│ ├── .openspec.yaml│ ├── design.md│ ├── proposal.md│ ├── specs/│ │ └── users-pagination/│ │ └── spec.md│ └── tasks.md└── specs/ └── users-pagination/ └── spec.mdInterestingly, the final spec.md also contains Gherkin-like scenarios:
The structure looks familiar, but these scenarios are still text inside a markdown file. They are not executable .feature files and do not run as acceptance tests.
OpenSpec solves the pagination task successfully, but managing its specs becomes an additional part of the process. Creating, archiving, and organizing these artifacts takes more of my time and more agent tokens.
Limitations
I am not saying “never write markdown specs.” Some changes require a design document:
- big multi-component changes;
- architecture decisions;
- data model changes;
- migrations;
- performance trade-offs;
This leads to a simple rule I use:
If a feature has a clear business flow, I describe it as a BDD scenario.
For complex tasks, BDD becomes one of the steps in the whole process. It captures the business flow, while design documents cover architecture, data, and implementation details.
Takeaway
In agentic BDD workflow, the feature file is both conversation and test. It starts as a planning surface. I iterate on it with the agent and simplify the steps and scenarios until the feature reads clearly. Then the agent implements the behavior and automates the same scenario with Playwright-BDD.
When the feature is done, the .feature file is the only spec artifact I keep. It explains the behavior to humans, proves the behavior in tests, and stays in sync with the code as the application evolves.
The complete example is available on GitHub. Feel free to experiment with it and share your experience with BDD and coding agents in the comments.