Spec-Driven Development: Write the Spec Before the Code

Spec-driven development means writing a clear spec before your AI writes code. Here's what a founder-grade spec contains, a worked example, and why it beats prompting.

· Justin Boggs

An architect working on a technical draft with a pencil and ruler

Photo by Daniel McCullough on Unsplash

Spec-driven development means writing a clear, structured specification of what you want before your AI assistant writes a single line of code. Instead of prompting your way toward a feature one message at a time, you define the intent, the constraints, and the acceptance criteria up front, then let the AI build against that shared plan. For a non-technical founder, this is the single habit that changed my hit rate the most. When I stopped describing features in scattered chat messages and started writing a short spec first, the AI's output went from "close, but I'll spend an hour fixing it" to "that's what I actually meant." This post covers what a spec contains, the workflow, and a worked example.

TL;DR

  • Spec-driven development puts a written spec — not the code — at the center: you define intent and constraints first, then generate against them.
  • It exists because AI agents are excellent at writing code and terrible at guessing what you meant. The spec removes the guessing.
  • A founder-grade spec has five parts: the goal, the constraints, the acceptance criteria, the edge cases, and what's explicitly out of scope.
  • The lifecycle is: specify, clarify, plan, implement, validate. Most of the value is in the first two steps.
  • Right-size it. A one-line bug fix doesn't need a spec. A new feature that touches your database, your billing, and your UI does.

What is spec-driven development?

A spec-driven development workflow is one where a written specification is the source of truth, and code is generated from it — not the other way around. You describe what the system should do in plain, structured language: the outcome you want, the rules it has to follow, and how you'll know it's correct. Then your AI assistant uses that spec as the context it builds from.

The phrase that keeps showing up across the 2025 and 2026 writing on this is "the spec is the prompt." That reframing matters. In a prompt-first workflow, your intent lives in a dozen chat messages that scroll off the top of the window. In a spec-first workflow, your intent lives in one durable document you can read, edit, and hand back to the AI whenever it drifts.

For an engineer, the spec is a planning nicety. For a non-technical founder, it's closer to load-bearing. You and I can't open the generated code, read it, and confirm it matches what we pictured. The spec is the one artifact we can read and verify, because it's written in our language, not the machine's. If the spec is right and the AI builds against it faithfully, we've moved the part we're able to check to the front of the process, where checking is cheap.

This is the natural next step past prompt engineering for non-developers. A good prompt gets you one good response. A good spec gets you a whole feature, because it stays in play across every message it takes to build the thing. The prompt is a sentence; the spec is the contract.

The methodology went mainstream in 2026 for a specific reason. As Microsoft's engineering team put it, AI has made software delivery faster, but "speed alone does not guarantee better outcomes." When the AI can generate code in seconds, the bottleneck stops being typing and starts being clarity. Spec-driven development attacks the new bottleneck directly.

Why prompt-first workflows break down as projects grow

Prompting works beautifully for small, self-contained tasks. "Add a loading spinner to this button" needs no spec. The trouble starts when the thing you're asking for is bigger than one message can hold.

Microsoft's team describes the failure as translation loss — the meaning that leaks out every time an idea moves from one form to the next. Their framing names four places it happens: stakeholder needs to requirements, requirements to architecture, design to implementation, and implementation to validation. Every one of those handoffs is an interpretation step, and "AI can accelerate those steps, but it cannot correct ambiguity that was never resolved."

Here's what that looks like at a founder's desk. You ask for a feature. The AI builds a reasonable version of what you said, which isn't quite what you meant. You correct it. The correction introduces a new assumption. Three messages later, the AI has quietly forgotten a constraint you mentioned at the start, because it scrolled out of the context window. You're now debugging a moving target, and you can't read the code well enough to see where it went wrong.

This is the same root cause behind why your AI assistant seems to get worse three hours into a session: intent that lives only in chat is fragile. It degrades as the conversation grows. A spec doesn't degrade, because it's a fixed document you re-supply whenever you need to.

The deeper problem is architectural drift. When requirements live in prompts, two features built a week apart can solve the same problem two different ways, because the AI had no shared context between them. Multiply that across a few months and you get a codebase that fights itself — the kind of inconsistency that turns into the database schema and structural mistakes that haunt founders a year in. A spec is how you give the AI a memory that outlives the conversation.

