AI coding assistants make it easy to produce a working feature before the team has agreed on how that feature should work. That feels productive — until the next developer cannot explain the architecture, a security assumption is missed, or every change introduces another workaround.

This is the risk behind unconstrained “vibe coding”: prompting an agent, accepting plausible output, and moving on without a durable technical contract. The problem is not that AI-generated code is always poor. The problem is that code can be generated faster than a team can review its design, dependencies, boundaries, and long-term consequences.

Spec-driven development (SDD) addresses that gap by making a structured specification the primary source of truth before code is generated. The specification defines what the system must do, which architectural rules apply, and how the result will be validated. For engineering leaders, it is a governance mechanism. For developers, it is a repeatable workflow for getting better results from coding agents.

The hidden cost of vibe coding

A typical unconstrained workflow looks efficient:

  1. A developer describes a feature in a chat prompt.
  2. The coding agent generates files and suggests a design.
  3. The developer fixes errors through follow-up prompts.
  4. Tests are added after the implementation appears to work.
  5. The change is merged before the broader architecture is reconsidered.

This works reasonably well for a small prototype. It becomes risky when the feature touches authentication, payments, customer data, shared services, or a codebase with established architectural boundaries.

The agent usually optimises for the immediate request. It may copy an existing pattern without understanding whether that pattern is deprecated. It may add a second way to access the database because the first way was inconvenient. It may put business logic in a controller because that makes the local task easier. Each decision can look harmless in isolation while increasing the cost of future changes.

The result is often an illusion of productivity. The team has more code, but not necessarily more maintainable software. Copy-paste activity can replace refactoring, and local fixes can gradually produce architectural drift. Security also becomes harder to reason about when the team has not specified data-handling rules, permission boundaries, input validation, or acceptable dependencies before implementation begins.

The practical question is not “Which coding agent writes the best code?” It is “What constraints must every coding agent follow in this repository?”

What spec-driven development changes

In SDD, the specification is not a document written after the code as a record of what happened. It is written before implementation and used to guide generation, review, and validation.

A useful specification normally includes:

  • Outcome: what the feature must enable for a user or another system.
  • Scope: what is included and explicitly excluded.
  • Interfaces: APIs, events, data structures, or user flows that must remain stable.
  • Architecture: which layers, services, and dependencies may be used.
  • Security rules: authentication, authorisation, data access, secrets, and validation requirements.
  • Acceptance criteria: observable conditions that determine whether the feature is complete.
  • Validation: tests, static checks, integration checks, and review gates required before merging.

This turns the specification into a contract between the product requirement, the engineering team, and the coding agent. The agent still produces implementation details, but it does not get to redefine the system’s boundaries simply because a prompt was ambiguous.

For example, suppose a team is adding an internal customer-export feature. A weak prompt might ask an agent to “add CSV export to the customer page.” A stronger specification would state that only users with a specific permission can export, that sensitive fields must be excluded, that exports above a defined size are queued rather than generated in a web request, that every export is audited, and that the endpoint must use the existing authorisation service.

The difference is not extra documentation for its own sake. The second approach gives the agent constraints that can be checked in code review and tests. It also gives the team a reference when the agent proposes a shortcut that conflicts with the system’s design.

Callout: Treat the spec as a brake, not a bottleneck

A short planning delay is usually cheaper than correcting an architectural decision after it has spread across multiple files, services, and deployments. The purpose of SDD is not to eliminate iteration; it is to make iteration occur inside known boundaries.

The three levels of SDD implementation

Martin Fowler describes SDD as a spectrum rather than a single mandatory process. The three levels help teams choose an adoption path that matches their current maturity.

A comparison shows how spec-first, spec-anchored, and spec-as-source approaches guide AI-assisted development.
SDD can grow from planning aid to authoritative source.

1. Spec-first

The team writes a specification before asking an AI agent to generate code. The specification guides the initial implementation, but the code remains the main artefact after generation.

This is a useful starting point for a team that currently relies on ad-hoc prompts. Before building a feature, the developer writes the intended behaviour, constraints, and acceptance tests. The agent then works from that material instead of inventing the design during implementation.

Best fit: new features, prototypes that may become production systems, and teams learning to plan AI-assisted work.

Main weakness: the specification can become stale if nobody updates it after design decisions change.

2. Spec-anchored

The specification remains attached to the repository and is actively consulted throughout development. It informs implementation, code review, testing, and future changes.

This is often the most practical target for an existing engineering team. A project-specific rules file can define conventions and architectural guardrails, while feature specifications describe individual changes. The agent is instructed to read these files before modifying code and to report conflicts rather than silently choosing a workaround.

Best fit: established codebases where architectural consistency matters but a full specification-as-source process would be too disruptive.

Main weakness: the team must maintain the rules and ensure they are actually included in the agent’s working context.

3. Spec-as-source

The specification becomes the authoritative source from which implementation and validation are derived. Code is treated more like a generated or continuously reconciled artefact than the primary design reference.

This can create strong consistency, but it requires mature specifications, dependable tooling, and clear ownership. It is not a sensible first step for every organisation, particularly when requirements change rapidly or the existing codebase is poorly documented.

Best fit: domains with stable rules, repeatable architectures, and a high need for traceability.

Main weakness: the process can become expensive and rigid if specifications are too detailed, poorly structured, or disconnected from real user needs.

The important decision is not to claim that a team is “doing SDD.” It is to identify which level is realistic for the repository and what evidence will show that the process is working.

Turning a repository into a constrained environment

