Claude Code Mastery Editor's pick

Spec-Driven Development skill for Claude Code

Requirements, design, tasks, code — each traced to the last. Claude researches in plan mode, then writes requirements, design and a task list as files in the repo and stops for approval at each gate. Implementation goes one task at a time with tests named after requirement IDs, ticked tasks carry commit hashes, deviations update the design before coding continues, and a final trace table proves every requirement has a passing test.

  • namespec-driven-development
  • size199 lines · ≈2,000 tokens
  • files1
  • licenseMIT
  • updated

What Claude sees before loading it

This description is the only part of the skill that sits in context all the time. Claude reads it to decide when to load the full playbook below.

description: Runs a spec-driven workflow in Claude Code where requirements, a technical design, and a numbered task list are written as files under a specs/ folder per feature in the repo, approved at each gate, then implemented one task at a time with tests traced back to requirement IDs and a final verification pass that checks every acceptance criterion. Uses EARS-style requirements, plan mode for read-only research, and keeps specs updated as the code changes. Use when the user asks for spec-first or spec-driven development, a feature is large enough to need a design, or past AI-built features drifted from what was asked.

Try asking

  • Let's do this invoice disputes feature spec-first — requirements, design, tasks, then build
  • Write the spec files for this feature in specs/ and wait for my approval before coding
  • Pick up specs/2026-10-invoice-disputes and continue with the next unchecked task

Use it when

  • A feature spans several modules or days of work
  • Earlier AI-built features drifted from what was asked
  • Work will continue across sessions or people and needs a durable contract
  • Reviewers want requirements traced to tests

Skip it when

How to check the result

Every requirement ID appears in at least one passing test, all tasks are ticked with commit hashes, and design.md matches what was built.

The common mistake it prevents

Letting code diverge from the approved design without updating design.md, so the spec tells the next session something that is no longer true.

~/.claude/skills/spec-driven-development/SKILL.md

--- name: spec-driven-development description: Runs a spec-driven workflow in Claude Code where requirements, a technical design, and a numbered task list are written as files under a… license: MIT ---

A spec-driven feature is done when every requirement ID maps to at least one passing test, every task in tasks.md is checked off with its commit, the design matches what was built (or records why not), and the spec files are merged with the code. The spec is the contract the next session and the reviewer read; chat history is not.

When to use it

Feature sizeProcess
Under a day, one module, obvious behaviorSkip the spec; use a plan in chat or task-decomposition-plans
1–10 days, several modules, or ambiguous behaviorFull spec (this skill)
Vague request, unclear goalFirst requirements-clarification, then this skill
Product-level why/who/metricsprd-writing produces the input; this skill turns it into engineering specs

Files

specs/
└── 2026-10-invoice-disputes/
    ├── requirements.md   # what and why, numbered, testable (gate 1)
    ├── design.md         # how: components, data, interfaces, risks (gate 2)
    └── tasks.md          # ordered checklist mapped to requirement IDs (gate 3)

Keep specs in the repo next to the code they govern, committed on the feature branch. Reference them from CLAUDE.md once: “Active specs live in specs/; read the relevant folder before working on a feature.”

Workflow

- [ ] 0. Research in plan mode: read code, list constraints and open questions
- [ ] 1. requirements.md -> user approves (gate 1)
- [ ] 2. design.md -> user approves (gate 2)
- [ ] 3. tasks.md -> user approves (gate 3)
- [ ] 4. Implement one task at a time: test first, code, run checks, tick, commit
- [ ] 5. Verification pass: every requirement ID -> passing test or recorded gap
- [ ] 6. Update design.md for deviations; merge spec with the code

Never skip a gate silently. If the user says “just build it”, write the three files compactly anyway and ask for one combined approval.

0. Research (read-only)

Enter plan mode (Shift+Tab) so nothing is edited. Find the modules involved, existing patterns to follow, data models, tests, and constraints (performance, auth, migrations, feature flags). Write open questions down; ask them before gate 1, not during coding.

1. requirements.md

# Invoice disputes — requirements
Status: draft | approved (2026-10-20, @maria)
Source: PRD-142, support tickets #881 #903

## Goal
Customers can dispute an invoice line so finance can resolve it without email.

## Non-goals
- Automated refunds. - Disputes on paid invoices older than 90 days.

## Requirements
- R1 WHEN a customer opens an unpaid invoice THE SYSTEM SHALL show a "Dispute" action per line.
- R2 WHEN a dispute is submitted with a reason of 10-1000 chars THE SYSTEM SHALL set the line
  status to `disputed` and notify the account's finance contact within 1 minute.
- R3 IF the invoice is paid and older than 90 days THEN THE SYSTEM SHALL reject the dispute with
  error code DISPUTE_WINDOW_CLOSED.
- R4 WHILE a line is disputed THE SYSTEM SHALL exclude it from dunning emails.
- R5 THE SYSTEM SHALL record who opened and resolved each dispute (audit log).

