“Build me a dashboard.”

That can produce surprisingly good code today. It can also produce the wrong dashboard surprisingly quickly.

The problem is not necessarily the model. The problem is that we gave it a sentence where an engineering contract was needed.

As coding agents become capable of reading repositories, changing multiple files, running tests, and repairing their own work, I think the way we describe work has to mature with them. A prompt can start a conversation. It should not automatically become the specification for a meaningful software change.

That is where spec-driven development becomes useful.

What I Mean by Spec-Driven Development

I am not suggesting that every change needs a large requirements document. I am suggesting something much more practical: before asking an AI agent to implement a non-trivial change, make the expected behavior explicit enough that both the agent and a human reviewer can tell whether the implementation is correct.

Idea
  ↓
Requirements
  ↓
Specification
  ↓
Technical plan
  ↓
Tasks
  ↓
Implementation
  ↓
Verification

The specification sits between an idea and an implementation. It turns “what I want” into something testable without prematurely deciding every implementation detail.

A Prompt Is Not a Specification

Consider this request:

Add search to the application.

A capable coding agent can inspect the repository and make reasonable assumptions. But there are many unanswered questions. What can users search? Is matching exact, partial, or fuzzy? What happens with no results? Should search work on mobile? Is there a minimum query length? Does the URL preserve the query? What response time is acceptable? Are there fields the user must not be allowed to search?

If those decisions are not stated, the agent has to invent them.

That may be acceptable for a prototype. It is a weak foundation for production engineering.

Turn the Same Request Into a Small Spec

# Search

## Goal
Help users find published articles by title, summary, topic, or tag.

## Behavior
- Search begins after 2 characters.
- Matching is case-insensitive.
- Title matches rank ahead of summary matches.
- Empty queries show the normal article list.
- No-result state explains that nothing matched and allows clearing the query.
- Search works with keyboard navigation and on mobile.

## Constraints
- Do not introduce a hosted search dependency for this version.
- Do not expose unpublished content.
- Reuse the existing article metadata.

## Acceptance criteria
- A title can be found by a partial title.
- Clearing the query restores the full list.
- An unmatched query renders the no-result state.
- Existing article navigation continues to work.
- Existing quality checks pass.

This is still small. But now the agent has boundaries. The reviewer has a contract. Tests can be derived from the acceptance criteria. And when someone disagrees with the behavior, the disagreement can happen before a large implementation is produced.

The Spec Should Describe What, Not Pretend to Know Every How

One failure mode is turning a specification into an implementation transcript.

A product or feature spec should normally describe the problem, expected behavior, constraints, interfaces that matter, and acceptance criteria. The technical plan can then describe which components change, how data flows, what dependencies are used, and how the repository will be modified.

I find this separation useful:

  • Spec: What must be true when we are done?
  • Plan: How do we intend to make it true?
  • Tasks: What work will we execute?
  • Verification: What evidence proves it?

When these are mixed together, requirements become harder to review and implementation assumptions can quietly masquerade as business requirements.

What Belongs in a Useful Feature Spec?

There is no universal template, but I usually want enough information to answer the following:

  • Context: Why are we changing something?
  • Problem: What is not working or not possible today?
  • Goal: What outcome are we trying to create?
  • Non-goals: What are we deliberately not solving?
  • Users: Who experiences the behavior?
  • Functional requirements: What must the system do?
  • Business rules: What conditions govern the behavior?
  • Interfaces: Which API, event, data, or UI contracts matter?
  • Constraints: What architectural, security, compliance, or technology boundaries apply?
  • Failure behavior: What happens when dependencies or inputs fail?
  • Non-functional requirements: What matters for performance, reliability, accessibility, observability, or scale?
  • Acceptance criteria: How will we know the change is correct?
  • Open questions: What has not been decided yet?

Not every change needs every section. The template should help thinking, not become paperwork.

Use Different Levels of Specification

