all skills / specify
arsdlc-spec
Write or repair an EARS specification (spec.md) that passes `npx arsdlc check spec`.
Use when `arsdlc next` reports SPECIFY, the user says "write the spec", "spec it", "requirements", "to-spec", or a spec still has [NEEDS CLARIFICATION], a requirement without SHALL, or without a Scenario. Covers happy, failure and edge scenarios, non-functionals, test seams, the UI interaction contract and glossary terms, and runs a two-pass adversarial review for conflicts and vague quantifiers.
MIT · skills/arsdlc-spec/SKILL.md · read the same way by every supported harness
Install everything, or just this one
npx skills add AnshRoshan/arsdlcnpx skills add AnshRoshan/arsdlc --skill arsdlc-specClaude Code: /plugin marketplace add AnshRoshan/arsdlc, then/plugin install arsdlc@arsdlc. Skills work without the CLI; the CLI is what makes done mean something.
A spec is a contract a stranger could verify. Every requirement is testable; every ambiguity is marked, never papered over. You could hand it to a competitor's engineer and get the same product back.
EARS in 30 seconds
| pattern | shape | use for |
|---|---|---|
| Ubiquitous | THE SYSTEM SHALL <response> | always-true properties (limits, formats, security) |
| Event-driven | WHEN <trigger> THE SYSTEM SHALL <response> | the happy paths |
| State-driven | WHILE <state> THE SYSTEM SHALL <response> | modes, in-progress, degraded |
| Unwanted behaviour | IF <condition> THEN THE SYSTEM SHALL <response> | failures, abuse, bad input |
| Optional feature | WHERE <feature is present> THE SYSTEM SHALL <response> | flags, tiers, platforms |
One SHALL per requirement. No "and/or", no "quickly", no "user-friendly", no "etc.". Numbers, not adjectives. Use the nouns from docs/glossary.md; if you need a new noun, add it there first.
File contract: docs/features/<slug>/spec.md
Use this artifact shape; npx arsdlc check spec docs/features/<slug>/spec.md checks the EARS rules below, not every section:
# Spec: <title>
## 1. Context
Kind: **<kind>**. Lane: **<lane>**. Verify model: <what proves it works>.
Problem: <one sentence from the brief>. Users: <roles>.
## 2. Goals / Non-goals
- Goal: ...
- Non-goal: ...
## 3. Requirements (EARS)
### Requirement: <Short Unique Name>
WHEN <trigger> THE SYSTEM SHALL <response>.
#### Scenario: <happy path name>
- GIVEN <precondition>
- WHEN <action>
- THEN <observable result with a number or exact value>
#### Scenario: <failure or edge name>
- GIVEN ...
- WHEN ...
- THEN ...
## 4. Constraints (non-functional, also EARS)
- THE SYSTEM SHALL <security / privacy / performance / a11y / compatibility property>.
## 5. Acceptance bar
Approved-by: ______ Date: ______
## 6. Open questions
| # | Question | Owner | Status |
|---|---|---|---|
## 7. Seams (where tests attach)
- <seam>: <public interface: HTTP route / CLI / exported function / UI flow> · exists today: yes/no
## 8. UX & interaction (kinds frontend / mobile; non-UI kinds get `n/a: <kind>`)
Primary journey: <one line: who does what, in order>
States: default · loading · empty (<what the user sees with no data>) · error (<what it says and what they can do>) · offline (if applicable)
A11y bar: <keyboard path, focus order, contrast/label rule — from docs/taste.md §UI, not invented here>
Touch targets / density: <only if it differs from the taste profile>
## 9. Value sourcing
| Value | Source | How obtained |
|---|---|---|
| <every field, number, message, state and file this feature produces, computes or displays> | <requirement name / API response / stored record / derived from X> | <the call, query or computation that yields it> |
Hard rules the validator checks:
- At least one
### Requirement:block. Names are unique; tasks reference them verbatim as[R:<name>]. - Every requirement contains
SHALLorMUSTand at least one#### Scenario:. - Zero
[NEEDS CLARIFICATION: ...]markers remain when you claim the spec is ready. While drafting, use them liberally; a marker is honest, a guess is not. - §5
Approved-by:is left for a human. Never fill it. Underscores mean unsigned. (Lanespikedoes not require a signature.) - §6 rows whose Status is not
done/resolved/closed/n/aare reported as warnings. - G2 (not
check spec) requires §9: named sources for every value, orn/a: <why>. A value with no source is an owed decision.
Rules the validator cannot check but the reviewer will:
- Every requirement has at least one unhappy scenario (IF/THEN) unless it is genuinely impossible to fail; say so if so.
- Every THEN is observable from outside the system (response, file, row, pixel, log line), with a value a test can assert.
- Section 4 has, at minimum, one line each for auth (who may not), data (what is stored/retained/PII), and a performance or size budget with a number, or explicitly
n/a: <why>. - Section 7 names the seams; prefer existing seams, the highest level that still isolates the behaviour, and as few as possible. Tests will live there and nowhere else.
- For kinds
frontendandmobile, §8 exists and is filled fromdocs/taste.md§UI — a spec with no states section will be built with invented loading and empty states. - §9 is built by walking the THEN clauses, not by asking yourself how you feel. For each requirement, list every thing the system must hand over: a field, a computed number, a message, a state, a file, an ID. Name the source of each. "Do I feel like I'm inventing something" is not a test, because the model that has to make the call rationalises a real design decision as plumbing; an enumerated list with a named source per row cannot be rationalised past.
- No two requirements contradict. Two
SHALLs that no single implementation can satisfy (retry forever vs. fail fast; log everything vs. never log PII; always sync vs. offline-first) is the most expensive class of spec bug, and it survives every per-requirement check because each requirement is individually valid. Read the requirement pairs against each other, not just each against its scenarios. - No ambiguous quantifier survives without a number. "quickly", "many", "large", "as needed", "frequently", "appropriate" — every one of them becomes two different implementations. Replace with a value or mark
[NEEDS CLARIFICATION: what number?]. - No requirement describes implementation that the plan does not yet own ("use Redis", "call the Stripe API"). Behaviour here; technology in
plan.mdDecisions.
Procedure
- Read
docs/brief.md,docs/taste.md,docs/glossary.md,baseline.md(brownfield) and anydeltas/. Skim the code the seams will touch; facts you find are not questions you ask. - Draft requirements from the brief's must-haves: one requirement per must-have, one scenario per observable path (happy, failure, edge). Add ubiquitous requirements for the non-functional needs.
- For each unknown write
[NEEDS CLARIFICATION: <question>]inline and add a §6 row. Then loadarsdlc-grillin "grill the spec" mode: work the open questions as a frontier, one round at a time, each with a recommended answer. Resolve the markers with the answers; leave nothing implicit. - Two adversarial passes (do this yourself before asking a human):
- Within each requirement: "what input breaks this?", "what if it happens twice?", "what if it happens while <other state>?", "who must not be able to do this?". Add scenarios or mark clarifications.
- Between requirements: read every pair that could interact and ask "can both of these hold at once?" Contradictions, overlapping ownership ("who is responsible for X?" answered twice differently), and one requirement quietly superseding another all hide here. Also sweep for unnumbered quantifiers. Fix by merging, narrowing, or a
[NEEDS CLARIFICATION]— never by picking a winner yourself.
- Run
npx arsdlc check spec <path>; fix until 0 errors. Paste the validator output in your reply. (CLI unavailable? Check the hard rules by hand and say you did.) - Ask the human to sign §5 (name + date);
arsdlc approvedoes not sign specs. Do not proceed untilarsdlc nextmoves to PLAN (or TASKS/BUILD in the quick lane).
Compact mode (lane quick)
1-3 requirements, each with a happy and a failure scenario, §4 with the auth/data lines, §7 with one seam. §8 becomes one line for frontend/mobile kinds (journey + the two states you are most likely to get wrong: empty and error). Skip §6 if empty. Same validator, same signature. Should take under ten minutes; if it is taking longer, the lane is wrong: upgrade with npx arsdlc lane <slug> standard.
Spike mode (lane spike)
One requirement: THE SYSTEM SHALL answer: <question> with one scenario whose THEN names the measurement and the threshold that decides. §1 gets the answer and the recommendation once the probe has run. No signature required; the evidence file is the deliverable.
Smells to refuse
- Requirements that describe implementation ("use Redis") rather than behaviour. Implementation goes in
plan.mdDecisions. - Scenarios with no THEN that a test could assert.
- A requirement whose only scenario is the happy path.
- "Etc.", "and so on", "as appropriate", "handle errors gracefully".
- Two requirements that can both be satisfied by the same trivial implementation (merge them) or that contradict (resolve now, not in code).
- A frontend/mobile spec with no §8 — the loading, empty and error states will be invented during implementation if you leave them out.
- Filling in §5 yourself, ever.