#AI#TypeScript

Spec-Driven Development: Requirements Engineering for the AI Era

Once AI can write code, the bottleneck shifts from "writing" to "defining exactly what is needed." Spec-driven development, which writes the spec before AI implements it, addresses this shift. This article covers requirements, constraints, acceptance criteria, non-goals, the spec-plan-iterate workflow, and specs as documentation, tests, and contracts.

Key Points

  • Topic Focus: AI、TypeScript
  • Suitable for: indie hackers, full-stack engineers, AI application developers
  • Core value: quickly understand background, practical paths, common pitfalls, and engineering advice
Author @admin·Published July 26, 2026·Updated July 26, 2026

Once AI could write code, something interesting happened: "turning requirements into code" became almost free, but "figuring out exactly what the requirements are" became the most expensive part. Ask AI to build a "user avatar upload" feature, and it can finish it in three minutes, but there is an 80% chance the result is not what you wanted because you did not specify size limits, formats, retry behavior, or whether cropping is required. Spec-Driven Development is requirements engineering built for this era.

I. The Bottleneck Shifts: Writing Code Gets Cheaper, Thinking Clearly Gets More Expensive

In traditional software engineering, implementation was the programmer's bottleneck. You had to translate logic into code by hand, which was slow and exhausting. Requirements could be rough because you would discover problems as you coded anyway.

AI-assisted programming changed one thing: implementation costs are approaching zero. AI can write 500 lines in a minute, but if your instruction is "build an upload feature," those 500 lines will probably need to be reworked. The problem is not a lack of capability; it is that you never defined the boundaries.

The bottleneck has therefore shifted from "writing" to "figuring out what is actually needed." A vague requirement used to become a rough but runnable implementation; now it becomes a polished implementation that solves the wrong problem. The cost of rework has not changed; it has simply shifted from "writing it by hand" to "rewriting it + review."

This is the fundamental reason specs matter more: when implementation is cheap, the specification becomes the leverage point. With a clear spec, AI gets it right in one pass; with a vague spec, you go back and forth.

II. What Is Spec-Driven Development?

The core of Spec-Driven Development fits in one sentence: write the specification (spec) first, then implement it.

Here, a "spec" is not a hundreds-of-pages requirements document from the waterfall era. It is a compact requirements description that both humans and AI can understand, usually one or two hundred lines of Markdown explaining what is needed, the constraints, what counts as done, and what not to do. Once the spec is written, either a human or AI can implement from it and validate the result against it.

Its difference from a traditional "requirements document" is density and executability: it is not prose written for a review committee, but a contract written for the implementer, whether AI or human. Its difference from "just ask AI to write it" is sequence: first put the vague intent in your head into writing and force yourself to clarify it, then let AI implement it.

One test is: if you handed your spec to someone with no domain knowledge at all, could they use it to validate the result? If yes, the spec passes.

III. What a Spec Should Contain: Four Elements

A valid spec contains at least four parts:

1. What to Build (What). Describe the feature's goal in the user's language instead of jumping directly to an implementation. Example: "Allow users to upload an avatar, which the server crops into a square for storage."

2. Hard Constraints (Constraints). Performance, compatibility, technology stack, and other hard constraints. These are the guardrails AI needs most. Example: "Images ≤ 5MB; support jpg/png/webp; use sharp for cropping; Node 20."

3. Acceptance Criteria (Acceptance). A verifiable checklist that can be checked off, forming the bridge between the spec and tests. Example: "Uploads over 5MB return 413; non-image types return 415; success returns the cropped image URL."

4. Non-goals (Non-goals). Draw explicit boundaries to prevent AI from improvising. Example: "No client-side cropping; no animated gifs; no multi-image batch uploads." This is the most frequently overlooked element and also the most valuable.

Here is a practical spec template for the "avatar upload" feature:

markdown
# Spec: User Avatar Upload

## Goal
Users can upload an image as their avatar, and the server crops it into a 256x256 square for storage.

## Constraints
- Size: ≤ 5MB
- Formats: jpg / png / webp
- Technology stack: Next.js Route Handler + sharp (Node 20)
- Storage: Write to /avatars/<userId>.webp
- Performance: Processing time < 500ms (for files up to 5MB)

## Acceptance Criteria
- [ ] Over 5MB → Return 413
- [ ] Unsupported format → Return 415
- [ ] Success → 200, return { url, width, height }
- [ ] Authentication failure → 401
- [ ] Repeated uploads by the same user overwrite the old file

## Do Not Build (Non-goals)
- No client-side cropping UI
- Do not support gif / video frames
- No upload progress bar (this iteration)
- Do not integrate object storage (use local disk first)

Give this spec to AI and it will almost never veer off course; give it to a new teammate and they can validate the result from it as well.

IV. The Spec → Plan → Iterate Workflow

Writing a spec does not mean immediately "letting AI do everything in one shot." Use a stable three-stage workflow:

1. Spec (write the specification). Clearly document the four elements above, save them as SPEC.md in the task directory, or paste them directly into the conversation.

