Skip to content
AI Agents & Systems11 min read

Spec-Driven Development (SDD): How to Use spec.md to Keep AI Coding Agents From Hallucinating

Why conversational prompting fails on large codebases, and how to use version-controlled spec.md files to anchor AI coding agents to strict architectural contracts.

CET
ComputeSpec Editorial Team

If you use AI coding editors like Cursor, Windsurf, or Claude Code, you have likely witnessed the “agentic drift” disaster. You open Composer mode, type a three-sentence prompt asking to add a new checkout payment step, and press submit.

The agent scans your repo, edits seven files across four directories, refactors your user database schema without asking, and installs a deprecated payment SDK from 2022.

The issue isn’t that the model is incompetent. The issue is that conversational chat windows are the worst possible medium for communicating complex software architecture. Chat transcripts are ephemeral, unstructured, and suffer from severe context degradation as token counts rise.

In 2026, leading engineering teams have abandoned pure prompt-and-pray workflows in favor of Spec-Driven Development (SDD).


What is Spec-Driven Development (SDD) in AI pair programming?

To understand why SDD transforms software stability, compare the two execution workflows:

CONVERSATIONAL PROMPTING (Fragile & Ad-Hoc):
  User Prompt -> AI Guesses Architecture -> Edits 8 Random Files -> Manual Untangling

SPEC-DRIVEN DEVELOPMENT (Deterministic & Contained):
  spec.md Contract -> AI Confirms Boundaries -> Atomic File Edits -> Automated Verification
Criteria Ad-Hoc Conversational Prompting Spec-Driven Development (SDD)
Source of Truth Ephemeral, scrolling chat window Version-controlled spec.md in repository
Scope Boundary Undefined (AI edits whatever it wants) Explicit whitelist of allowed and forbidden files
Data Contracts Implicit assumptions about API shapes Explicit Zod schemas and TypeScript interfaces
Session Memory Resets every time you start a new chat Persistent across days, weeks, and team members
Reproducibility Zero (same prompt gives different code) High (structured constraints anchor the agent)

The Anatomy of a Production-Grade spec.md File

A specification for an AI agent should not read like a 40-page corporate document. It is a lean, highly structured contract designed for token efficiency and unambiguous parsing. Every robust spec.md contains four essential sections:

# Feature Specification: [Feature Name]

## 1. Intent & Context
- Why are we building this?
- What user problem does it solve?
- What tech stack primitives are available?

## 2. The Boundary Box (Crucial)
- Files allowed to modify: [List paths explicitly]
- Files FORBIDDEN to touch: [Config, auth handlers, package.json]
- External dependencies: Do NOT install any new npm libraries.

## 3. Data Contracts & Schemas
- Explicit input and output shapes defined with TypeScript/Zod.

## 4. Acceptance Criteria Checklist
- [ ] Criterion 1: Specific observable behavior
- [ ] Criterion 2: Error handling scenario
- [ ] Criterion 3: Automated test passing verification

How do you configure Cursor to follow a spec.md contract?

Here is the exact setup you can drop into your repository right now:

Step 1: Create Your .cursorrules Anchor

Add this rule to your root .cursorrules file to train Cursor’s AI models to respect specifications by default:

# Spec-Driven Development Guardrail

When an instruction references `@spec.md` or any feature specification:
1. Treat `spec.md` as the definitive, immutable source of truth.
2. Read the "Boundary Box" section first. Never modify, rename, or delete any file listed as FORBIDDEN.
3. If an implementation detail requires altering a forbidden file or installing new dependencies, HALT and request user approval before proceeding.
4. Implement tasks incrementally, verifying each item against the Acceptance Criteria checklist.

Step 2: The Practical Walkthrough: Building an API Webhook Handler

Let’s see an example in action. Suppose you need to build a Stripe webhook endpoint to update user subscription status. Instead of typing “Build me a Stripe webhook”, you create docs/specs/stripe-webhook.md:

# Feature: Stripe Subscription Webhook Handler

## Boundary Box
- Allowed to edit: `src/pages/api/webhooks/stripe.ts`
- Forbidden: `src/lib/auth.ts`, `src/config/database.ts`
- Libraries: Use existing `@stripe/stripe-js` already in package.json.

## Data Contract
Validate the incoming payload with this Zod schema:
```typescript
import { z } from 'zod';

export const StripeSubscriptionEventSchema = z.object({
  type: z.enum(['customer.subscription.created', 'customer.subscription.deleted']),
  data: z.object({
    object: z.object({
      customer: z.string(),
      status: z.string(),
    }),
  }),
});

Acceptance Criteria

  • Verify Stripe webhook signature using STRIPE_WEBHOOK_SECRET
  • Reject invalid signatures with HTTP 400 and error message
  • Parse valid events through StripeSubscriptionEventSchema
  • Return HTTP 200 within 200ms of payload receipt

### Step 3: Triggering Cursor Composer
Open Cursor Composer (`Cmd+I` on macOS, `Ctrl+I` on Windows) and submit this prompt:

> *"Execute the tasks defined in `@docs/specs/stripe-webhook.md`. Implement `src/pages/api/webhooks/stripe.ts` strictly adhering to the Boundary Box and Acceptance Criteria. Do not touch any other files."*

Because the AI's attention heads are anchored to the specification file rather than random tokens in your chat history, it produces clean, surgically targeted code that compiles and passes tests on the very first attempt.

---

## The 3 Cardinal Rules of Spec-Driven Engineering

1. **Specs Are Versioned, Not Disposable:** Check your `spec.md` files into Git alongside your code. When a teammate or future AI agent needs to modify the feature six months later, the original intent and architectural boundaries remain documented.
2. **Never Let the AI Edit the Spec and the Code Simultaneously:** Write the spec first, review it yourself, and commit it. Then instruct the AI to code against it. Letting the AI write its own specification defeats the purpose of the constraint.
3. **Use the Spec as a Testing Blueprint:** Each item in your Acceptance Criteria checklist should map directly to an automated test case (using Vitest or Playwright). A feature is only finished when the automated tests verify every checkbox.

By adopting Spec-Driven Development, you eliminate the cognitive fatigue of prompt micromanagement and build software that remains robust as your codebase scales into tens of thousands of lines.
#Spec-Driven Development#Cursor#AI Agents#Architecture#Engineering Standards#Vibe Coding

Related Technical Guides

Comments are powered by GitHub Discussions and will appear here once connected.