Why spec-first?
"Just build it"
User: add a digest email feature Agent: [writes 600 lines] User: wait, what about unsubscribes? Agent: [refactors 200 lines] User: also it needs to skip free users Agent: [refactors again] User: this is taking forever
~3 hours wasted. Code is half-right because requirements arrived in pieces.
"Specify first"
User: /speckit.specifyAgent: [writes spec.md] User: [reads, edits 4 lines] User: /speckit.clarify Agent: [asks 3 questions] User: [answers] User: /speckit.implement task 1 Agent: [test, code, green, commit]
~30 minutes of thinking. Then code that matches the actual intent. One pass.
The most expensive 10 minutes of any feature are spent at the keyboard after you discover what you actually wanted. Spec-kit moves those 10 minutes to the front, before any code exists.
The pipeline at a glance
Spec-kit is a directed pipeline. Each step's output is the next step's input. You can re-enter at any earlier step if you realize something's off.
flowchart LR C[/"π constitution
project principles"/]:::const S[/"π specify
what + why"/]:::spec CL[/"β clarify
resolve holes"/]:::clarify P[/"πΊοΈ plan
technical approach"/]:::plan T[/"β tasks
decompose"/]:::tasks A[/"π analyze
drift check"/]:::analyze I[/"π οΈ implement
TDD loop"/]:::impl C ==>|once per project| S S ==> CL CL ==> P P ==> T T ==> A A ==> I I -.->|"if scope shifted"| S A -.->|"misalignment"| P classDef const fill:#1e3a8a,stroke:#3b82f6,color:#fff classDef spec fill:#581c87,stroke:#a855f7,color:#fff classDef clarify fill:#7c2d12,stroke:#f97316,color:#fff classDef plan fill:#134e4a,stroke:#14b8a6,color:#fff classDef tasks fill:#365314,stroke:#84cc16,color:#fff classDef analyze fill:#7c2d12,stroke:#f97316,color:#fff classDef impl fill:#14532d,stroke:#22c55e,color:#fff
.specify/The 7 commands
/speckit.constitution
β project principles (write once, edit rarely)
What it writes: .specify/memory/constitution.md
What it captures: the rules every feature must obey β stack defaults, security baselines, "we never log PII", "every endpoint validates with zod first".
When to invoke: once when the project is born. Edit between features when you learn something new. Never during a feature build.
/speckit.specify
β what + why (the most important prompt)
What it writes: .specify/specs/<feature>/spec.md
- User outcome (a specific person, specific moment)
- Why now (the actual business reason)
- Non-goals (what we're explicitly NOT doing)
- Constraints (auth, limits, deps)
- Acceptance signals (3-5 testable conditions)
- Implementation details (those go in /plan)
- File names or table schemas
- "Should be performant" without a number
- "Nice to have" features (they're scope creep)
- Anything you're not sure about (use /clarify)
/speckit.clarify
β hole-finder; answer every question honestly
What it does: agent re-reads your spec and asks 3-5 questions about ambiguity it found. Edge cases, failure modes, "what if X is empty?".
What it writes: appends Q&A to spec.md.
/speckit.plan
β technical approach (read it before continuing)
What it writes: .specify/specs/<feature>/plan.md
What's in it: tables, RLS policies, Inngest function shapes, API contracts, library choices, the unsubscribe route, the test strategy.
Your job: read it. If something's wrong, say: "Plan is good except change point 4 to use a materialized view instead of per-user joins. Update the plan." Don't proceed with a wrong plan.
/speckit.tasks
β decompose plan into 8-15 testable units
What it writes: .specify/specs/<feature>/tasks.md β numbered list, each independently testable.
Good task shape: "Create digest_subscribers table with RLS allowing user-own SELECT and admin SELECT/UPDATE. Schema + migration + RLS policy + 2 tests."
/speckit.analyze
β drift check (always run before implement)
What it does: agent cross-reads spec β plan β tasks and flags inconsistencies.
/speckit.implement
β execute task-by-task with TDD
Invocation: /speckit.implement task N β runs one task at a time.
What happens automatically: tests-first, fail-then-pass, conventional commit when green.
What you add: "Use the superpowers:test-driven-development skill. Show me the failing test before the implementation." β this pins the discipline.
TDD inside implement β the red/green/refactor loop
Implement runs TDD by default, but the magic prompt makes the discipline visible. Every cycle has exactly three phases. If any phase is skipped, you don't have TDD β you have wishful thinking.
flowchart TB A([Task N starts]):::start R[π΄ RED
Write a failing test
Run it. See it fail.]:::red G[π’ GREEN
Write minimum code
to make it pass]:::green F[β»οΈ REFACTOR
Improve structure
Tests still pass]:::refactor C([Conventional commit]):::commit N([Task N+1]):::next A --> R R --> G G --> F F --> C C --> N R -.->|"if test passes immediately"| W[β οΈ Test isn't testing what you think.
Rewrite the test.]:::warn W -.-> R classDef start fill:#1e293b,color:#fff,stroke:#64748b classDef red fill:#7f1d1d,color:#fff,stroke:#ef4444 classDef green fill:#14532d,color:#fff,stroke:#22c55e classDef refactor fill:#1e3a8a,color:#fff,stroke:#3b82f6 classDef commit fill:#581c87,color:#fff,stroke:#a855f7 classDef next fill:#1e293b,color:#fff,stroke:#64748b classDef warn fill:#7c2d12,color:#fff,stroke:#f59e0b
Write the test for behavior that doesn't exist yet. Run the test suite. You should see it fail in a specific way.
If it passes immediately, your test is wrong, not your code.
Write the smallest amount of code that makes the failing test pass. Don't generalize. Don't add features.
If you find yourself writing more than needed, stop. That's the refactor phase.
Tests are green. Now improve structure: extract functions, rename, remove duplication. Re-run tests after each change.
If tests fail during refactor, you went too far. Revert to last green.
/speckit.implement task 1 Use the superpowers:test-driven-development skill. Red-green-refactor. Show me the failing test before the implementation.
That second paragraph is what flips the agent from "write code that probably works" to "prove each step." Skip it and you'll get fast-but-fragile output.
Worked example β weekly digest email
A real feature, end to end. Same shape you'd use for any non-trivial work in a Next.js + Supabase + LemonSqueezy SaaS.
In your project root:
specify init . --integration claude
Drops .specify/ with all 7 slash commands. Skip if already initialized.
/speckit.constitution
(only once in project lifetime)
Your exact prompt:
/speckit.constitution We're a solo-dev SaaS on Next.js App Router + Supabase + LemonSqueezy. Principles: - Strict TypeScript, no `any` - RLS on every table - Functional patterns, named exports - Tests before merge - Conventional commits Hard rules: - Never log PII - Never send unbounded emails - Every cron job has a kill switch Release blockers (any one of these and we don't ship): - Failing type-check - Failing RLS test - Missing migration - Secret in diff
/speckit.specify
β the prompt that matters most
/speckit.specify Feature: weekly email digest of new threat-intel articles for opted-in users. USER OUTCOME: A subscriber who opted in to "Weekly Digest" gets one email every Monday 8 AM ET with the top 10 articles tagged in their followed categories from the past 7 days. They click any article title to open it. They unsubscribe in one click. WHY NOW: 40% of our churn is "I forgot the product exists." Digest brings them back. NON-GOALS: - Real-time alerts (separate feature) - Personalization beyond category follow (v2) - Mobile push (v2) CONSTRAINTS: - Resend for delivery - LemonSqueezy plan gate (Pro+ only) - Single Inngest cron, idempotent if retried - Must respect unsubscribe within 24h per CAN-SPAM - No PII in logs ACCEPTANCE SIGNALS: - A test user with 3 followed categories receives exactly one email Monday morning, containing exactly 10 article rows - An unsubscribed user receives zero emails - Re-running the cron in the same hour produces zero duplicate sends
/speckit.clarify
Just run it. The agent comes back with questions like:
Answer each one. Don't hand-wave. Every unclarified question is hour-3 rework.
/speckit.plan
Writes plan.md. Read it. Tweak with: "Change point 4: use materialized view, not per-user join."
/speckit.tasks
Decomposes into ~10 tasks. Each independently testable. No prompt needed.
/speckit.analyze
Drift check. Always run before implement. Catches spec β plan misalignment.
/speckit.implement task 1
β TDD enters here
/speckit.implement task 1 Use the superpowers:test-driven-development skill. Red-green-refactor. Show me the failing test before the implementation.
test/digest/eligibility.test.ts, runs it. Output: FAIL β getEligibleSubscribers is not defined. Confirms RED.src/digest/eligibility.ts. Re-runs test. Output: PASS. Confirms GREEN.feat(digest): add subscriber eligibility check (task 1/10)Pitfalls (the real ones)
It's never small. Even a 1-hour change gets a 5-line spec. The spec is the floor, not the ceiling. Skipping it is how 1-hour changes become 5-hour rewrites.
The constitution is supposed to be stable. If you want to change it during a feature build, write the change into the next spec instead. Revisit constitution after the feature ships.
You edited the plan but didn't regenerate tasks. Now /implement is building from stale tasks. Analyze catches this in 10 seconds; without it, you find out at task 6.
/speckit.implement task 1 alone gets you fast code. The "Show me the failing test before the implementation" line is what pins the loop. Without it, the agent will sometimes write code first and test second β which is not TDD.
spec.md, plan.md, tasks.md are real files. If you don't open them, the agent's hallucinations become law. Five minutes of reading saves hours of fixing.
Cheat sheet (print this)
| Command | When | Output |
|---|---|---|
specify init . --integration claude | Once per project | .specify/ + 7 commands |
/speckit.constitution | Project birth + rare edits | constitution.md |
/speckit.specify | Start every feature | spec.md |
/speckit.clarify | Right after specify | Q&A appended to spec.md |
/speckit.plan | After clarify (read result!) | plan.md |
/speckit.tasks | After plan is right | tasks.md |
/speckit.analyze | Always, before implement | Drift report |
/speckit.implement task N | Per task, in order | Test + code + commit |
If you only remember two prompts, remember these:
/speckit.specify [outcome + why + non-goals + constraints + acceptance]
/speckit.implement task N Use the superpowers:test-driven-development skill. Red-green-refactor. Show me the failing test before the implementation.
Spec-kit isn't only for features. For a non-trivial bug:
/speckit.specify Bug: [one line] Reproduce: [exact steps] Root cause hypothesis: [your best guess] Acceptance: [the regression test that should exist after fix]
Then clarify β plan β implement (with TDD). The TDD pass forces a regression test, so the same bug can't return.