A one-line validation change should not require the same process as a new authorization model.

I prefer three rough levels:

Quick Spec

For small, well-bounded changes. Capture the goal, expected behavior, constraints, and acceptance criteria. This may fit on one screen.

Feature Spec

For normal product and engineering work. Add user flows, business rules, interfaces, failure behavior, non-functional requirements, and explicit non-goals.

Architecture Spec

For cross-system or high-impact changes. Add system context, boundaries, data ownership, security model, operational concerns, migration strategy, compatibility, alternatives, and architecture decisions.

The amount of specification should follow the risk and ambiguity of the change, not a process mandate.

AI Can Help Write the Spec, but It Should Not Invent the Product

There is a useful role for AI before implementation begins.

Give the agent the initial idea and relevant repository context. Ask it to identify ambiguity, missing decisions, edge cases, dependencies, and acceptance criteria. Let it ask questions. Let it draft the structure.

But there is an important boundary: generated requirements are proposals until a human responsible for the change accepts them.

If an AI agent notices that a search feature has no defined empty state, that is useful. If it silently decides what the empty state should be and then implements it, a design decision has been hidden inside code generation.

Specifications Become More Valuable When They Live With the Code

This connects directly to the idea of an AI-ready repository.

If the repository contains architecture context, engineering rules, specifications, plans, decisions, tests, and verification commands, the coding agent has a much stronger environment in which to work.

docs/
  architecture.md
  conventions.md

specs/
  article-search/
    spec.md
    plan.md
    tasks.md
    decisions.md

src/
tests/

The exact directories do not matter. What matters is that engineering intent is durable and discoverable rather than trapped in a chat session.

The Spec Can Become the Spine of the Development Loop

Once acceptance criteria are explicit, the rest of the workflow becomes easier to reason about.

Spec
  ↓
Plan against repository
  ↓
Human review
  ↓
Implementation
  ↓
Tests + repository verification
  ↓
Compare evidence to acceptance criteria
  ↓
Review

The agent is no longer trying to infer success from “the code looks finished.” It has something concrete to verify against.

Where Spec-Driven Development Goes Wrong

Specs are not automatically good because they exist.

Overspecification can make a small change unnecessarily slow. Stale specifications can become more dangerous than no specification because an agent may confidently follow outdated intent. Generated requirements can introduce assumptions nobody consciously approved. Contradictory acceptance criteria can make verification meaningless. And a giant template filled with vague text can create the appearance of rigor without actually reducing ambiguity.

The goal is not documentation volume. The goal is shared clarity.

A Simple Test for a Good Spec

Before implementation starts, I would ask:

  1. Can someone unfamiliar with the conversation understand the intended outcome?
  2. Are important boundaries and non-goals explicit?
  3. Have we exposed decisions the AI would otherwise have to guess?
  4. Can acceptance criteria become tests or other observable evidence?
  5. Does the spec leave reasonable implementation choices to the technical plan?
  6. Can we tell when the spec itself needs to change?

If the answer is yes, the spec is probably doing useful work.

From Prompting to Engineering

Prompting is not going away. It remains a natural way to explore ideas, ask questions, and work with coding agents.

But as the consequence of an AI-generated change increases, I want something more durable than the conversation that produced it.

I want the intent captured. I want assumptions visible. I want boundaries explicit. I want acceptance criteria that can be verified. And I want the implementation to be judged against that contract rather than against how convincing the agent sounds when it says it is done.

Spec-driven development is not about giving AI more documentation. It is about giving software development a clearer contract between human intent and machine execution.

Download the Starter Templates

I use templates as thinking aids, not forms that must be filled out. Start with the smallest one that removes the ambiguity in the work.

They are deliberately plain Markdown. They can live beside the code, be reviewed in a pull request, and work with whichever coding agent or development environment a team chooses.


Continue: Read The AI-Ready Repository: Designing Codebases for Coding Agents to see how specifications fit into the wider repository context.