Installs into .claude/skills of the current project.
Are you the author of Acceptance Criteria Gwt?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/makifbaysal-acceptance-criteria-gwt)
---
name: acceptance-criteria-gwt
category: pm
description: Use when writing acceptance criteria for a task - express each as an observable Given/When/Then that QA can execute, including negative cases
source: cucumber/docs better-gherkin.md (MIT), adapted
---
# Acceptance Criteria (Given/When/Then)
## Overview
Acceptance criteria are the contract QA tests the product against and the PM verifies at UAT. If a criterion isn't executable, it can't be verified — and unverifiable criteria are where defects hide.
**Core principle:** Every criterion is an observable behavior QA can execute with a command or a click path. No aspirational adjectives.
## The shape
`Given [precondition], When [action], Then [measurable result].`
## Where they go
Criteria live in the board task's own `acceptance_criteria` field — an array of strings, one criterion per item, passed to `create_board_task` (or `update_board_task` to replace the whole list). Each item becomes a checkbox the implementer ticks with `set_criterion_completed`, and that QA (in ready_for_qa/in_qa) and you (in pm_uat) then rule on independently with `review_criterion`. The tick is the implementer's claim — QA and PM never call `set_criterion_completed`; your verdict is `review_criterion`.
Never write them into `description`. A criteria block pasted as markdown leaves the task's checklist empty: nothing to tick, nothing the move guard can check, and the prose copy goes stale the moment the real criteria are edited.
## Testability gate
For each criterion, before you save it, write down:
- **who executes it** — QA in in_qa, and the PM in pm_uat with browser or mobile tools (or `http_request` against the task's own preview when the surface is an API, not a screen);
- **the action** — a click path, a URL, or a request;
- **the exact observable** — text, a count, an element state, or a file.
If the behaviour is user-facing, the Then must be visible in the UI — not a status code standing in for what the user sees. If nobody outside the code can observe it, it belongs in `technical_description`, not in a criterion.
## Declarative When, concrete Then
Write the When as what happens, not the click-by-click path — the cucumber test: "Will this wording need to change if the implementation changes?" If yes, it's too imperative. One behaviour per criterion. Put exact copy strings in quotes in the Then; "an error appears" is not testable, "'Title must be at most 200 characters' appears under the field" is.
## Never a criterion: board actions
A criterion states what the finished WORK is, never what the board does around
it. These are not criteria and the tools drop them:
| Not a criterion | Why | Write instead |
|---|---|---|
| "Task moved to ready_for_qa / analiz_review / done" | a column move is workflow; the agent's role already tells it where the card goes | the behaviour that makes the task ready |
| "Implementation tasks are created" | they are opened AFTER this task is approved — a criterion nobody can tick before the hand-off keeps the card out of done forever | what the plan those tasks come from must contain |
| "Spec attached with add_task_document" / "questions asked with add_task_comment" | naming the tool describes the mechanics, and an attached document is not a good one | what the document must say |
| "Presented for human approval" / "assigned to the developer" | hand-offs are the flow's job | nothing — the flow does it |
The test: could a reviewer check it by looking only at the product and the
documents, without opening the board's history? If not, it is not a criterion.
## Rules
- **Observable + measurable.** "Then a 422 with message 'title too long'" — not "Then it handles it gracefully."
- **At least one negative criterion where the feature accepts input or has permissions:** invalid input, unauthorized access, empty state. Not required for a pure copy or styling change.
- **3–7 criteria per task.** More means the task should be split.
- **No 'fast'/'user-friendly'/'robust'** — replace with a number or a concrete behavior.
## Mid-flight edits
`update_board_task(acceptance_criteria=…)` replaces the whole array and resets every tick on it — use it only before work starts, or when the human explicitly asked for the change. To drop one criterion from a task already in progress (descoped, superseded, covered elsewhere), use `cancel_criterion` with a reason instead of rewriting the list.
## Worked Example
Feature: reject task titles over 200 chars, in the New Task dialog.
```
❌ Given a create-task form, When I submit a 201-char title, Then I get 422.
(status code stands in for what the user sees — fine for an API-only task, not for a dialog)
✅ AC1 (happy) Given the New Task dialog,
When I enter a 200-character title and press Create,
Then the dialog closes and a card with that title appears on the board.
✅ AC2 (boundary/negative)
Given the New Task dialog,
When I enter a 201-character title and press Create,
Then the dialog stays open, shows "Title must be at most 200 characters"
under the field, and no card is added to the board.
✅ AC3 (auth/negative)
Given a user without write access to the project,
When they open the board,
Then the "New Task" button is not shown.
```
Keep one API-surface example only when the API itself is the product (usually a `task_type: "technical"` task):
```
Given a member of the project, When they GET /api/v1/projects/:id/tasks/export,
Then they get 200 + text/csv with header "id,title,status,created_at"
```
## Common Mistakes
- A board action as a criterion (see above) — the most common one is "the task is moved to X".
- An HTTP status as the only Then on a user-facing task — say what the user sees, not the wire protocol underneath it.
- Aspirational wording ("intuitive", "fast").
- Only happy-path criteria, no negative, on a task with input or permissions.
- A "Then" with no exact text, count or state — "an error appears" instead of the exact copy.
- 12 criteria on one task → split it.
- Criteria pasted into `description` as a markdown list instead of passed as `acceptance_criteria`.
- Rewriting `acceptance_criteria` on a task already in progress instead of `cancel_criterion`.
## Red Flags
- QA asks "how do I test this?" → the AC isn't executable; run it through the testability gate again.
- No negative/auth criterion on a task that takes input or checks permission.
- An adjective in a "Then".
- A criterion that names a board tool or a column the card must reach.