Modern coding agents can load repository-specific instructions from defined files. Cursor projects may use .cursor/rules/, while Claude Code commonly uses CLAUDE.md. The filenames are less important than the operating model: the agent needs persistent, version-controlled instructions rather than relying on a developer to repeat them in every prompt.

A useful rules file should be short enough to be read and specific enough to influence decisions. It might contain:

Architecture
- Keep business rules in the domain layer.
- Controllers may validate request shape but must not contain business decisions.
- Use the existing repository and service abstractions; do not add direct database access.

Security
- Every customer-data endpoint must enforce the existing permission policy.
- Never log tokens, credentials, or sensitive customer fields.
- Validate external input at the boundary.

Change process
- Before editing, identify the relevant specification and existing tests.
- If the request conflicts with these rules, explain the conflict before coding.
- Add or update tests for each acceptance criterion.

The file should not attempt to describe every line of the codebase. Its job is to establish non-negotiable boundaries and direct the agent to more specific documentation.

A feature specification can then add the local contract:

Feature: customer export

Outcome
- An authorised support user can request a CSV export of customer records.

Constraints
- Use the existing export job queue.
- Exclude payment credentials and internal risk notes.
- Record the requesting user, filters, and completion status in the audit log.

Acceptance criteria
- Unauthorised users receive a denial without customer data exposure.
- Large exports are processed asynchronously.
- The download link expires after the configured period.
- Tests cover permission failure, field exclusion, queueing, and audit logging.

The workflow changes in several practical ways:

  1. Before coding: the developer writes or reviews the feature specification and identifies the repository rules that apply.
  2. During planning: the agent proposes a change plan, lists affected files, and flags ambiguities or conflicts.
  3. During implementation: the developer asks for small, reviewable changes rather than one large generation step.
  4. During validation: acceptance criteria are mapped to tests and checks, not merely confirmed by reading the generated code.
  5. During review: the reviewer checks both the implementation and whether the specification still describes the intended behaviour.
  6. After release: changes to architecture or behaviour are reflected in the specification and rules files.

This is how a specification becomes an executable validation gate rather than passive documentation. It influences what the agent may change, what tests must exist, and what reviewers should challenge.

A practical adoption plan for engineering teams

A team does not need to rewrite every requirement before using SDD. Start with one repository and one class of change where AI assistance is already common.

Step 1: Audit the current workflow

Collect a few recent AI-assisted pull requests. Look for:

  • prompts that contain no architectural or security constraints;
  • duplicated helpers or competing access patterns;
  • tests added only after implementation;
  • changes that modify unrelated files;
  • repeated reviewer comments about the same standards;
  • specifications that no longer match the code.

This audit identifies process failures without blaming a particular tool or developer.

Step 2: Establish repository guardrails

Create a version-controlled rules file. Keep the first version focused on high-impact boundaries: layering, data access, security, testing, dependency policy, and commands used to validate changes.

Assign an owner for reviewing the file. If nobody owns it, it will become either inaccurate or ignored.

Step 3: Require a plan before implementation

For changes above a chosen risk threshold, require the agent to produce a plan that names:

  • the relevant specification;
  • affected modules;
  • data and permission implications;
  • tests to add or update;
  • unresolved questions.

A technical lead should be able to reject the plan before code is generated. This is much cheaper than reviewing a large pull request built on a flawed assumption.

Step 4: Connect criteria to automated checks

Each important acceptance criterion should have a corresponding test, static check, or review question. For the customer-export example, “sensitive fields are excluded” should be tested against the actual serialised output, not left as a sentence in a document.

Step 5: Measure quality, not generated volume

Track indicators such as rework after review, escaped defects, repeated architecture violations, test coverage of critical paths, and time spent maintaining rules and specifications. Lines of AI-generated code are not a useful measure of engineering value.

Where SDD can fail

SDD reduces risk; it does not remove the need for engineering judgement.

The specification can be wrong. A detailed contract built on a misunderstood customer requirement simply helps the team implement the wrong thing more consistently. Product and engineering review still matter before the agent starts coding.

The specification can drift. If a design changes in a pull request but the rules and feature contract are not updated, the claimed single source of truth becomes misleading. Make specification updates part of the definition of done.

The specification can become bureaucracy. If every trivial change requires a long document, developers will work around the process. Use lightweight templates for low-risk work and deeper contracts for security-sensitive or cross-service changes.

The agent may not apply the rules reliably. Repository instructions are useful, but they are not a security boundary by themselves. Protect sensitive operations with permissions, automated tests, static analysis, CI checks, and human review.

Tooling is still inconsistent. SDD does not yet have one universal file format, workflow, or standard for translating specifications into executable checks. Teams should treat tool conventions as implementation details and keep the underlying contracts portable and understandable.

The most important failure mode is confusing the presence of a specification with successful adoption. A file that nobody reads, tests, updates, or enforces is documentation — not an engineering control.

The shift from faster prompts to safer systems

AI coding agents are most useful when they operate inside a clear system of constraints. Spec-driven development gives teams a way to define those constraints before implementation, preserve them during change, and test whether the resulting software still meets the intended contract.

For most organisations, the sensible starting point is spec-anchored development: create a project-specific rules file, require a short feature specification for meaningful changes, and make the agent produce a plan before it edits the repository. Then connect the important criteria to automated tests and review gates.

That approach will not make every AI-generated change correct. It does something more valuable: it makes incorrect assumptions easier to expose before they become architecture. The goal is not to stop developers from moving quickly. It is to ensure that speed produces software the team can still understand, secure, and maintain six months later.