None of this means prompting is wrong. It means prompting alone stops scaling at exactly the point most founder projects get interesting: when the feature touches more than one part of the app.

What a founder-grade spec actually contains

A spec is not a novel. The best ones I write are half a page. What makes them work isn't length — it's that they answer the five questions the AI would otherwise have to guess at.

The goal. One or two sentences on what this feature does and who it's for. Not how it's built. What outcome a user gets. "A logged-in user can export their data as a CSV file from their account settings page."

The constraints. The rules the solution has to respect. This is where you encode the things you know about your own app that the AI can't see. "Must use our existing Supabase auth. Export runs server-side. No new third-party service." Constraints are how you keep the AI from inventing a fancier solution than you asked for.

The acceptance criteria. How you'll know it's done and correct, written as checkable statements. "The CSV includes every row the user owns and none belonging to other users. The download works on mobile. An empty account produces a valid empty file, not an error." These double as your test list.

The edge cases. The situations that break naive implementations. "What happens with 100,000 rows? What if the user clicks export twice? What if the export fails halfway?" Naming edge cases up front is the single highest-value thing a non-technical founder can do, because these are exactly the cases the AI skips when it's guessing.

What's out of scope. The boundary. "Not doing scheduled exports. Not doing PDF. Not doing email delivery — download only." Scope boundaries stop the AI from gold-plating and stop you from accidentally approving twice the work you meant to.

Here's how a spec-first request compares to the prompt-first version most of us start with:

| Dimension | Prompt-first | Spec-first | | --- | --- | --- | | Where intent lives | Scattered across chat messages | One durable document | | Survives a long session | No — it scrolls out of context | Yes — you re-supply it | | Edge cases | Discovered when they break | Named before building | | Reviewable by a non-dev | Only the code, which you can't read | The spec, in plain English | | Rework rate | High — drift compounds | Lower — one source of truth | | Best for | Small, one-shot tasks | Features touching multiple parts |

The discipline that makes specs work is the same one behind a good CLAUDE.md file: say the specific, true thing and cut everything else. A spec bloated with implementation detail is as useless as one that's too vague. Aim for the middle — concrete about what and why, quiet about how.

The spec-driven workflow, step by step

The lifecycle most tools converge on is short. Microsoft's open-source GitHub Spec Kit frames it as a sequence you can follow by hand, no special tooling required: define intent, remove ambiguity, plan with constraints, implement with AI, and validate against the spec.

Here's that flow the way a solo founder actually runs it:

flowchart TD
    A[Specify: write the goal, constraints, and acceptance criteria] --> B[Clarify: resolve ambiguity and name edge cases]
    B --> C[Plan: let the AI propose an approach, you approve it]
    C --> D[Implement: AI generates code against the approved plan]
    D --> E[Validate: check the output against the acceptance criteria]
    E -->|Gaps found| B
    E -->|Matches spec| F[Ship]

Specify. Write the five-part spec from the section above. Ten minutes, tops, for most founder features.

Clarify. Hand the spec to your AI and ask it to poke holes: "What's ambiguous here? What edge cases am I missing? What would you need to decide that I haven't told you?" This step is gold. The AI is far better at finding gaps than at guessing past them, so let it. You'll usually add two or three lines to the spec here.

Plan. Ask the AI to describe its approach before it writes anything — which files it'll touch, what the data flow is, what it'll change. This is the same instinct as Claude Code's plan mode: move the checkpoint earlier, before code lands, when a course correction costs a sentence instead of an afternoon. You approve or redirect the plan.

Implement. Now the AI writes code, and because it's building against an approved spec and plan, the output is dramatically more likely to be what you meant. This is the step everyone wants to start with, and it's the one that works best when it comes last.

Validate. Walk through your acceptance criteria one at a time. Each "the CSV includes every row the user owns" becomes a thing you actually check. If something's off, you don't start over — you go back to Clarify, tighten the spec, and re-run. The spec is a living artifact, per Spec Kit's own guidance: you refine it as you learn.

The honest caveat, straight from the teams shipping this: not every change needs the full lifecycle. Spec Kit's authors say adoption "should be right-sized." A typo fix doesn't get a spec. A feature that spans your database, your auth, and your UI absolutely does. Learning where that line sits for your project is most of the skill.

A worked example: from vague ask to shipped feature

Let me make this concrete with something small enough to fit in one post but real enough to show the difference.

