bdd-step-library-curator · git:20260725.b4ad92d · 2026-07-25 · sha256 19c57682f22e5ed3

bdd-step-library-curator git:20260725.b4ad92dA

Immutable. This exact content never changes and is served at /api/v1/blob/19c57682f22e5ed3.

---
name: bdd-step-library-curator
description: "Keeps a BDD step-definition library DRY across a Cucumber / Behave / Reqnroll project - inventories every step definition, detects duplicates (different patterns matching the same intent), recommends canonical consolidations, reorganizes steps by domain, and publishes a step-library README the team greps for \"is there already a step for X?\" before authoring new ones. Use on a cadence as the antidote to step-definition proliferation in long-lived BDD projects, or when a new engineer reports they cannot find an existing step."
---

# bdd-step-library-curator

## Overview

After 6 months of a BDD project, step definitions proliferate:

- Two engineers write `Given a user` and `Given a logged-in user`
  for the same fixture.
- Three slightly-different "I click X" steps (one for buttons,
  one for links, one for arbitrary elements) - all do the same
  thing.
- A new engineer can't find existing steps and writes a fourth
  variant.

The result: step library bloat → Gherkin features hard to read,
step ambiguities, runtime errors, drift.

This skill builds a curation workflow.

## When to use

- A BDD project's step count exceeds ~50 (proliferation threshold).
- A new engineer reports "I couldn't find a step for X."
- Quarterly: scheduled step review.
- Before adopting BDD across multiple teams (proactively design
  the step library shape).

## How to use

1. **Inventory** every step definition across the project - extract
   patterns per runner (the per-runner commands are in
   [references/step-extraction-and-overlap.md](references/step-extraction-and-overlap.md)).
2. **Detect** duplicate / overlapping patterns by normalizing wording
   and grouping - the overlap script lives in the same reference.
3. **Recommend** one canonical step per duplicate group; deprecate the rest.
4. **Reorganize** step files by domain and **publish** the step-library
   README - the team's "is there a step for X?" index.
5. **Gate** new steps at pre-merge so every added definition is acknowledged.
6. **Repeat** on a cadence (quarterly plus threshold-triggered reviews).

## Step 1 - Inventory step definitions

Extract every declared step pattern across the project. Each runner
uses its own annotation syntax (`@Given` in Cucumber-JVM, `@given`
in Behave, `[Given]` in Reqnroll / SpecFlow) - the per-runner
extraction commands are in
[references/step-extraction-and-overlap.md](references/step-extraction-and-overlap.md).

The inventory produces a step audit:

```
Total step definitions: 142
Unique patterns: 138    (4 ambiguous duplicates already)
Per Gherkin verb:
  Given: 58
  When:  34
  Then:  47
  And:    3
```

## Step 2 - Detect duplicates / overlaps

Two patterns are likely duplicates when:

- Same wording, different phrasing: `Given a user` vs `Given an
  existing user` vs `Given the user`.
- Same parameters, different verbs: `When I click {label}` vs
  `When I press {label}` vs `When I tap {label}`.
- Same fixture, different shape: `Given a cart with {n} items` vs
  `Given a cart containing {n} items`.

Normalize each pattern (lowercase, drop articles, collapse
parameters) and group by the normalized form; any group of size
greater than one is a candidate cluster. The overlap script that
does this is in
[references/step-extraction-and-overlap.md](references/step-extraction-and-overlap.md).

## Step 3 - Recommend consolidation

For each duplicate group:

```markdown
**Duplicate group:** 4 step definitions with normalized "user is
logged in"

| Pattern                            | File / line                |
|------------------------------------|----------------------------|
| `Given a user is logged in`         | `auth_steps.py:12`         |
| `Given the user is logged in`        | `cart_steps.py:8`           |
| `Given an authenticated user`        | `checkout_steps.py:5`       |
| `Given a logged-in user`            | `profile_steps.py:14`       |

**Recommendation:** Consolidate to **`Given a logged-in user`**
(highest count of usage in current Gherkin; clearest wording).

Replace the other 3 step definitions with a single canonical one
in `shared_steps.py`. Update the Gherkin features that use the
deprecated patterns.
```

## Step 4 - Domain organization

Group steps per domain area:

```
features/steps/
├── shared/                      # cross-domain (login, navigation, etc.)
│   ├── auth_steps.py
│   ├── navigation_steps.py
│   └── data_steps.py
├── checkout/                    # checkout-specific
│   ├── promo_steps.py
│   ├── payment_steps.py
│   └── cart_steps.py
├── account/                     # account-specific
│   └── profile_steps.py
└── README.md                    # step library index
```

The README is the discoverability artifact:

