Spec-Driven Development: writing specifications instead of prompts When Andrej Karpathy popularized the term "vibe coding" in early 2025 - loosely prompting an AI with no clear plan, accepting whatever "feels right" - he accurately described how most developers were using AI agents at the time. That works great for a one-off prototype. And pretty badly for anything you'll have to maintain for months or years.

Spec-Driven Development (SDD) is the disciplined response to that problem, and over 2025-2026 it went from a niche idea to a de facto standard. GitHub (Spec Kit), AWS (Kiro), OpenSpec, BMAD, Tessl, and Google Antigravity have all shipped their own take on it.

The problem SDD solves

The core issue is simple: AI agents are already good at writing code, but bad at guessing what you actually meant. Without an explicit scope, an agent starts making assumptions - and quickly heads in the wrong direction. Without clear acceptance criteria, there's no way to verify whether the result is "correct." Code review turns into an endless process, because there's no single source of truth to check the output against.

The numbers here are fairly telling: research shows LLMs generate vulnerable code in 9.8-42.1% of cases depending on the benchmark, and the number of recorded issues caused by AI-generated code in production repositories surpassed 110,000 by February 2026.

The core idea: the spec is the source of truth, not the code

A phrase that shows up in nearly every SDD article from 2025-2026: "the spec is the prompt." This is a methodology where a detailed, version-controlled specification - not the code - is the single source of truth. A team (or an AI agent) first writes a spec describing what the system should do, then derives an implementation plan from it, breaks that plan into atomic tasks, and only then generates the code. The spec stays alive: when requirements change, you edit the spec and regenerate the relevant code.

That doesn't mean code stops mattering - it's more of an architectural shift: human effort moves from writing lines of code toward precisely defining system behavior.

The four-stage workflow

Nearly every modern SDD tool converges on the same cycle: Specify → Plan → Tasks → Implement.

Using GitHub Spec Kit as an example, this looks like a sequence of slash commands in your AI agent (Claude Code, Copilot, Cursor - Spec Kit is agent-agnostic):

/speckit.constitution   # project principles and rules, written once
/speckit.specify        # what to build - focus on what and why, no tech details
/speckit.plan           # technical plan - stack, architecture, dependencies
/speckit.tasks          # breaking the plan into concrete, actionable tasks
/speckit.implement      # the actual code generation from the tasks

There's also an intermediate command for consistency checking - it catches discrepancies between the spec, plan, and tasks (like directory mismatches or missing requirements) before the agent starts writing any code.

Spec-Driven Development sequence diagram: developer interacts with the AI agent through specify, plan, tasks, implement commands, the agent writes EARS criteria to the specification and generates code

EARS notation: writing requirements that can't be misread

The most practical part of the whole methodology is how you actually write acceptance criteria. EARS (Easy Approach to Requirements Syntax) is a formal notation for writing unambiguous, testable requirements. Every requirement follows a strict pattern with uppercase keywords. The word SHALL is mandatory - never "should," "must," or "may."

Five core patterns:

Ubiquitous (always active, no trigger):
THE System SHALL encrypt all passwords using bcrypt

Event-driven (trigger event):
WHEN a user submits the login form THE System SHALL validate credentials

State-driven (while a condition holds):
WHILE the user is authenticated THE System SHALL display the dashboard

Optional feature:
WHERE two-factor authentication is enabled THE System SHALL require a verification code

Unwanted behavior (error handling):
IF the password is incorrect THEN THE System SHALL display an error message

These patterns can be combined for more complex requirements:

WHILE the cart is not empty
WHEN the user clicks checkout
THE System SHALL navigate to payment

Worked example: password reset with rate limiting

Let's take a concrete feature - password reset with rate limiting - to see the whole cycle in practice.

Step 1 - Specify (what and why, no tech details):

Build a password reset flow. Users who forget their password should be
able to request a reset link via email. To prevent abuse, limit how
often a single account or IP address can request a reset.

Step 2 - the agent asks clarifying questions (this is the actual value of this step - preventing underspecification, the number one reason agents go off the rails): How many requests are allowed within what time window? What should be shown to the user once the limit is hit? Is the reset link time-limited?

Step 3 - EARS acceptance criteria, after clarification:

THE System SHALL allow a maximum of 3 password reset requests per email
address within a 15-minute window

WHEN a user requests a password reset THE System SHALL send an email
containing a reset link valid for 30 minutes

IF a user exceeds the reset request limit THEN THE System SHALL display
a message indicating when they can try again

WHILE a reset link has already been used THE System SHALL reject any
further attempts to use that same link

IF the reset link has expired THEN THE System SHALL display an error
and offer to request a new link

