EngineeringGuides

Spec-Driven Development with AI Coding Agents

Shiplight AI Team

Shiplight AI Team

Updated on July 15, 2026

View as Markdown
Illustrated Shiplight blog cover: a glossy AI chip reading a specification document and producing a small app window, with a green checkmark verifying the output matches the spec, arranged in a compact loop.

Spec-driven development with AI coding agents is a workflow where you write a structured specification first, then hand it to an agent that implements, verifies, and tests against it. The spec is not documentation that trails the code. It is the input that drives generation and the contract that defines what "done" means, so the same document that tells the agent what to build also tells you and the agent when it is finished.

This matters because AI coding agents are fast at producing code and unreliable at knowing whether that code is correct. Left to a loose prompt, an agent will generate something plausible, and plausible is where subtle bugs live. A spec closes that gap: it fixes the requirements, constraints, and acceptance criteria before a single line is written, so the agent has an unambiguous target and a way to check its own work. (For the definitional groundwork, see what spec-driven development is.)

The practical shape of spec-driven development is a loop with four moves: write the spec, let the agent implement it, verify the output against the spec, and promote the acceptance criteria into regression tests. Each move produces a concrete artifact, and each artifact feeds the next, so velocity and confidence rise together instead of trading off. This guide walks each step, shows what the artifacts look like, and explains where the loop tends to break: the verification handoff, where "the agent wrote it" quietly becomes "nobody checked it in a real browser."

Why the spec is shared context, not just documentation

Modern coding agents already read context files. Claude Code loads a CLAUDE.md at the root of a repository when a session starts. The AGENTS.md format is an open standard for the same idea, supported across more than 20 tools including Codex, Cursor, Jules, and VS Code, giving an agent setup commands, code style, and architectural boundaries in one machine-readable file. These files tell the agent how the codebase works in general.

A spec is the task-level version of that context. Where a context file describes the repository, a spec describes one change: the behavior to build, the constraints it must respect, and the acceptance criteria that decide whether it worked. Given a good spec, the agent generates against structured intent instead of guessing from a one-line prompt, and it has a checklist to test its output against.

The reason this improves output is not magic: context is what makes language models accurate. Research presented at ICSE 2026 found that feeding architectural documentation into LLM-assisted code generation produced measurable gains in functional correctness and conformance. A well-written spec is exactly that kind of context, aimed at a single unit of work.

The four-phase spec workflow

The clearest published model of this workflow comes from GitHub's Spec Kit, an open-source toolkit that brings spec-driven development to coding agents. Its process runs in four phases with a checkpoint after each one, and the phases generalize to any agent, not just the ones Spec Kit ships integrations for. For a tool-specific walkthrough, see spec-driven development with Spec Kit.

Specify. You give a high-level description of what you are building. The agent expands it into a detailed specification focused on user journeys, requirements, and what success looks like, deliberately excluding implementation detail. As GitHub describes it, this spec becomes "a contract for how your code should behave" and a living artifact that evolves with the project.

Plan. You add the technical constraints: the stack, architectural patterns, compliance needs, performance targets. The agent produces a technical plan that respects them. Because the plan is separate from the spec, you can revise how something is built without rewriting what it should do.

Tasks. The agent breaks the spec and plan into small, reviewable work items. GitHub's own guidance is that "each task should be something you can implement and test in isolation," which is the same discipline test-driven development asks for, applied one level up.

Implement. The agent works the tasks, and you review focused changes instead of one large code dump. Each phase has a reflect-and-refine checkpoint, so you catch a missed edge case or a wrong constraint while it is cheap to fix, before it is baked into code.

Write acceptance criteria in a consistent, testable form. The EARS syntax (Easy Approach to Requirements Syntax) is a common choice because criteria written that way read unambiguously to both humans and models and map close to one-to-one onto test cases. That property is what makes a spec executable rather than advisory, and it is the hinge the rest of this loop turns on.

The practical loop for a team using coding agents

Here is the loop as a team actually runs it, with the artifact each step leaves behind.

1. Write the spec: what "done" means, in acceptance criteria

Start with the behavior and the checks, not the code. A spec for a single change is short. It states the user-facing goal, the constraints, and a list of acceptance criteria phrased as observable outcomes.

## Feature: password reset via email

Goal: A signed-out user can reset their password using a link sent to their email.

Acceptance criteria:
- WHEN a user submits a known email on /forgot-password,
  the system sends a reset email within 60 seconds.
- WHEN the user opens the reset link, they land on /reset-password
  with a valid token.
- WHEN the user submits a new valid password,
  they are redirected to /login with a success message.
- WHEN the reset link is older than 24 hours,
  the page shows "This link has expired."

That artifact is the target for the agent and the yardstick for you. Every criterion is something you can observe in a running browser, which is what makes the later steps mechanical rather than subjective.

2. The agent implements against the spec

You point the agent at the spec and let it build. Because the criteria are explicit, the agent is not inferring requirements from a vague prompt. It implements the forgot-password page, the token flow, the email send, and the expiry handling, opening a pull request with focused diffs. The spec constrains scope, so the agent is less likely to gold-plate or drift.

3. The agent verifies its output against the spec

This is the step most workflows skip, and it is where spec-driven development either holds or falls apart. Generating code that looks right is not the same as confirming it works. The acceptance criteria describe browser behavior, so the honest check is to exercise that behavior in a browser, not to read the diff and nod.