2. Plan (have AI produce a plan first). Do not have it start writing code immediately. Give it the spec and ask, "How many steps will you use, which files will you touch, and what are the risks?" A solid plan lets you catch misalignment before implementation begins, which is far cheaper than throwing everything away afterward. Claude Code's plan mode and Codex's planning phase are designed for exactly this.

3. Iterate (implement in small steps + check against acceptance criteria). Work through the plan incrementally. At every step, check the spec's acceptance criteria: run tests, inspect the diff, and confirm that the step passes before moving on.

In practice, the first conversation looks like this:

text
# Instructions for the AI (after pasting the contents of SPEC.md)
Here is the avatar upload spec. First, produce only an implementation plan:
1. List the files to modify/add
2. State which spec acceptance criterion each step addresses
3. Flag anything you consider risky or that requires my confirmation
Do not write implementation code yet. Wait for me to approve the plan.

This step constrains the AI's "freedom to improvise." Once you confirm the plan and let it implement, quality becomes much more consistent and rework decreases.

V. The Multiple Roles of a Spec

A good spec is not just for AI. It serves four roles at once:

  • It is documentation. Six months later, reading the spec is ten times faster than digging through the code. New teammates can onboard by reading it directly.
  • It is context for AI. Feed the spec back to AI for later changes, and it immediately understands the feature's boundaries without touching areas it should leave alone.
  • It is an acceptance checklist. Acceptance criteria can be converted directly into test cases, keeping the spec and tests derived from the same source.
  • It is a team contract. A PM, frontend developer, and backend developer may each understand a feature 15 degrees differently. The spec aligns everyone to the same baseline. Reviews stop arguing about "what I think" and instead ask, "What does the spec say, and should we change the spec?"

A single spec serves four purposes at once, which is the fundamental reason for its high return on investment. Write it once and use it everywhere.

VI. How to Write a Good Spec: Good vs. Bad Examples

The keys to writing a good spec are: be clear, make it verifiable, give examples, and define boundaries. Bad examples make the problem easiest to see.

Bad example (a vague spec that is guaranteed to fail):

text
Build a search feature. It should be fast, support fuzzy search, and provide a good experience.

Every word in this spec is a trap: what does "search" search? Is "fast" 50ms or 500ms? Does "fuzzy" mean prefix matching, substring matching, or Pinyin? Does a "good experience" mean debouncing, highlighting, or suggestions? If AI implements this, you will get a search experience it "thinks is good," which is probably not what you wanted.

Good example (the same feature expressed as an executable spec):

markdown
# Spec: Article Title Search (suggest)

## Goal
As the user types in the input field, return matching article titles in real time (up to 10).

## Constraints
- Data source: Existing articles table (approximately 50,000 rows)
- Matching: Prefix matching (case-insensitive)
- Latency: 300ms debounce after input; endpoint P95 < 100ms
- Frontend: React, using the existing input component

## Acceptance Criteria
- [ ] Input "next" returns all articles whose titles start with next
- [ ] Results ≤ 10, sorted by update time in descending order
- [ ] Empty input sends no request
- [ ] Case-insensitive: "Next" and "next" return the same results

## Do Not Build
- No full-text search (this iteration searches titles only)
- No Pinyin/tokenization support
- No highlighting (next iteration)

The difference is obvious: the bad example describes feelings; the good example states checkable facts. The essence of writing a spec is to pull out all those "everyone knows that" default assumptions in your head and put them into words, one by one. Whatever you cannot pull out is where future rework will come from.

VII. Spec Granularity

A spec that is too large becomes unmanageable, while one that is too small fragments the work. The principle is: split by units that can be independently accepted.

  • One spec should correspond to a feature slice that can be delivered and accepted independently. Avatar upload is one spec; avatar upload + cropping UI + CDN delivery are three.
  • Too large, such as "the entire user system": AI loses direction in an enormous context, and passing all acceptance criteria in one attempt becomes difficult.
  • Too small, such as "add one field": the cost of writing the spec exceeds the benefit, so a clear explanation in the conversation is enough.

A useful rule of thumb is: a spec usually has 3-8 acceptance criteria. More than 10 suggests it should be split; fewer than 2 suggests it may not deserve its own spec.

With the right granularity, specs constrain AI without slowing down the work.

Summary

Spec-Driven Development is requirements engineering for the AI era:

  • A shifting bottleneck: writing code gets cheaper while "figuring out exactly what is needed" gets more expensive, making the spec the new leverage point.
  • Four elements: what to build, constraints, acceptance criteria, and non-goals. Non-goals are the most valuable.
  • Workflow: spec → have AI plan first → iterate in small steps, checking acceptance criteria at every step.
  • One spec, four uses: documentation, AI context, acceptance checklist, and team contract.
  • Granularity: split by independently acceptable units, ideally with 3-8 acceptance criteria.

Remember: in the AI era, people who can write code are not scarce; people who can think requirements through clearly are. A spec is the product of that clear thinking. Spend an extra half hour on the spec, and AI can save you three hours of implementation rework. However you run the numbers, it pays off.

Related

Related Content