## Acceptance criteria
- AC1 (R1,R2): e2e — dispute a line, see status `disputed`, finance email captured in test mailbox.
- AC2 (R3): API returns 422 DISPUTE_WINDOW_CLOSED for a 91-day-old paid invoice.
- AC3 (R4): dunning job unit test skips disputed lines.

## Open questions
- Q1 Can a customer withdraw a dispute? (answer: yes, owner: PM, 2026-10-18)

Rules: one behavior per requirement; EARS keywords (WHEN / IF-THEN / WHILE / WHERE / THE SYSTEM SHALL) keep triggers and responses explicit; numbers instead of adjectives (“within 1 minute”, not “quickly”); non-goals stated; every requirement covered by an acceptance criterion.

2. design.md

# Invoice disputes — design
Status: approved (2026-10-21)

## Approach
Add `disputes` table and `DisputeService`; extend line status enum; reuse NotificationQueue.

## Changes by component
| Component | Change | Requirements |
|---|---|---|
| db/migrations | `disputes` table, `invoice_lines.status` += `disputed` | R2, R5 |
| api/invoices | `POST /invoices/:id/lines/:lineId/disputes` | R2, R3 |
| jobs/dunning | filter disputed lines | R4 |
| web/invoice-page | Dispute dialog | R1 |

## Interfaces
POST body `{ reason: string }` -> 201 `{ disputeId, status }` | 422 `{ code }`

## Data and migration
Additive migration; backfill none; enum change deployed before code that writes it.

## Alternatives rejected
- Status flag on line only (no table): loses audit trail (R5).

## Risks
- Dunning job runs hourly; a dispute filed mid-run may still send one email. Accepted; noted in UI copy.

## Test strategy
Unit: DisputeService rules (R2, R3). Integration: API + DB. E2E: AC1.

The design must name real files and existing patterns found in step 0, and every row traces to requirement IDs. A design without “Alternatives rejected” and “Risks” is not finished.

3. tasks.md

# Invoice disputes — tasks
- [ ] T1 Migration: disputes table + enum value (R2, R5) — verify: `make migrate-test`
- [ ] T2 DisputeService with window rule, unit tests first (R2, R3) — verify: `pnpm vitest run dispute`
- [ ] T3 API endpoint + integration tests (R2, R3) — verify: `pnpm test:api -t disputes`
- [ ] T4 Dunning exclusion + unit test (R4)
- [ ] T5 Notification to finance contact (R2)
- [ ] T6 UI dialog + e2e AC1 (R1)
- [ ] T7 Audit log entries (R5)

Each task: one commit-sized change (under ~300 lines), leaves the build green, names its requirement IDs and its verify command. Order by dependency, riskiest unknown early.

4. Implement

For each task, in a loop:

  1. Re-read the task, its requirements, and the relevant design row.
  2. Write or extend the test that encodes the requirement (name tests with the ID: it("R3 rejects disputes after 90 days")).
  3. Implement the minimum to pass; follow the patterns named in the design.
  4. Run the task’s verify command plus typecheck/lint.
  5. Tick the box with the commit hash: - [x] T2 ... (a1b2c3d). Commit code and the updated tasks.md together.

If reality contradicts the design (an API does not exist, a constraint was missed), stop, update design.md with the change and reason, and get a quick confirmation before continuing. Do not let code and design diverge silently.

For long features across sessions, the files are the handoff: a new session starts with “Read specs/<feature>/ and continue with the first unchecked task.”

5. Verification pass

Build the trace and fill every row:

grep -rnoE '\bR[0-9]+\b' --include='*.test.*' --include='*_test.*' src tests | sort -u
ReqTest(s)Status
R1e2e/disputes.spec.ts “R1 shows dispute action”pass
R3dispute.service.test.ts “R3 rejects after 90 days”pass
R4dunning.test.ts “R4 skips disputed lines”pass

Any requirement without a passing test is either implemented now, or listed as a gap with the user’s explicit acceptance. Run the full suite once at the end.

Gotchas

  • Specs written after the code are documentation, not specs; they miss the decisions.
  • Requirements that describe implementation (“use a Redis queue”) belong in design.
  • Giant task lists (> 15 tasks) mean the feature should be split into two specs.
  • Updating code without ticking tasks or updating design makes the spec lie to the next session; treat spec edits as part of the change.
  • Do not let the spec grow into a novel. Target: requirements under 80 lines, design under 150, tasks under 40.

Output

**Spec:** specs/2026-10-invoice-disputes/ (requirements, design, tasks — all approved)
**Progress:** 7/7 tasks done, 7 commits; design updated once (notification via existing queue, not webhook)
**Trace:** R1-R5 each covered by passing tests; AC1-AC3 pass
**Gaps accepted:** none · **Follow-ups:** dispute withdrawal (Q1) as separate spec

About this skill

Written and maintained by the Claude Skills editors to the same editorial standard as every skill in the directory: a selective trigger, a real workflow, known pitfalls and a verification step. First published , last updated . MIT licensed.

esc