Purpose
Stage: Spec (human-led — the agent drafts, the human signs). acceptance-criteria authors one feature's
acceptance.md: its observable behavior, written as Given/When/Then scenarios in plain prose.
This is the highest-leverage artifact in the whole suite. Because the agent runs Implement → Verify →
Review → Ship fully autonomously with no mid-run human halt, acceptance.md is the
human-anchored oracle for this feature's behavior — the one place a human pins down "what done
means" for it before going AFK. It is the run's only human-anchored oracle, which is why a
behavior missing from it is a behavior nothing checks. test-driven-development
realizes each scenario as a RED test; quality-verification grades the running app against these scenarios and keeps an
exercised/not-reachable ledger by id; pull-request forces a human-ack line for any scenario the run could not
reach. A behavior you forget to write here is a behavior no gate will ever check. Completeness is the
job.
It is a prose contract, not a test framework: no Cucumber, no step-defs, no .feature engine.
Rigid frameworks are anti-boring-tech and brittle on UI; the agent realizes each scenario as a test
through test-driven-development by judgment. Drift control is the intelligent Verify gate reading
acceptance.md, not a mechanical scenario↔test mapping.
When to use / when to skip
Use after to-prd lands prd.md, for every feature, before plan-breakdown/test-driven-development/quality-verification. On a UI
feature one skill sits in between: frontend-design runs in Spec after to-prd and before
acceptance-criteria and environment-manifest run — not merely before they are signed. Exploring an
interface surfaces behaviour a prd.md omits (the empty state, the failed save), and that has to reach
acceptance.md while it is being written rather than after it exists. If you are reaching
for the words "acceptance criteria", "definition of done", or "let me write some test scenarios", you are
in this skill's territory — use it.
Skip / don't when:
- the change is a pure refactor with zero product-observable behavior change — there is no new
behavior to pin. (Refactors are still covered by existing scenarios + regression tests.)
- you are tempted to write a design scenario ("the button is blue", "the modal slides in", "the focus
ring is visible"). STOP — design floors, rubric, and prototype-fidelity live in
frontend-design's signed design contract, never here. Zero design content enters acceptance.md. The two
signed artifacts must never be able to contradict each other.
Escape hatch — depth: lite: a one-story feature still writes the happy path plus at least one
error/edge scenario. Never zero error coverage; "the happy path is obvious" is the failure mode this
skill exists to prevent.
Inputs
Refuse-to-run unless these resolve:
- REQUIRED —
docs/features/<slug>/prd.md (from to-prd) with a populated ## User Stories
section (numbered list, As an <actor>, I want <feature>, so that <benefit>). The story numbers are the
ids your scenarios back-reference. If prd.md is absent or has no ## User Stories → STOP
and send the user to to-prd. There is nothing to derive scenarios from.
- Also read (context, not back-referenced):
## Problem / ## Solution (to frame the happy paths) and
## Out of Scope (the not-doing boundary — these are never scenarios; an out-of-scope item that
needs a guarantee is a security-observable scenario stated as a behavior the system must refuse).
If STATE.md / docs/features/ do not exist, the repo was never set up → run project-setup first.
Process
Read prd.md fully. Note every numbered story id under ## User Stories. Frame the user-observable
happy paths from ## Problem / ## Solution. Read ## Out of Scope to know the boundary.
Enumerate behaviors per story — three classes (see below). For each story, ask: what does the user
observe when it works? when input/state is wrong? what must the system refuse or protect? Do not
stop at the happy path — error/edge and security-observable are required classes, not extras.
Write each behavior as a Given/When/Then scenario, behavioral-only. Assert outcomes the user or
system can observe — never a file path, signature, table name, library, or design token. Plain prose.
Id every scenario. Use the feature's PRD namespace + A + number: PWR-A1, PWR-A2, …
(matching the STATE.md PRD-namespacing). Tag each scenario with the story id it realizes
(realizes: story 3). Multiple scenarios may realize one story; every story must have ≥1 scenario.
Set frontmatter status: draft. Do NOT sign. Only the human signs at the Spec gate (status: signed). If you set signed yourself you have forged the oracle (Red flags).
Self-check coverage + the behavioral-only boundary (Verification below). Every story id → ≥1
scenario; three classes present where applicable; zero design/impl/engine content.
Present for sign-off. Hand the human a complete draft as soon as it lands — this is the one Spec
artifact that presents on its own, because everything downstream depends on it as the oracle. Signing
waits: architecture-design runs against a draft acceptance.md — present, not signed — and the
two are signed together in one act at the Spec gate, so the scenarios cannot move between the trace and
the signature. A scenario that traces through nothing goes back to acceptance-criteria while it is
still editable. The round trip is bounded at one: anything still unresolved becomes an open question
the person answers at the gate. What a later prd.md edit un-signs is stated once, in
using-agent-skills's What an edit un-signs.
The three required scenario classes
Every feature covers these classes (a story may not touch all three, but the feature must):
- Happy path — the feature working as intended, the user's main goal achieved. (≥1 per story.)
- Error / edge — invalid input, wrong state, boundary values, expiry, concurrency, empty/limit cases.
The behavior the user observes when things go wrong (clear failure, no data loss, safe state).
- Security-observable — behavior a user/attacker can observe that proves a boundary holds: an expired
token is rejected, an unauthorized actor is refused, a secret never appears in a response, rate limits
trip. Observable only — not "the code uses bcrypt" (that is implementation, and design/threat
rationale lives in ADRs/
security-and-hardening, not here).
Behavioral-only boundary
acceptance.md asserts what is observable, and nothing else:
- NO design content — no color, typography, spacing, layout, motion, focus-ring, pixel, breakpoint.
All of that is
frontend-design's signed design contract (a Spec artifact UI features add to the
bundle) and, for an axis that contract marks inherited, docs/design.md. quality-verification's
design gate grades those; acceptance.md grades behavior. Neither ever carries the other's content.
- NO implementation content — no file path, function/type signature, schema-as-code, table/column
name, driver or library internal. Scenarios survive a rewrite of the implementation.
- NO engine — no
.feature files, no @given/@when step definitions, no Cucumber/Behave/SpecFlow.
Prose only; test-driven-development turns prose into tests by judgment.
Scenario anatomy
### PWR-A2 — reset link rejected after expiry realizes: story 3 class: error/edge
Given a password-reset link issued more than 1 hour ago
When the user opens that link and submits a new password
Then the system refuses the reset and tells the user the link has expired
And the user's existing password is unchanged
Keep ids stable once written (downstream qa.md ledgers reference them). Append new scenarios with new
ids rather than renumbering.
Rationalizations
Stop signals disguised as good reasons:
- "I'll just cover the happy path; the errors are obvious." → No. Error/edge is a required class, and
"obvious" failures are exactly where the autonomous run ships silent defects. Enumerate them.
- "This UI scenario needs the button colour / the modal animation." → No. Design lives in
frontend-design's contract, not here. Behavioral-only here — assert what the user does, not how it looks.
- "I'll name the function / endpoint path so the test is precise." → No. Outcomes only. Signatures and
paths go stale and turn the oracle into an implementation mirror;
test-driven-development/plan-breakdown own those.
- "It looks right — I'll mark it
signed." → No. The human signs; signed set by the agent forges a
human-anchored oracle. Leave it draft and present for sign-off.
- "Cucumber would make this executable." → No engine. Executability comes from
test-driven-development realizing the
prose, not from a brittle step-def framework.
- "The PRD has 8 stories but 3 are similar — I'll write 3 scenarios total." → Every story id needs
≥1 scenario. Coverage is the load-bearing property; thin it and a gate goes blind.
Red flags
Stop and fix before presenting if any are true:
- A scenario mentions a
/ file path, a function/def/type signature, a table/column name, or a
library/driver name. → Strip it; restate as an observable outcome.
- A scenario describes colour, font, pixel, spacing, layout, motion, or focus styling. → Move the intent
to
frontend-design's design contract; delete it here.
- A
.feature file or step-definition code was generated. → Delete; this is a prose contract.
- Any
## User Stories id has zero scenarios. → The oracle has a hole; add scenarios.
- A feature with risky paths has only happy-path scenarios (no error/edge, no security-observable).
- Frontmatter says
status: signed and no human signed it. → Revert to draft; present for sign-off.
Verification (ending criteria)
Done when ALL hold:
docs/features/<slug>/acceptance.md exists, frontmatter status: draft (never signed by the agent).
- Coverage: every numbered id in
prd.md's ## User Stories is named by ≥1 scenario's realizes:
tag. (This is the completeness invariant spec-review re-checks: every story id → ≥1 reachable
exercised scenario.)
- Every scenario has a feature-namespaced id matching
^### [A-Z]{2,}-A[0-9]+ and a realizes: story <n>
back-reference and a class: of happy / error/edge / security-observable.
- The three classes are represented across the feature (happy + ≥1 error/edge + ≥1 security-observable
where the feature has any boundary to protect).
- Behavioral-only grep is clean: no file paths, signatures, schemas-as-code, library internals, or
design tokens (colour/font/px/layout/motion). No
.feature/step-def artifacts exist.
- Presented to the human for sign-off; the gate stays
you until the human flips status: signed.
Outputs & handoff contract
- Emits:
docs/features/<slug>/acceptance.md — per-scenario id · realizes: story <n> · class: ·
Given/When/Then prose; frontmatter status: draft → signed. Change the shape of a scenario id or the
status field → update its consumers (architecture-design, test-driven-development, quality-verification, spec-review, pull-request) in the same commit.
- STATE.md update: add
acceptance.md to the feature's origin: line; feature state stays spec;
gate stays you (the human signs at the Spec gate). No slice rows yet (slices are born in Plan).
- Downstream consumers:
architecture-design (traces every scenario through the structure while this
file is still draft) · test-driven-development (realizes each scenario as a RED test, test-first; refuses an
unsigned/absent contract) · quality-verification (grades the running app per scenario, keeps an exercised/not-reachable
ledger by id in qa.md; refuses an unsigned contract) · spec-review (checks every story id → ≥1
reachable scenario before the human reviews) · pull-request (any "not-reachable" classification at run time
→ a required human-ack line in the PR body, never silently absorbed).
- Frozen-under-retry invariant — safety rail 4,
references/safety-rails.md. What this skill owns
is the way out: the contract changes only by a fresh human re-sign, never by an agent's edit.
- Boundary with
frontend-design: design floors/rubric/prototype-fidelity live in its signed design
contract and, for an axis that contract marks inherited, in docs/design.md; acceptance.md carries
zero design content. No two signed artifacts can contradict. frontend-design running before this
skill makes the boundary matter more, not less: what the exploration surfaces about behaviour (the
empty state, the failed save) belongs here, and what it decides about look never does.
1---2name: acceptance-criteria3description: Turn a prd.md into acceptance.md — the Given/When/Then prose contract that is the human-anchored oracle for THIS feature's behavior across the entire autonomous run — the only human-anchored oracle the run has. Reach for this the MOMENT a prd.md exists (on a UI feature, once frontend-design has explored the interface) and BEFORE any planning, TDD, or QA — test-driven-development and quality-verification REFUSE to run without a signed acceptance.md. If you are about to write "acceptance criteria", "definition of done", test scenarios, or Given/When/Then for a feature, you need this first. Behavioral-only: keep ALL design floors out (those belong to frontend-design's contract).4---56## Purpose78**Stage: Spec (human-led — the agent drafts, the human signs).** `acceptance-criteria` authors one feature's9`acceptance.md`: its observable behavior, written as Given/When/Then scenarios in plain prose.1011This is the highest-leverage artifact in the whole suite. Because the agent runs Implement → Verify →12Review → Ship **fully autonomously with no mid-run human halt**, `acceptance.md` is the13**human-anchored oracle for this feature's behavior** — the one place a human pins down "what *done*14means" for it before going AFK. It is the run's only human-anchored oracle, which is why a15behavior missing from it is a behavior nothing checks. `test-driven-development`16realizes each scenario as a RED test; `quality-verification` grades the running app against these scenarios and keeps an17exercised/not-reachable ledger by id; `pull-request` forces a human-ack line for any scenario the run could not18reach. **A behavior you forget to write here is a behavior no gate will ever check.** Completeness is the19job.2021It is a **prose contract, not a test framework**: no Cucumber, no step-defs, no `.feature` engine.22Rigid frameworks are anti-boring-tech and brittle on UI; the agent realizes each scenario as a test23through `test-driven-development` **by judgment**. Drift control is the intelligent Verify gate reading24`acceptance.md`, not a mechanical scenario↔test mapping.2526## When to use / when to skip2728**Use** after `to-prd` lands `prd.md`, for every feature, before `plan-breakdown`/`test-driven-development`/`quality-verification`. On a UI29feature one skill sits in between: `frontend-design` runs in Spec after `to-prd` and **before30`acceptance-criteria` and `environment-manifest` run** — not merely before they are signed. Exploring an31interface surfaces behaviour a `prd.md` omits (the empty state, the failed save), and that has to reach32`acceptance.md` while it is being written rather than after it exists. If you are reaching33for the words "acceptance criteria", "definition of done", or "let me write some test scenarios", you are34in this skill's territory — use it.3536**Skip / don't** when:37- the change is a **pure refactor** with zero product-observable behavior change — there is no new38 behavior to pin. (Refactors are still covered by existing scenarios + regression tests.)39- you are tempted to write a **design** scenario ("the button is blue", "the modal slides in", "the focus40 ring is visible"). **STOP** — design floors, rubric, and prototype-fidelity live in41 `frontend-design`'s signed design contract, never here. Zero design content enters `acceptance.md`. The two42 signed artifacts must never be able to contradict each other.4344**Escape hatch — `depth: lite`:** a one-story feature still writes the happy path **plus at least one45error/edge scenario**. Never zero error coverage; "the happy path is obvious" is the failure mode this46skill exists to prevent.4748## Inputs4950Refuse-to-run unless these resolve:5152- **REQUIRED — `docs/features/<slug>/prd.md`** (from `to-prd`) with a populated **`## User Stories`**53 section (numbered list, `As an <actor>, I want <feature>, so that <benefit>`). The story numbers are the54 ids your scenarios back-reference. If `prd.md` is **absent** or has **no `## User Stories`** → **STOP**55 and send the user to `to-prd`. There is nothing to derive scenarios from.56- Also read (context, not back-referenced): `## Problem` / `## Solution` (to frame the happy paths) and57 `## Out of Scope` (the not-doing boundary — these are **never** scenarios; an out-of-scope item that58 needs a guarantee is a *security-observable* scenario stated as a behavior the system must refuse).5960If `STATE.md` / `docs/features/` do not exist, the repo was never set up → run `project-setup` first.6162## Process63641. **Read `prd.md` fully.** Note every numbered story id under `## User Stories`. Frame the user-observable65 happy paths from `## Problem` / `## Solution`. Read `## Out of Scope` to know the boundary.66672. **Enumerate behaviors per story — three classes (see below).** For each story, ask: what does the user68 observe when it works? when input/state is wrong? what must the system refuse or protect? Do **not**69 stop at the happy path — error/edge and security-observable are *required classes*, not extras.70713. **Write each behavior as a Given/When/Then scenario, behavioral-only.** Assert *outcomes the user or72 system can observe* — never a file path, signature, table name, library, or design token. Plain prose.73744. **Id every scenario.** Use the feature's PRD namespace + `A` + number: `PWR-A1`, `PWR-A2`, …75 (matching the STATE.md PRD-namespacing). Tag each scenario with the **story id it realizes**76 (`realizes: story 3`). Multiple scenarios may realize one story; every story must have ≥1 scenario.77785. **Set frontmatter `status: draft`. Do NOT sign.** Only the human signs at the Spec gate (`status:79 signed`). If you set `signed` yourself you have forged the oracle (Red flags).80816. **Self-check coverage + the behavioral-only boundary** (Verification below). Every story id → ≥182 scenario; three classes present where applicable; zero design/impl/engine content.83847. **Present for sign-off.** Hand the human a complete draft as soon as it lands — this is the one Spec85 artifact that presents on its own, because everything downstream depends on it as the oracle. Signing86 waits: `architecture-design` runs against a **draft** `acceptance.md` — present, not signed — and the87 two are signed together in one act at the Spec gate, so the scenarios cannot move between the trace and88 the signature. A scenario that traces through nothing goes back to `acceptance-criteria` while it is89 still editable. The round trip is bounded at one: anything still unresolved becomes an open question90 the person answers at the gate. What a later `prd.md` edit un-signs is stated once, in91 `using-agent-skills`'s *What an edit un-signs*.9293## The three required scenario classes9495Every feature covers these classes (a story may not touch all three, but the feature must):9697- **Happy path** — the feature working as intended, the user's main goal achieved. (≥1 per story.)98- **Error / edge** — invalid input, wrong state, boundary values, expiry, concurrency, empty/limit cases.99 The behavior the user observes when things go wrong (clear failure, no data loss, safe state).100- **Security-observable** — behavior a user/attacker can observe that proves a boundary holds: an expired101 token is rejected, an unauthorized actor is refused, a secret never appears in a response, rate limits102 trip. **Observable** only — not "the code uses bcrypt" (that is implementation, and design/threat103 rationale lives in ADRs/`security-and-hardening`, not here).104105## Behavioral-only boundary106107`acceptance.md` asserts **what is observable**, and nothing else:108109- **NO design content** — no color, typography, spacing, layout, motion, focus-ring, pixel, breakpoint.110 All of that is `frontend-design`'s signed design contract (a Spec artifact UI features add to the111 bundle) and, for an axis that contract marks inherited, `docs/design.md`. `quality-verification`'s112 design gate grades those; `acceptance.md` grades behavior. Neither ever carries the other's content.113- **NO implementation content** — no file path, function/type signature, schema-as-code, table/column114 name, driver or library internal. Scenarios survive a rewrite of the implementation.115- **NO engine** — no `.feature` files, no `@given`/`@when` step definitions, no Cucumber/Behave/SpecFlow.116 Prose only; `test-driven-development` turns prose into tests by judgment.117118## Scenario anatomy119120```121### PWR-A2 — reset link rejected after expiry realizes: story 3 class: error/edge122Given a password-reset link issued more than 1 hour ago123When the user opens that link and submits a new password124Then the system refuses the reset and tells the user the link has expired125And the user's existing password is unchanged126```127128Keep ids stable once written (downstream `qa.md` ledgers reference them). Append new scenarios with new129ids rather than renumbering.130131## Rationalizations132133Stop signals disguised as good reasons:134135- "I'll just cover the happy path; the errors are obvious." → No. Error/edge is a **required class**, and136 "obvious" failures are exactly where the autonomous run ships silent defects. Enumerate them.137- "This UI scenario needs the button colour / the modal animation." → No. Design lives in138 `frontend-design`'s contract, not here. Behavioral-only here — assert what the user *does*, not how it looks.139- "I'll name the function / endpoint path so the test is precise." → No. Outcomes only. Signatures and140 paths go stale and turn the oracle into an implementation mirror; `test-driven-development`/`plan-breakdown` own those.141- "It looks right — I'll mark it `signed`." → No. The **human signs**; `signed` set by the agent forges a142 human-anchored oracle. Leave it `draft` and present for sign-off.143- "Cucumber would make this executable." → No engine. Executability comes from `test-driven-development` realizing the144 prose, not from a brittle step-def framework.145- "The PRD has 8 stories but 3 are similar — I'll write 3 scenarios total." → Every **story id** needs146 ≥1 scenario. Coverage is the load-bearing property; thin it and a gate goes blind.147148## Red flags149150Stop and fix before presenting if any are true:151152- A scenario mentions a `/` file path, a `function`/`def`/type signature, a table/column name, or a153 library/driver name. → Strip it; restate as an observable outcome.154- A scenario describes colour, font, pixel, spacing, layout, motion, or focus styling. → Move the intent155 to `frontend-design`'s design contract; delete it here.156- A `.feature` file or step-definition code was generated. → Delete; this is a prose contract.157- Any `## User Stories` id has **zero** scenarios. → The oracle has a hole; add scenarios.158- A feature with risky paths has **only** happy-path scenarios (no error/edge, no security-observable).159- Frontmatter says `status: signed` and no human signed it. → Revert to `draft`; present for sign-off.160161## Verification (ending criteria)162163Done when ALL hold:164165- `docs/features/<slug>/acceptance.md` exists, frontmatter `status: draft` (never `signed` by the agent).166- **Coverage:** every numbered id in `prd.md`'s `## User Stories` is named by ≥1 scenario's `realizes:`167 tag. (This is the completeness invariant `spec-review` re-checks: every story id → ≥1 reachable168 exercised scenario.)169- Every scenario has a feature-namespaced id matching `^### [A-Z]{2,}-A[0-9]+` and a `realizes: story <n>`170 back-reference and a `class:` of happy / error/edge / security-observable.171- The three classes are represented across the feature (happy + ≥1 error/edge + ≥1 security-observable172 where the feature has any boundary to protect).173- **Behavioral-only grep is clean:** no file paths, signatures, schemas-as-code, library internals, or174 design tokens (colour/font/px/layout/motion). No `.feature`/step-def artifacts exist.175- Presented to the human for sign-off; the gate stays `you` until the human flips `status: signed`.176177## Outputs & handoff contract178179- **Emits:** `docs/features/<slug>/acceptance.md` — per-scenario `id` · `realizes: story <n>` · `class:` ·180 Given/When/Then prose; frontmatter `status: draft → signed`. Change the shape of a scenario id or the181 status field → update its consumers (`architecture-design`, `test-driven-development`, `quality-verification`, `spec-review`, `pull-request`) in the same commit.182- **STATE.md update:** add `acceptance.md` to the feature's `origin:` line; feature state stays `spec`;183 gate stays `you` (the human signs at the Spec gate). No slice rows yet (slices are born in Plan).184- **Downstream consumers:** `architecture-design` (traces every scenario through the structure while this185 file is still `draft`) · `test-driven-development` (realizes each scenario as a RED test, test-first; refuses an186 unsigned/absent contract) · `quality-verification` (grades the running app per scenario, keeps an exercised/not-reachable187 ledger by id in `qa.md`; refuses an unsigned contract) · `spec-review` (checks every story id → ≥1188 reachable scenario before the human reviews) · `pull-request` (any "not-reachable" classification at run time189 → a required human-ack line in the PR body, never silently absorbed).190- **Frozen-under-retry invariant** — safety rail 4, `references/safety-rails.md`. What this skill owns191 is the way out: the contract changes only by a **fresh human re-sign**, never by an agent's edit.192- **Boundary with `frontend-design`:** design floors/rubric/prototype-fidelity live in its signed design193 contract and, for an axis that contract marks inherited, in `docs/design.md`; `acceptance.md` carries194 zero design content. No two signed artifacts can contradict. `frontend-design` running *before* this195 skill makes the boundary matter more, not less: what the exploration surfaces about **behaviour** (the196 empty state, the failed save) belongs here, and what it decides about **look** never does.