Step 4 - Plan: here you provide the technical context - "use our existing stack and patterns, consult the constitution and the spec, keep dependencies minimal." The agent derives the concrete architecture: which database table, which queue for email, which rate-limiting mechanism (a Redis counter, a database throttle).

Step 5 - Tasks: the plan gets broken into actionable chunks - a database migration, a throttle middleware, an email template, the reset endpoint, tests for each EARS criterion.

Step 6 - Implement: the agent executes the tasks one by one (or the whole batch at once, if you trust it more), and each written test maps directly to a specific EARS line above - meaning you get direct traceability from requirement to the code that verifies it.

Superpowers: a methodology alongside specifications

Beyond the SDD cycle itself, it's worth knowing about obra/superpowers - a Claude Code plugin (also compatible with several other agents - Codex, Cursor, Gemini CLI) that describes itself as "an agentic skills framework & software development methodology that works." This isn't a replacement for Spec Kit, it's more of an adjacent layer: a library of 20+ battle-tested skills covering brainstorming, writing plans, TDD, systematic debugging, git workflows, and code review.

The cycle here is shorter and less formal than the full SDD loop:

/superpowers:brainstorm      # interactive design refinement
/superpowers:write-plan      # create an implementation plan
/superpowers:execute-plan    # execute the plan in batches

The key difference from Spec Kit is that Superpowers is less about a formal specification-as-contract and more about proven patterns for working with an agent: when to create a git worktree, when to delegate a task to a subagent, how to debug systematically instead of guessing. Skills activate automatically when Claude Code recognizes the relevant context - no need to memorize commands.

Real-world results, and why this isn't always the right call

GitHub reports that teams using Spec Kit on internal projects ship features with roughly an order-of-magnitude fewer "regenerate from scratch" cycles compared to ad-hoc prompting. AWS Kiro documents real customer cases where 40-hour features were shipped in under 8 hours of human time when authored as specs first.

But it's worth staying level-headed here. Thoughtworks, in its own review of the methodology, notes plainly that experienced programmers may find over-formalized specs cause unnecessary trouble and slow down change and feedback cycles - just as happened in the early days of waterfall development. SDD remains an emerging practice, and the industry hasn't fully settled whether the spec or the code is the ultimate artifact of software development.

A practical rule that shows up across several sources: vibe-code for prototypes, throwaway scripts, and exploration where speed matters most. Spec-Driven Development is for production code, team projects, and long-lived systems where drifting from the original intent is costly.

Why I'm skeptical of paid SDD courses

Lately my feed keeps surfacing paid courses and bootcamps on Spec-Driven Development - and honestly, I'm fairly skeptical of them. Not because the topic isn't worth studying - it is, I just spent an entire article on it. But because most of these courses essentially repackage what's already sitting in the open documentation for Spec Kit or Kiro, wrapped in "my personal framework" and "an exclusive method I've refined over years of work."

The methodology itself is a handful of slash commands, half a page of EARS notation, and a general discipline of "describe first, then plan, then execute." You can read that in a repo's README in 20 minutes. A paid course usually adds the author's personal anecdotes and some motivational rhetoric about how SDD "will change your career" on top - which isn't bad in itself, but is usually priced disproportionately to how much genuinely new information it offers beyond the official sources.

If you're curious about SDD, I'd suggest reading the Spec Kit documentation first, along with a few practical breakdowns like this one, trying the specify → plan → tasks → implement cycle on a real small feature, and only looking for a paid course - targeted at a specific gap - if concrete questions remain after that, rather than as a general introduction to the topic.

How I actually use this

When I step into unfamiliar code with no documentation at all, I end up building a lightweight version of this same approach, even before I'd read about SDD as a formal methodology. Instead of asking an agent to "figure out the code" with one broad request, I scope it module by module: starting with deterministic shell tools (cloc, git log, find) for hard facts with no LLM involved, then bounding each pass to a single directory, and distilling each pass into a nested CLAUDE.md file - essentially a "living spec" of what that module does and what not to touch.

This directly echoes the philosophy behind Superpowers - subagent-driven development, where each subagent gets a narrow, tightly bounded scope instead of one agent holding the entire project in context at once. I build separate subagents following exactly this principle: each one checks one specific, narrow thing and appends its findings to a persistent file, rather than keeping everything in the conversation's working memory.

For new features in my own projects, I now deliberately write a short EARS-style spec before asking an agent to implement anything - even without the full Spec Kit cycle. Just three to five lines of "WHEN / THE SYSTEM SHALL" before writing the prompt take about a minute and save me from the agent inventing its own version of what I "meant."