This is the half of spec-driven development that Shiplight makes real. Shiplight installs into the coding agent as an MCP server plus Skills, giving the agent eyes and hands in a real browser through the Model Context Protocol. After the agent implements the change, it runs /shiplight verify and walks the acceptance criteria live: submit a known email, open the reset link, set a new password, land on /login. The agent checks its own output against the same spec that drove it, before a human sees the PR. If a criterion fails, it iterates in the same session instead of shipping a plausible-looking bug. This is verification embedded in the development loop, the pattern covered in the executable intent playbook.

4. The spec becomes your regression tests

A verified change is worth little if the next change silently breaks it. The final move turns the acceptance criteria into durable coverage. Because they are already written as observable outcomes, they convert almost directly into end-to-end tests.

With Shiplight, the agent runs /shiplight create-yaml-tests and authors the tests by walking the app in a real browser, one test per acceptance criterion. The tests are readable YAML written from intent, not brittle selectors:

goal: Password reset via email link succeeds
statements:
  - intent: Navigate to /forgot-password
  - intent: Submit a known account email
  - VERIFY: a reset email arrives within 60 seconds
  - intent: Open the reset link from the email
  - VERIFY: the page is /reset-password with a valid token
  - intent: Submit a new valid password
  - VERIFY: the user is redirected to /login with a success message

Those tests live in your git repository, run locally with npx shiplight test, and run in CI on every future pull request. They are Playwright-compatible and sit alongside any Playwright suite you already have, so there is no rip-and-replace. When the UI changes, the tests self-heal from the stored intent rather than failing on a moved button, and larger repairs surface as reviewable PR diffs instead of silent rewrites. The path from a written requirement to living coverage is the subject of turning product requirements into living end-to-end coverage.

The loop now closes without a human QA handoff. The agent that read the spec, implemented it, and verified it also owns the regression tests that protect it. This is what agent-first development looks like when the quality step is agent-native too, and it is why the integration mechanism, MCP, is the same across Cursor, Copilot, Codex, and Claude Code.

Where teams get the balance wrong

Two failure modes are common. The first is treating the spec as a formality, a paragraph the agent skims and ignores. A spec earns its keep only when its acceptance criteria are concrete enough to test, which is why the EARS-style "WHEN X, the system does Y" phrasing is worth the small effort.

The second is stopping at step two: write a good spec, let the agent implement it, review the diff, and merge, treating "the agent finished" as proof. Reading a diff confirms the code exists. It does not confirm the reset email arrives or the expired-link message renders. The criteria are behavioral, so the verification has to be behavioral. Skipping the browser is how a plausible implementation becomes a production incident, and it is the gap Shiplight is built to close.

Key Takeaways

  • In spec-driven development, the spec is both the input that drives an agent's code generation and the contract that defines when the work is done.
  • Write acceptance criteria as observable outcomes (EARS-style "WHEN X, the system does Y") so they map almost one-to-one onto tests.
  • The loop has four moves: specify, implement, verify against the spec, and promote the criteria into regression tests.
  • Verification is the step teams skip. Reading a diff is not proof; exercising the acceptance criteria in a real browser is.
  • Shiplight lets the coding agent verify its output against the spec and author maintained E2E tests from the same criteria, so the loop closes without a human QA handoff.

Frequently Asked Questions

What is spec-driven development with AI coding agents?

It is a workflow where you write a structured specification before any code, then hand it to an AI coding agent that implements, verifies, and tests against it. The spec fixes requirements, constraints, and acceptance criteria up front, so it serves as both the input that drives the agent's code generation and the definition of what "done" means. Toolkits like GitHub Spec Kit formalize this as a four-phase loop of specify, plan, tasks, and implement.

How do AI coding agents consume specs and context?

Agents read context in layers. Repository-level files like CLAUDE.md or the open AGENTS.md format give an agent standing context about the codebase: build commands, code style, and boundaries. A task-level spec adds the specifics of one change: its behavior, constraints, and acceptance criteria. The agent generates against that structured context instead of inferring requirements from a short prompt, which measurably improves correctness.

How do acceptance criteria become tests?

If you write acceptance criteria as observable outcomes, they translate almost directly into end-to-end tests. A criterion like "WHEN the user submits a valid password, they are redirected to /login" is already a test case: perform the action, assert the result. With Shiplight, the coding agent authors these tests by walking the app in a real browser and saves them as intent-based YAML in your repo, one test per criterion, so the spec becomes regression coverage that runs on every future pull request.

Does spec-driven development work with any coding agent?

Yes. The four-phase workflow is tool-agnostic, and GitHub Spec Kit alone ships integrations for around 30 agents including Claude Code, Copilot, Cursor, Codex, and Gemini CLI. The verification and test-authoring half works across agents too, because it uses the Model Context Protocol, an open standard that any MCP-compatible agent can call. The same install works for Claude Code, Cursor, Codex, and 40-plus agents.

How is spec-driven development different from test-driven development?

Test-driven development writes a failing test, then code to pass it, at the level of individual functions. Spec-driven development works one level up: it starts from a human-readable specification of behavior and acceptance criteria that an agent uses to generate code, verify it, and derive tests. The two are complementary. Spec Kit's own guidance to make each task "something you can implement and test in isolation" is TDD discipline applied inside a spec-driven loop.