The prompt-first version starts like this: "Add a way for users to delete their account." Reasonable-sounding. Here's what an AI does with it — it adds a red "Delete account" button that removes the user's login row and calls it done. Then you discover, in production, that their data is still in three other tables, their active subscription is still billing them, and there was no confirmation step, so someone fat-fingered it and lost everything. Every one of those is a gap the prompt never closed.

Now the spec-first version. Same feature, ten minutes of writing first:

Goal: A logged-in user can permanently delete their own account and all associated data from account settings.

Constraints: Uses existing Supabase auth. Must cancel any active Stripe subscription as part of deletion. Deletion is irreversible.

Acceptance criteria: After deletion, the user's row and all rows they own across every table are gone. An active subscription is cancelled at Stripe. The user is signed out and can't log back in. A confirmation step requires typing the word "delete" before it runs.

Edge cases: User with no subscription. User whose subscription cancel fails (must not orphan data). User who closes the tab mid-deletion. Double-click on the confirm button.

Out of scope: Data export (separate feature). Soft-delete or 30-day recovery. Admin-initiated deletion.

Watch what that spec does. It surfaces the Stripe cancellation the naive version forgot. It names the multi-table cleanup that would've become a support nightmare. It forces a confirmation step. And it draws a scope line so you don't accidentally sign up for a recovery system you didn't want to build today.

When you run the Clarify step, the AI might come back with: "Should deletion happen immediately or should the subscription cancel at period end? What should happen to data another user shares with this account?" Both are real questions you'd rather answer at the spec stage than discover in a bug report. This is the same "name the failure mode before it bites" instinct behind knowing when to trust your AI assistant and when to slow down.

The feature that ships from the spec is boring in the best way. It does what you meant, handles the cases you named, and stops where you told it to stop. You spent ten minutes writing to save yourself an afternoon of debugging a half-built deletion flow. That's the entire trade, and once you've felt it a few times, going back to pure prompting on anything non-trivial feels like driving with your eyes closed.

Frequently asked questions

Isn't writing a spec just slowing me down?

It feels slower for the first ten minutes and is faster by the end. The time you spend clarifying intent up front is time you don't spend debugging a feature that drifted from what you meant. Microsoft's teams found that "more clarity early usually reduces total delivery time" — the up-front cost is real but smaller than the rework it prevents. For trivial changes, skip the spec; for anything touching multiple parts of your app, it pays back the same session.

Do I need special tools like GitHub Spec Kit or Kiro to do this?

No. The tools help teams standardize the workflow, but the core habit is just writing a structured document before you prompt. You can do spec-driven development in a plain markdown file and paste it into Claude Code, Cursor, or Cowork. Start manual; reach for tooling only if you find yourself wanting the workflow enforced across a team.

How long should a spec be?

Shorter than you'd think. Most founder-grade specs for a single feature fit on half a page: a goal, a handful of constraints, a checklist of acceptance criteria, the edge cases, and a scope boundary. A spec that runs several pages usually means the feature is too big and should be split. Length isn't the goal; resolved ambiguity is.

What's the difference between a spec and a CLAUDE.md file?

A CLAUDE.md holds facts true in every session — your project layout, conventions, and standing rules. A spec is about one feature and is disposable once that feature ships. Think of the CLAUDE.md as the constitution and the spec as the bill you're passing today. They work together: the AI reads your standing rules and your feature spec at the same time.

Does spec-driven development work for fixing bugs, not just new features?

Yes, in a lighter form. For a bug, the "spec" is a clear reproduction and expected behavior: what happens now, what should happen, and how you'll confirm it's fixed. That's usually two or three sentences, not a full document. The principle is identical — define correct before you ask the AI to chase it, which keeps it from "fixing" the same bug in a loop.

Where to start this week

Pick the next feature on your list that touches more than one part of your app, and before you open your AI assistant, write the five parts down: goal, constraints, acceptance criteria, edge cases, out of scope. Ten minutes. Then paste it in and ask the AI to poke holes before it writes anything. That one change — clarify first, generate second — is the whole method, and you'll feel the difference in the first feature.

If you want a codebase that's already organized around clear specs and standing rules, Coding Capybaras is the free boilerplate I built for non-technical founders shipping SaaS with AI coding tools — every region ships with the kind of written-down conventions that make spec-driven work land on the first try.