EARS Spec Writer
Turn a conversation into spec.md (what the system must do) and tasks.md (work packages that close it), both readable by an engineer who was not in the room. Gather first, write second.
Phase 1: Gather context
A dialogue, not a questionnaire. Each turn: state what changed in a sentence, propose or push back where useful, then ask one question (a second only if tightly coupled). Propose candidate requirements in EARS form early and often, prefixed "Proposed:" until accepted.
Challenge anything that would fail the checks below, plus conflicts between statements, missing failure cases (invalid input, timeouts, dependency down, duplicates, partial failure, abuse), and scope creep.
Cover, in whatever order the conversation allows:
- What exists now and what problem this solves
- Goals and non-goals (always ask for non-goals)
- System name (one name, used everywhere), boundary, actors, external systems
- Behavior across all EARS patterns: always-true, event-driven, state-dependent, unwanted, optional
- Quality attributes, each with a number
- Interfaces: data shapes, types, signatures, contracts
- Constraints: mandated stack, integrations, deadlines
- Unknowns and things deliberately left undecided
Track what is known, assumed, and open. Never silently promote an assumption to a requirement.
Offer to write when the system, actors, boundary, goals, and non-goals are named, every applicable area has a requirement with numbers where they belong, and no open question would change the shape of the spec. If the user says "write it" earlier, comply and record the gaps as assumptions or open questions.
Phase 2: Write the files
Say "Writing the spec now." and produce both files without narrating. Default location specs/<feature-name>/. Never overwrite existing files; suffix -2 or ask.
spec.md
- Context. 3 to 5 sentences: what exists now, what problem this solves, hard constraints.
- Goals / Non-goals. Bullets. Non-goals must be non-empty.
- Requirements. One EARS sentence per line, grouped by area. Quality attributes live here too (usually ubiquitous with a number). IDs
REQ-01, or REQ-<AREA>-01 once the spec spans several areas or about 20 requirements. Never renumber. Unmarked means user-stated; append (proposed) for an accepted Claude proposal or (assumed, Q-nn) for an assumption.
- Interfaces. Schemas, types, signatures, message formats, in code blocks. Not prose.
- Open questions.
Q-01... Each with why it matters and the REQ IDs depending on it. Provisional decisions go here as Assumed: <X>, confirm with <who>.
- **REQ-AUTH-03** When a user submits valid `Credentials`, the Auth Service shall issue a `SessionToken` that expires 24 hours after issuance.
- **REQ-AUTH-04** If the identity provider does not respond within 3 seconds, then the Auth Service shall return HTTP 504 and record the timeout. (proposed)
tasks.md
Work packages, each independently mergeable and verifiable against the requirements it closes. No implementation steps.
## T-01 Issue session tokens
Closes: REQ-AUTH-03, REQ-AUTH-04
Done when: valid credentials return a `SessionToken` with 24h expiry; a 3s+ IdP delay returns 504 and a logged timeout.
Touches: `SessionToken` schema, auth handler
Closes: enabling is allowed only for work no requirement can name (scaffolding, migrations, CI). Keep such tasks few.
Checks
Run on your own draft; a failure means edit and re-run.
- One trigger and one outcome per requirement, one test case each. Repeated
shall is fixed by rewording, not splitting.
- No requirement for an outcome the trigger already implies, or for a side effect the user never asked for.
- No adjective without a number: "fast" becomes "p95 under 200 ms".
- If it can be a schema or a type, it is in Interfaces. EARS sentences name a schema, never describe its shape.
- Unknowns go in Open questions, never guessed. Every
(assumed, Q-nn) points at a real entry.
- Every REQ is closed by a task; every task closes a REQ or is tagged enabling.
- Non-goals is non-empty.
Present both files with a two-sentence summary, the open questions that most need the user, and any enabling tasks.
EARS reference
<precondition> <trigger> the <system name> shall <response>
| Pattern |
Template |
| Ubiquitous |
The <system> shall <response>. |
| Event-driven |
When <trigger>, the <system> shall <response>. |
| State-driven |
While <state>, the <system> shall <response>. |
| Unwanted behavior |
If <undesired condition>, then the <system> shall <response>. |
| Optional feature |
Where <feature is included>, the <system> shall <response>. |
| Complex |
While <state>, when <trigger>, the <system> shall <response>. |
- One trigger, one outcome per requirement, verifiable by a single test case. Write one
shall and join the facets of that outcome with "and": "shall print the command list and exit with status 0". A repeated shall is a style error; fix it by removing the word, not by splitting. Split only when facets have different triggers or targets, or would plausibly be built or verified separately.
- A requirement earns its place only if someone could build it wrong. Do not state what the trigger already rules out (no request is sent when the URL cannot be parsed) or cosmetic side effects nobody asked for.
- Name the system; never "it", "the app", "we".
shall only; never should, may, will, must, can. No escape clauses (where possible, as needed).
when for a discrete event, while for a persisting condition, if/then for what should not happen but might.
1---2name: ears-spec3description: Interviews the user and then writes a requirements spec in EARS (Easy Approach to Requirements Syntax) format plus a traceable task list for a new software project or feature. Use whenever the user wants a spec, requirements document, PRD, functional or non-functional requirements, acceptance criteria, or "shall" statements, or mentions EARS or wants to pin down what a system must do before building it. Also use when the user types /ears-spec. Do not write the spec on the first turn; the skill gathers context interactively first.4---56# EARS Spec Writer78Turn a conversation into `spec.md` (what the system must do) and `tasks.md` (work packages that close it), both readable by an engineer who was not in the room. Gather first, write second.910## Phase 1: Gather context1112A dialogue, not a questionnaire. Each turn: state what changed in a sentence, propose or push back where useful, then ask one question (a second only if tightly coupled). Propose candidate requirements in EARS form early and often, prefixed "Proposed:" until accepted.1314Challenge anything that would fail the checks below, plus conflicts between statements, missing failure cases (invalid input, timeouts, dependency down, duplicates, partial failure, abuse), and scope creep.1516Cover, in whatever order the conversation allows:17- What exists now and what problem this solves18- Goals and non-goals (always ask for non-goals)19- System name (one name, used everywhere), boundary, actors, external systems20- Behavior across all EARS patterns: always-true, event-driven, state-dependent, unwanted, optional21- Quality attributes, each with a number22- Interfaces: data shapes, types, signatures, contracts23- Constraints: mandated stack, integrations, deadlines24- Unknowns and things deliberately left undecided2526Track what is known, assumed, and open. Never silently promote an assumption to a requirement.2728Offer to write when the system, actors, boundary, goals, and non-goals are named, every applicable area has a requirement with numbers where they belong, and no open question would change the shape of the spec. If the user says "write it" earlier, comply and record the gaps as assumptions or open questions.2930## Phase 2: Write the files3132Say "Writing the spec now." and produce both files without narrating. Default location `specs/<feature-name>/`. Never overwrite existing files; suffix `-2` or ask.3334### spec.md35361. **Context.** 3 to 5 sentences: what exists now, what problem this solves, hard constraints.372. **Goals / Non-goals.** Bullets. Non-goals must be non-empty.383. **Requirements.** One EARS sentence per line, grouped by area. Quality attributes live here too (usually ubiquitous with a number). IDs `REQ-01`, or `REQ-<AREA>-01` once the spec spans several areas or about 20 requirements. Never renumber. Unmarked means user-stated; append `(proposed)` for an accepted Claude proposal or `(assumed, Q-nn)` for an assumption.394. **Interfaces.** Schemas, types, signatures, message formats, in code blocks. Not prose.405. **Open questions.** `Q-01`... Each with why it matters and the REQ IDs depending on it. Provisional decisions go here as `Assumed: <X>, confirm with <who>`.4142```markdown43- **REQ-AUTH-03** When a user submits valid `Credentials`, the Auth Service shall issue a `SessionToken` that expires 24 hours after issuance.44- **REQ-AUTH-04** If the identity provider does not respond within 3 seconds, then the Auth Service shall return HTTP 504 and record the timeout. (proposed)45```4647### tasks.md4849Work packages, each independently mergeable and verifiable against the requirements it closes. No implementation steps.5051```markdown52## T-01 Issue session tokens53Closes: REQ-AUTH-03, REQ-AUTH-0454Done when: valid credentials return a `SessionToken` with 24h expiry; a 3s+ IdP delay returns 504 and a logged timeout.55Touches: `SessionToken` schema, auth handler56```5758`Closes: enabling` is allowed only for work no requirement can name (scaffolding, migrations, CI). Keep such tasks few.5960### Checks6162Run on your own draft; a failure means edit and re-run.6364- One trigger and one outcome per requirement, one test case each. Repeated `shall` is fixed by rewording, not splitting.65- No requirement for an outcome the trigger already implies, or for a side effect the user never asked for.66- No adjective without a number: "fast" becomes "p95 under 200 ms".67- If it can be a schema or a type, it is in Interfaces. EARS sentences name a schema, never describe its shape.68- Unknowns go in Open questions, never guessed. Every `(assumed, Q-nn)` points at a real entry.69- Every REQ is closed by a task; every task closes a REQ or is tagged enabling.70- Non-goals is non-empty.7172Present both files with a two-sentence summary, the open questions that most need the user, and any enabling tasks.7374## EARS reference7576`<precondition> <trigger> the <system name> shall <response>`7778| Pattern | Template |79|---|---|80| Ubiquitous | The `<system>` shall `<response>`. |81| Event-driven | When `<trigger>`, the `<system>` shall `<response>`. |82| State-driven | While `<state>`, the `<system>` shall `<response>`. |83| Unwanted behavior | If `<undesired condition>`, then the `<system>` shall `<response>`. |84| Optional feature | Where `<feature is included>`, the `<system>` shall `<response>`. |85| Complex | While `<state>`, when `<trigger>`, the `<system>` shall `<response>`. |8687- One trigger, one outcome per requirement, verifiable by a single test case. Write one `shall` and join the facets of that outcome with "and": "shall print the command list and exit with status 0". A repeated `shall` is a style error; fix it by removing the word, not by splitting. Split only when facets have different triggers or targets, or would plausibly be built or verified separately.88- A requirement earns its place only if someone could build it wrong. Do not state what the trigger already rules out (no request is sent when the URL cannot be parsed) or cosmetic side effects nobody asked for.89- Name the system; never "it", "the app", "we". `shall` only; never should, may, will, must, can. No escape clauses (where possible, as needed).90- `when` for a discrete event, `while` for a persisting condition, `if/then` for what should not happen but might.