Quick answer
- One-line definition
- A per-task document: what to build, what not to touch, how success is judged
- Where it sits
- Prompt < spec file < PRD
- The core sections
- Goal · scope · non-scope · files · acceptance criteria · test plan · risks
- The heart of it
- Acceptance criteria a reviewer or test can mark true or false
What an AI Spec File Is, and Where It Sits
An AI spec file is a short, written, reviewable document that tells a coding agent exactly what to build and how you will judge whether it succeeded. It is the single highest-leverage piece of context you can attach to a task: not a paragraph of hopeful prose, but a bounded contract that names the goal, the scope, the files in play, and a set of checkable acceptance criteria. Give an agent a good spec file and it works toward something verifiable; give it a bare prompt and it infers all of that, usually wrong.
The easiest way to place it is by size. A prompt is a sentence or two, fast to write and fine for throwaway work, but it leaves scope, boundaries, and definition of done to the model. A PRD is a full product requirements document: personas, rationale, rollout, metrics, written for a team over weeks. A spec file sits between them, bigger than a one-liner, smaller than a design doc, scoped to one concrete change and written to be read in two minutes. The methodology of working this way, why the plan comes before the code at all, is its own topic; this page is about the artifact itself.
One distinction trips people up constantly: a spec file is not the same thing as your CLAUDE.md or AGENTS.md. Those are durable project context, the conventions and commands that apply to every task and rarely change. A spec file is per-task and disposable. You keep one AGENTS.md for the repo and write a fresh spec for each story; the agent reads both.
| Dimension | AGENTS.md / CLAUDE.md | Spec file | PRD |
|---|---|---|---|
| Scope | Whole project | One task / one change | A product or feature area |
| Lifespan | Durable, evolves slowly | Disposable, dies with the merge | Weeks to months |
| Audience | Every agent, every session | One agent + its reviewer | Team, stakeholders, PM |
| Contains | Commands, conventions, boundaries | Goal, scope, files, acceptance criteria | Personas, rationale, metrics, rollout |
| Written by | Set up once, generated + tuned | Per story, drafted then approved | Product, over multiple drafts |
The Anatomy of a Good Spec File
A useful spec file is short and has a fixed shape, so it is skimmable and nothing important gets forgotten. Seven sections cover almost every task; drop the ones that do not apply, but never drop the acceptance criteria.
Goal / why
Scope (in)
Non-scope (out)
Affected files / interfaces
Acceptance criteria
Test plan
The seventh section is risks and rollback: the one or two things that could go wrong (a dependency that must fail open, a migration that is hard to reverse) and how you would back the change out. On small changes it is a single line; on anything touching data or auth it earns its place. Keep the whole file shorter than the diff it describes, if the spec is longer than the change, you are over-specifying.
A Full, Copyable Spec File
Here is a complete spec file for a realistic, self-contained task, adding per-IP rate limiting to POST /api/login. Copy it, change the nouns, and you have a template for most tasks. Note how every acceptance criterion is a checkbox you could tick during review, and how the non-scope section does as much work as the scope section.
# Spec: per-IP rate limiting on POST /api/login
## Goal / why
Brute-force attempts against POST /api/login are unthrottled. Add
per-IP rate limiting so an attacker cannot try passwords at machine
speed. Success = a single IP is capped at 5 login attempts per minute.
## Scope (in)
- Add a rate-limit check to the POST /api/login handler only.
- Use a fixed window of 5 attempts / 60s, keyed by client IP.
- Store counters in the existing Redis client (src/lib/redis.ts).
- Return 429 with a Retry-After header when the limit is exceeded.
## Non-scope (out) — do NOT touch
- Any route other than POST /api/login.
- The password-hashing or session logic (src/lib/auth.ts).
- The User schema or any migration.
- Global/CDN-level rate limiting (handled at the edge separately).
## Affected files / interfaces
- src/app/api/login/route.ts (modify: add limiter call)
- src/lib/rate-limit.ts (create: fixedWindow(key, max, windowSec))
- No public interface changes; response shape unchanged except 429.
## Acceptance criteria (checkable)
- [ ] 5 valid-shaped POSTs from one IP within 60s all return normally.
- [ ] The 6th POST from that IP within the window returns 429.
- [ ] The 429 response includes a Retry-After header in seconds.
- [ ] A different IP is unaffected by the first IP's counter.
- [ ] After the 60s window elapses, that IP can attempt again.
## Test plan
- Unit: fixedWindow() increments, expires, and isolates by key.
- Integration: hit the route 6x in a loop, assert 200x5 then 429.
- Manual: confirm Retry-After decreases on repeated blocked calls.
## Risks / rollback
- Risk: Redis outage should fail OPEN (allow), not lock users out.
Wrap the check in try/catch; on error, log and permit the request.
- Rollback: remove the limiter call from route.ts; no schema change,
so revert is a single-file diff.
Acceptance Criteria Done Right
The acceptance criteria are the part of the spec file that actually earns its keep. They are the reviewer's contract: the set of statements that, if all true, mean the work is done, and if any is false, mean it is not. Written well, they turn code review from “re-read the whole diff and hope” into “walk the checklist.”
The single rule: every criterion must be checkable. Compare:
| Not a criterion (unverifiable) | A real criterion (checkable) |
|---|---|
| Login should be more secure | The 6th login POST from one IP within 60s returns 429 |
| Handle errors gracefully | On Redis error the request is permitted, not blocked |
| Good test coverage | fixedWindow() has unit tests for increment, expiry, isolation |
| Fast enough | The limiter adds under 5ms p95 to the login handler |
The left column reads fine and means nothing: no reviewer and no test can mark it true or false, so it silently becomes “whatever the agent decided.” The right column is a target the agent can verify against before you see the diff, and a checklist you can run against the PR. If a criterion is not checkable, it is not finished, either make it concrete or move it to the goal section as context.
Your AI workspace for shipping software.
Download AIDEN free and point it at your existing Claude Code or Codex setup. No credit card, running in minutes.
Download AIDEN freeFree to start · macOS 12+ · No credit card required
Where Spec Files Live, and How They Version
There are two good homes for a spec file, and the choice is mostly taste:
In the repo, under specs/
On the story card
The rule underneath both options: the spec versions with the code it describes. That is what makes it worth writing. Six months later, the spec attached to a merged PR tells you exactly what was decided and why, in a way a chat log almost never can. If you keep specs in-repo, the free story and spec templates give you consistent starting files, and the agent spec builder turns a short story into a filled-in draft you can drop straight into specs/.
Common Mistakes
Most bad spec files fail in one of four predictable ways. All are easy to fix once you can name them.
Spec Files in the Workflow
A spec file is not a document you write and file away, it is a working artifact that shows up three times in the life of a task, and each appearance is a payoff:
- 1
It feeds the agent
The approved spec becomes the agent's brief, the primary task context in its window. This is the highest-value lever in context engineering: a clean window plus a sharp spec beats a cluttered window with a clever prompt, every time. - 2
It gates approval
Reviewing and approving the spec, before any code exists, is the cheapest place to catch a misunderstanding. Two minutes on the spec routinely saves an hour of re-review on the diff. In a kanban flow the card sits in a spec-review column until you sign off. - 3
It becomes the PR review checklist
When the PR opens, the same acceptance criteria are the review checklist, and the spec ships as the PR description. Review is now “walk the list,” not “re-read the diff cold.” This is what makes PR automation trustworthy: the bot, or you, checks the diff against a written contract, not a memory.
The same file, three jobs. That reuse is why the spec file earns the few minutes it takes: it is the brief, the gate, and the checklist at once, and the guardrails that carry it across those stages are what a good agent harness provides.
How AIDEN Uses Spec Files
AIDEN's board is built around the spec file as the unit of work. Cards move through Project → Epic → Story → Spec: you write a one or two sentence story, and AIDEN drafts the full spec file, goal, scope, non-scope, affected files, acceptance criteria, from your card plus its analysis of your codebase. You review, edit anything that is off, and approve. Since v1.5.21 that approval is an enforced gate: no agent starts coding without an approved spec.
After approval, the same file does the rest of its jobs automatically. AIDEN opens a git worktree per story and launches your Claude Code or Codex CLI with the spec as the working prompt, you keep BYO inference, running your own subscriptions or keys. When the agent is done, the PR is one click from the card with the spec attached as the description, so the acceptance criteria are the review checklist. The spec you approved is the brief the agent worked from and the contract you review against, no retyping, no drift.
You can draft spec files this way outside the board too: the agent spec builder turns a short story into a filled-in spec, and the story and spec templates give you a consistent starting shape. AIDEN is a cockpit over the CLIs you already use, and it is $19/mo for Solo, free for one project, so the whole spec-first loop costs nothing to try.