```markdown
# Step library

## Shared (cross-domain)

### Auth
- `Given a logged-in user` (auth_steps.py:12) - creates and logs in a generic test user.
- `Given a logged-in admin` (auth_steps.py:25) - logged-in user with admin role.
- `Given an unauthenticated visitor` (auth_steps.py:38) - no session.

### Navigation
- `When I navigate to {path}` - go to URL.
- `When I click {label}` - click any element with this label.

## Checkout

### Cart
- `Given the cart contains {qty} of {sku} at ${price}` - seed a cart.
- `Given the cart is empty` - empty cart.

### Promo codes
- `Given promo code {code} is active` - pre-seed a promo in the admin.
- `When I enter {code} in the promo input` - type the code.
- `When I click {label}` - (uses shared step).

(...)
```

The README + grep is the team's "is there a step for X?" tool.

## Step 5 - Pre-merge step gate

Add a CI check that flags new step definitions so no engineer adds a
duplicate unknowingly. The check warns (doesn't block), forcing the
author to acknowledge the new step and grep the README first. The
`check-new-steps.sh` script is in
[references/step-extraction-and-overlap.md](references/step-extraction-and-overlap.md).

## Step 6 - Quarterly cadence

| Cadence            | Trigger                                           |
|--------------------|---------------------------------------------------|
| Quarterly           | Scheduled step library review.                    |
| New team member     | Onboarding: walk the README.                      |
| Step count exceeds threshold | Triggered review.                         |
| New domain area     | Add steps; update README.                          |

## Worked example

Curating a 142-step library in a mixed Behave project, end to end.

**1. Inventory.** Running the Behave extraction over `features/steps/`
yields 142 step definitions and 138 unique patterns - so 4 are
already ambiguous duplicates the runner would flag at match time:

```
Total step definitions: 142
Unique patterns: 138
Given: 58   When: 34   Then: 47   And: 3
```

**2. Detect.** The overlap script normalizes patterns and surfaces
one cluster:

```
Likely duplicates (4): normalized "user is logged in"
  Given a user is logged in    - auth_steps.py:12
  Given the user is logged in   - cart_steps.py:8
  Given an authenticated user   - checkout_steps.py:5
  Given a logged-in user        - profile_steps.py:14
```

**3. Consolidate.** Pick `Given a logged-in user` as canonical
(clearest wording, most-used in current Gherkin). Move it into
`features/steps/shared/auth_steps.py`, delete the other three
definitions, and rewrite the `.feature` files that used the
deprecated phrasings - edit the Gherkin first so no scenario is
left orphaned.

**4. Reorganize + publish.** Split the flat `features/steps/` into
`shared/`, `checkout/`, and `account/`, then regenerate the README
index. The library now advertises
`Given a logged-in user (auth_steps.py) - creates and logs in a generic test user`
under Shared → Auth.

**5. Gate.** Add the pre-merge new-step check. The next PR that adds
`Given the customer is signed in` trips the warning; the author greps
the README, finds `Given a logged-in user`, and reuses it instead of
adding a fifth variant.

Result: 142 → 139 step definitions, zero ambiguous duplicates, one
discoverable index the whole team searches before writing a step.

## Anti-patterns

| Anti-pattern                                                          | Why it fails                                                              | Fix |
|-----------------------------------------------------------------------|---------------------------------------------------------------------------|-----|
| Per-engineer step files (`alice_steps.py`)                            | Ownership without domain alignment; duplication across files.            | Domain-organized files (Step 4). |
| Step library README missing                                            | Discoverability nil; engineers re-implement.                             | README per Step 4. |
| Ambiguous step deletion without grep                                   | Breaks scenarios silently.                                                | Replace canonical → deprecated; update all Gherkin first. |
| Step "shared library" that's a giant `helpers.py`                      | All engineers conflict on it; merge hell.                                | Domain split (Step 4). |
| Reviewing step count quarterly only                                    | Proliferation outpaces review; library bloats.                          | Pre-merge gate (Step 5). |

## Limitations

- **Heuristic duplicate detection.** Some patterns are
  legitimately distinct (`Given a user` for auth vs `Given a user
  with profile data` for profile tests).
- **Domain organization is per-team.** What's "shared" varies.
- **Consolidation cost.** Each refactor touches Gherkin + step
  definitions; not free.
- **Doesn't fix Gherkin quality.** A clean step library doesn't
  prevent imperative-style Gherkin scenarios. Pair with a Gherkin
  style review.

## References

- Step extraction commands, the overlap-detection script, and the
  pre-merge gate:
  [references/step-extraction-and-overlap.md](references/step-extraction-and-overlap.md).
- `cucumber-testing`,
  `behave-testing`,
  `reqnroll-testing` - per-language
  runners this curator works alongside.