Spec-Driven Development With AI Agents: The Complete Workflow
Agents left alone rush in, touch too many files, and skip planning. Spec-driven development is the fix. Here's how to run the full idea-to-reviewed-code loop with skills like Superpowers, GStack, and GSD.
Alexandr Rich
AI Learning Hub

Give a capable coding agent a vague task and watch what happens. It reads two files, decides it understands the whole system, and starts editing. Twenty minutes later you have a diff that touches fourteen files, renames a function you depended on, invents a config option that doesn't exist, and "fixes" a test by deleting the assertion. The code might even run. It just isn't what you asked for.
This isn't a model quality problem. The same agent that produced that mess can produce excellent work β it just needs a process that forces it to think before it types. That process has a name now: spec-driven development, or SDD. The idea is old (write down what you're building before you build it), but the application to autonomous agents is new and genuinely changes how much you can trust them.
I've been running spec-driven workflows daily for months across several teams, and I want to give you the complete loop: why agents go sideways, what a real spec looks like, how the interview step keeps the agent honest, how to write and approve an implementation plan, how to use subagents to build and review each other's work, and when this whole apparatus is overkill. I'll compare the major skills that implement SDD β Superpowers, GStack, GSD Core, and Matt Pocock's composable approach β so you can pick the one that fits how you work.
Why agents rush in and make a mess
To fix the behavior you have to understand it. Agents go sideways for three structural reasons, and none of them are about the model being "dumb."
They optimize for motion, not correctness. A coding agent is trained and prompted to make progress. Editing a file looks like progress. Asking a clarifying question looks like stalling. So the default gradient pushes toward "do something" over "understand first." Left alone, the agent will always pick action.
They have no durable memory of intent. The instruction you gave lives in the context window. As the agent reads files, runs commands, and generates code, that original intent gets buried under tokens. By edit number nine, the thing it's actually optimizing is "make this file look consistent with the other files I just read," not "deliver what the human asked for." This is context rot β the signal-to-noise ratio of the context window degrades as it fills, and the earliest, most important instructions get the least attention.
They can't tell a small task from a large one. "Add a rate limiter" might be a ten-line change or a three-day architecture project depending on your system. The agent can't feel that difference the way you can. Without a forcing function, it treats everything as a quick edit and discovers the complexity halfway through, by which point it's already committed to a bad approach.
Spec-driven development attacks all three. It replaces "do something" with "produce a spec" as the first unit of progress. It externalizes intent into a written document that survives context compaction. And it surfaces scope early, before any code exists, when changing direction is free.
The whole bet of SDD is this: the cheapest place to fix a misunderstanding is in a paragraph of English, the second cheapest is in a plan, and the most expensive is in merged code. Move the thinking left.
The shape of the loop
Every spec-driven workflow, regardless of which skill implements it, follows the same six phases. The skills differ in how heavy each phase is and how much they automate, but the spine is identical:
- Clarify intent. The agent interviews you. It asks what you actually want, what the edge cases are, what's out of scope. No code, no files.
- Write a spec. The agent produces a short document describing the desired behavior β what changes from the user's perspective, what stays the same, what done looks like.
- Get sign-off. You read the spec and approve it or correct it. This is a hard gate. Nothing proceeds without it.
- Write an implementation plan. The agent translates the approved spec into concrete steps: which files, which functions, which tests, in what order.
- Build. The agent (or a subagent) executes the plan, ideally in small atomic chunks with tests.
- Review. A separate agent β fresh eyes, no attachment to the code β reviews the diff against the spec and the plan.
The discipline is in the gates. Phase 3 and a lighter checkpoint after phase 4 are where a human says "yes, continue" or "no, you misunderstood." Everything before a gate is cheap to throw away. That's the entire value proposition.
The interview step: make the agent ask first
The single highest-leverage habit in spec-driven development is forcing the agent to interview you before it writes anything. Most people skip this because it feels slow. It is the opposite of slow β it's the step that prevents the twenty-minute mess.
Here's the failure mode it fixes. You say "add caching to the user service." The agent assumes you mean in-memory caching with a five-minute TTL, builds it, and you actually wanted Redis with explicit invalidation on write because you run three instances behind a load balancer. The in-memory cache is not just wrong, it's actively dangerous in your topology. None of that was in your one-line request, and the agent had no mechanism to discover it.
The interview step gives it that mechanism. Before writing a spec, the agent has to ask. A good interview produces questions like:
- "Are there multiple instances of this service? That changes whether an in-process cache is safe."
- "Should the cache invalidate on write, or is staleness acceptable for some window?"
- "What's the read/write ratio? That tells me whether this is even worth doing."
- "Is there a latency budget I'm trying to hit, or is this about reducing database load?"
This is exactly what the grill-me skill automates. It turns the agent into a slightly adversarial interviewer that refuses to proceed until it has enough information to write an unambiguous spec. The "grill" framing matters β you want the agent to push back, to surface the assumption it's about to make so you can correct it. A polite agent that asks one soft question and then guesses is worse than useless, because the guess feels validated.
I treat the interview as done when I can no longer answer a question with "I don't know, what do you think?" If the agent asks something I haven't decided, that's a decision I needed to make anyway β better now than after the code is written. When the questions start feeling pedantic, that's the signal the agent has enough to write the spec.
What a good spec actually contains
A spec is not a design document and it's definitely not a ticket. It's a short, behavior-focused description of what will be true after the change that wasn't true before. Keep it under a page. If it's longer, the task is too big and should be split.
A good spec has these sections:
- Goal β one or two sentences, in user/business terms, not implementation terms.
- Behavior changes β concrete, observable differences. "When a user requests
/profileand the result is cached and fresh, the response returns in under 10ms without a DB query." - Out of scope β explicit. This is the most underrated section. It's where you prevent gold-plating.
- Constraints β non-negotiables. "Must work across three instances." "Cannot change the public API."
- Acceptance criteria β how we'll know it's done, ideally testable.
Here's a real spec for a small feature, the kind I'd approve in thirty seconds or send back with two comments:
# Spec: Cache user profile reads
## Goal
Reduce database load from repeated profile reads on the
hot `/profile` endpoint without serving stale data after edits.
## Behavior changes
- GET /profile/:id returns from cache when a fresh entry exists,
skipping the DB query.
- Cache entries are invalidated immediately on any write to that
user's profile (PUT/PATCH /profile/:id).
- Cache misses fall through to the DB exactly as today.
## Out of scope
- Caching any endpoint other than /profile/:id.
- Caching list endpoints or search.
- Changing the response shape or status codes.
## Constraints
- Must be correct across 3 app instances behind the LB,
so the cache must be shared (Redis), not in-process.
- Public API response unchanged.
- TTL is a safety net only (15 min); correctness comes from
explicit invalidation on write.
## Acceptance criteria
- Repeated reads of an unchanged profile hit Redis, not Postgres
(verified by query count in an integration test).
- A write followed immediately by a read returns the new value.
- All existing /profile tests still pass.
Notice what this spec does not contain: no mention of which Redis client library, no function names, no file paths. Those are implementation decisions that belong in the plan. The spec is about behavior. Keeping that boundary clean is what lets a non-author β you, a teammate, or a reviewing subagent β verify the work without reading code.
From spec to plan: making it executable
Once the spec is approved, the agent writes an implementation plan. This is where it gets concrete: files, functions, order of operations, and crucially, the tests that prove each step. The plan is also where scope reveals itself. A spec that looked like a small change sometimes produces a plan with twelve steps and a database migration, and that's the plan's job β to make the real size visible before you commit to it.
A good plan is a sequence of atomic steps, each of which leaves the codebase in a working, tested state. Here's the plan for the caching spec above:
# Plan: Cache user profile reads
## Step 1 β Add a cache client wrapper
- New file: src/cache/redisClient.ts
- Exports get(key), set(key, value, ttl), del(key).
- Thin wrapper over the existing ioredis connection in src/db.
- Test: unit test the wrapper against a Redis mock.
## Step 2 β Cache reads in the profile service
- Edit: src/services/profile.ts, getProfile().
- Check cache first; on miss, read DB and populate cache (TTL 15m).
- Test: integration test asserting second read issues 0 DB queries.
## Step 3 β Invalidate on write
- Edit: src/services/profile.ts, updateProfile().
- After a successful DB write, del() the cache key for that id.
- Test: write-then-read returns the updated value.
## Step 4 β Wire config
- Add CACHE_PROFILE_TTL to config with a 900s default.
- No new env required to run; default is safe.
## Order & safety
- Steps are independently committable. After each step,
the full test suite must pass before moving on.
The plan does three things the spec couldn't. It picks the actual libraries and file paths. It sequences the work so the system is never broken between steps. And it attaches a verification to each step, so "done" is observable rather than asserted. When I review a plan, I'm checking exactly one thing: if every step executes as written, does the spec come true? If yes, approve. If I have to squint, the plan needs more detail.
This is also the right moment for the lighter second gate. You don't need to scrutinize a plan as hard as a spec β the spec is where intent lives β but a quick read catches the agent picking a library you've banned or sequencing steps in a way that breaks the build halfway through.
Subagents: build and review with fresh eyes
Here's where modern agent harnesses earn their keep. The single most effective structural improvement you can make to agent output is to separate the builder from the reviewer. Not the same agent reviewing its own work in the same context β a genuinely separate subagent with its own fresh context window, given the spec, the plan, and the diff, and asked one question: does this diff satisfy the spec, and is it correct?
Why fresh context matters: an agent that just wrote 300 lines of code is the worst possible reviewer of those lines. It's primed to see them as correct β it generated them by following what it believed was right, so re-reading them reactivates the same reasoning that produced them. It will skim its own bugs the way you skim your own typos. A reviewer subagent that has never seen the code being written, that only knows the spec and the plan, reads the diff the way a stranger would. It catches the off-by-one, the missing invalidation, the test that asserts nothing.
A practical build-review loop looks like this:
- Builder subagent takes one plan step, implements it, runs the tests for that step, and reports back with the diff.
- Reviewer subagent gets the spec, the plan step, and the diff. It checks correctness, checks the diff against the out-of-scope list (did the builder touch something it shouldn't?), and either approves or returns specific findings.
- Orchestrator (the main agent, or you) routes findings back to the builder and re-runs the loop until the reviewer is satisfied.
The out-of-scope check is the sleeper feature here. Because the spec explicitly lists what's not changing, the reviewer has a concrete list to check the diff against. "The spec says list endpoints are out of scope, but this diff added caching to getProfileList" is the kind of catch that a self-reviewing agent almost never makes and a fresh reviewer almost always does. I cover the context-window mechanics behind this in more depth in context engineering β the short version is that fresh eyes are fresh precisely because their context isn't polluted with the builder's intermediate reasoning.
Atomic plans and fresh context: the GSD approach
There's a sharper version of the fresh-context idea, and it's the core insight of GSD (Get Stuff Done). Instead of running the whole plan in one long-lived context window that slowly rots, you run each atomic step in its own fresh context window.
Think about what happens in a long agent session. By step four of a six-step plan, the context window holds: the spec, the plan, the diffs from steps one through three, the test output from each, a few wrong turns the agent backed out of, and whatever files it read along the way. The signal β "implement step four" β is buried under thousands of tokens of history that are no longer relevant. The agent's attention is diluted across all of it. Quality degrades. This is context rot in action, and it's why long agent sessions get progressively worse, not better.
GSD's answer: make each plan step genuinely atomic, then execute it in a clean window that contains only what that step needs β the spec, that one step, and the current state of the relevant files. No accumulated history. The step runs at full attention, produces its diff, gets reviewed, and the context is discarded. The next step starts fresh.
The tradeoff is real and worth naming. Fresh context per step means re-establishing context per step β you pay tokens to reload the spec and re-read the relevant files at the start of each atomic run. For a six-step plan that's six reloads. But the alternative is a single window where every step after the second is operating on degraded attention, and the cost of that is bugs you have to find and fix later. GSD is betting, correctly in my experience, that paying for clean context up front is cheaper than paying for rework. It works best when your plan steps are truly independent and well-specified, which loops back to why the plan quality matters so much.
Role-based variants: the GStack approach
GStack takes a different organizing principle: roles. Instead of one agent moving through phases, you have a small team of specialized agents, each with a defined role and a defined handoff β a product-minded agent that owns the spec, an architect that owns the plan, an engineer that builds, and a reviewer that checks.
The appeal is that each role gets a focused system prompt and a narrow job. The spec-writer is prompted to think about user behavior and edge cases and is explicitly not allowed to talk about implementation. The architect can't change the spec, only translate it. This separation enforces the spec/plan boundary structurally rather than relying on one agent to remember to keep them separate. The handoffs become the gates: the spec-writer hands to the architect, which is the natural sign-off point.
Role-based workflows shine on larger features and on teams, because the roles map onto how humans already divide the work, and the artifacts (spec, plan, review) are exactly the artifacts a human team would produce and review. The cost is ceremony. For a ten-line change, spinning up four roles is absurd. GStack knows this and lets you collapse roles for small work, but the model is fundamentally built for substantial features where the structure pays for itself.
Comparing the major SDD skills
These four skills all implement spec-driven development, but they sit at very different points on the spectrum from "opinionated and complete" to "minimal and composable." Here's how I'd characterize them:
| Skill | Philosophy | Best for | Heaviness | The catch |
|---|---|---|---|---|
| Superpowers | Full, opinionated, end-to-end | Teams that want the whole loop enforced out of the box | Heavy | Strong opinions; you adopt its workflow, not the reverse |
| GStack | Role-based, specialized agents | Larger features, team-shaped work | Medium-heavy | Ceremony overhead on small tasks |
| GSD Core | Atomic plans in fresh context | Long multi-step builds where context rot bites | Medium | Token cost of reloading context per step |
| Matt Pocock | Composable, anti-heaviness | Devs who want SDD pieces without the full ritual | Light | You assemble the discipline yourself |
Superpowers is the maximalist. It bundles the interview, the spec, the sign-off gates, the plan, the build, and the review into one coherent, opinionated workflow. If you want SDD and you don't want to think about how to wire it together, this is the default. The flip side of opinionated is that you live inside its choices.
GStack organizes around roles, as covered above β reach for it when the work is big enough that role separation clarifies rather than encumbers.
GSD Core is the atomic-plans-in-fresh-context skill. Its differentiator isn't the loop, it's the execution model: every step runs clean. Use it when your builds are long enough that context rot is your actual bottleneck.
Matt Pocock's skills are the deliberate counterweight to SDD heaviness. The thesis is that the full ritual is overkill for most changes and that you're better served by small composable pieces you invoke when you need them β a spec helper here, a review pass there β without committing to a four-phase pipeline for every task. If you find Superpowers stifling, this is where to go.
For a broader tour of how these fit alongside other tools, I keep a running comparison in the most popular AI coding skills roundup.
When SDD is overkill
I have to be honest about this because the SDD-evangelist crowd often isn't: full spec-driven development is overkill for most of what you do day to day. Writing a spec, getting sign-off, writing a plan, and running a build-review loop for a one-line copy change or an obvious bug fix is process for the sake of process. You'll spend more tokens and more of your own attention on the ceremony than the change is worth.
The honest decision rule is about irreversibility and ambiguity, not size:
- Tiny and obvious (typo, copy tweak, add a log line) β just do it. No spec.
- Small but ambiguous (the request could mean two different things) β at minimum, do the interview step. Often that's enough.
- Medium and clear (a well-understood feature in a familiar part of the codebase) β a lightweight spec and a quick plan, skip the role ceremony.
- Large, ambiguous, or risky (touches money, auth, data integrity, or a part of the system you don't fully understand) β full SDD, every gate, fresh-context execution, separate reviewer.
For the broad middle, a light ruleset beats a heavy pipeline. The Karpathy-style guidelines approach is the minimal viable discipline: a short set of standing rules you give every agent β keep diffs small, don't touch files outside the task, write a test, ask before doing anything destructive, explain your plan in two sentences before editing. No spec document, no formal gates, just a handful of guardrails that prevent the worst behaviors. For a huge fraction of real work, that's the right amount of process. SDD is what you escalate to when the guardrails aren't enough, not what you start with.
The skill, frankly, is matching the process to the task. An engineer who runs full SDD on everything looks disciplined and is actually just slow. An engineer who runs guidelines on everything looks fast and ships the occasional disaster. The good ones read the task and pick.
Token cost: what this actually costs you
None of this is free, and you should reason about the bill. Spec-driven development spends tokens in three places the cowboy approach doesn't: the interview, the spec-and-plan artifacts, and the separate reviewer with its fresh context.
Roughly, here's how the costs stack:
- The interview is cheap β a few exchanges of mostly-text, no large file reads. Easily the best ROI in the whole pipeline.
- Spec and plan are cheap to write and cheap to store β they're short documents. Their cost is mostly your time reading them, not tokens.
- Fresh-context execution (GSD-style) is the expensive part. Reloading the spec and re-reading relevant files per atomic step multiplies your input tokens by roughly the number of steps. This is the line item to watch.
- The separate reviewer roughly doubles the read cost of the diff, since a second agent reads what the builder wrote.
So a full SDD run on a real feature might cost two to four times the raw tokens of letting one agent cowboy it. That sounds bad until you price the alternative: the cowboy run that produces a subtly wrong diff costs you a debugging session, a re-explanation, and a second attempt β often more total tokens and far more of your wall-clock time. The expensive failure mode isn't tokens, it's you, three days later, reverse-engineering why the cache serves stale data across instances.
My rule: spend tokens on the gates (interview, spec, review) generously, because they prevent expensive failures, and spend them on fresh-context execution selectively, because it's the priciest piece and only pays off on genuinely long builds. If you're token-budget-constrained, the interview and the separate reviewer are the two things to keep; they catch the most for the least.
Putting it together: one feature, end to end
Let me walk the caching feature through the whole loop so the abstraction has a body.
I start with a one-liner: "Add caching to profile reads." The agent, running grill-me, refuses to write anything and instead asks: how many instances? invalidate on write or tolerate staleness? read/write ratio? latency budget or DB-load reduction? I answer: three instances, must invalidate on write, mostly reads, this is about DB load. Those answers immediately rule out an in-process cache β the agent now knows it needs Redis. That single interview saved the entire wrong-architecture detour.
The agent writes the spec you saw above. I read it, and the one thing I correct is the TTL β I push it from 5 minutes to 15 because the invalidation is doing the real work and the TTL is just a safety net. Approved.
It writes the four-step plan. I read it, confirm that executing all four steps makes the spec true, and notice it's using the existing ioredis connection rather than opening a new one β good. Approved.
Now the build. A builder subagent takes step one, writes the cache wrapper, tests it, reports the diff. A reviewer subagent β fresh context, only the spec and step one β confirms it's correct and in scope. Step two: cache the reads. The reviewer catches that the first draft populated the cache before confirming the DB read succeeded, which would cache an error state. Returned, fixed, re-reviewed. Step three: invalidation. The reviewer checks it against the out-of-scope list and against the spec's "write-then-read returns new value" criterion. Step four: config. Done.
Total: one interview, one spec, one plan, four build-review cycles. The reviewer caught one real bug (caching before confirming the read) that a self-reviewing agent would very likely have shipped, because the builder intended it to be correct and would have read its own code as correct. That single catch justifies the whole apparatus.
What I did not get: a fourteen-file diff, a renamed dependency, an invented config option, or a cache that corrupts data across my three instances. The process didn't make the agent smarter. It made the agent's intent legible and its mistakes catchable, which is all I actually need.
How to start tomorrow
You don't have to adopt a full skill on day one. Build the habit in this order:
- Add the interview. Before any non-trivial task, make the agent ask before building. This alone fixes most of the pain. Try grill-me.
- Write tiny specs. One paragraph of behavior plus an out-of-scope line. Approve it before any code.
- Add a separate reviewer. A fresh subagent that reads the spec and the diff. Cheap, high-catch.
- Then escalate to a full skill β Superpowers, GStack, or GSD β once you feel where your bottleneck actually is.
Match the process to the task, spend tokens on the gates, and let the agent do the typing while you keep the judgment. That's the whole discipline. If you want the structured version with exercises, the agentic automation track walks through each phase with hands-on builds.
Resources & links
External repositories:
- Superpowers β github.com/obra/superpowers
- GStack β github.com/garrytan/gstack
- GSD Core β github.com/open-gsd/gsd-core
- Matt Pocock skills β github.com/mattpocock/skills
On this site:
- Superpowers skill β the full, opinionated end-to-end SDD workflow
- GStack skill β role-based agents for team-shaped work
- GSD Core skill β atomic plans in fresh context windows
- grill-me skill β the interview step that makes agents ask before building
- Context engineering β the mechanics behind fresh-context review
- The most popular AI coding skills β a running comparison roundup
- Agentic automation track β the structured course with hands-on builds
Download the skills from this guide
Put the ideas above into practice β grab these ready-to-run agent skills.

Superpowers: The Spec-Driven Skill That Owns Your Whole Build
The most-starred agent skill on GitHub. Superpowers stops your agent from rushing in, works a spec out of the conversation, and hands a reviewed plan to subagents that build and check each other's work.

GStack: Give Your Agent a Whole Software Team's Worth of Roles
Garry Tan's Claude Code setup, ~110k stars. Instead of one mode, GStack gives your agent distinct roles β product vision, designer, engineering manager, QA, release manager β each behind its own slash command.

GSD Core: Ship Without Context Rot Using Atomic Plans
Git. Ship. Done. A spec-driven system that fights context rot by breaking work into atomic plans that run in fresh context windows, keeping your main session light while subagents do the heavy lifting.