Skip to content

Prompts vs Specs

A prompt and a spec are the same thing — a statement of intent — with one difference that changes everything: lifespan. A prompt governs one session and evaporates. A committed spec governs every future session, every teammate's agent, every re-run after a failed attempt, and every "wait, why does it work this way?" six months later. Treating them as interchangeable is the single most common process error in agent-assisted teams.

Why the lifespan difference dominates

When intent lives only in a prompt:

  • Re-runs drift. The second attempt at a feature gets a from-memory retelling of the requirements — close to the original, but not identical. You now have two slightly different sources of truth, one of which is gone.
  • Nobody else can operate. A teammate picking up the feature has the code and a chat transcript they'll never read. The decisions — why per-key rate limiting, why 429 over queuing — exist nowhere.
  • There's no arbiter. When the output looks wrong, "wrong relative to what?" has no answer. You review against your recollection, which the agent's fluent output actively reshapes.
  • Compaction eats it. On long sessions, Claude Code summarizes older conversation to reclaim context; your precisely-worded constraint from hour one survives as a paraphrase. See Context and Instruction Hierarchy.

A spec file has none of these problems, plus properties chat can never have: it's versioned, diffable, reviewable in a PR, and readable by the agent on demand in any session.

The escalation rule

If you've said it twice in chat, it belongs in a file.

Twice is the signal that the knowledge is durable, not task-scoped. Where it goes depends on its scope:

You keep repeating…Escalate to
A convention or invariant ("integer cents, never floats")Project CLAUDE.md — see CLAUDE.md and AGENTS.md
Feature requirements or acceptance criteriaA spec under specs/ or docs/specs/, committed
How a subsystem worksRepo docs — see Docs as Memory
Why an architectural choice was madeAn ADR — see Decision Records

After escalation, prompts shrink to pointers. That's the end state to aim for: files carry truth, prompts carry direction.

Weak vs strong: the same feature, two ways

Weak — the chat-only version:

text
Add CSV export to the invoices list. Include the usual columns, handle
big exports sensibly, and make it match how the rest of the app does
downloads.

Every load-bearing decision is delegated by vagueness: "usual columns" (which? localized headers? which date format — the EU customers filed a bug about this once), "big exports sensibly" (streaming? background job + email? row cap?), "how the rest of the app does downloads" (there are two patterns in the codebase; the agent will pick one). The agent ships something plausible. Three weeks later a teammate re-runs a variant of this prompt to add PDF export and gets different answers to all three questions. This is the six-silent-decisions problem in the wild.

Strong — committed spec plus pointer prompt. First, specs/invoice-csv-export.md (abridged):

markdown
# Spec: Invoice CSV export

## Behavior
- Export respects the *currently applied* list filters and sort.
- Columns: invoice_number, customer_name, issued_at (ISO 8601),
  due_at, status, total (integer cents), currency.
- Header row uses the user's locale via the existing i18n keys.

## Scale
- ≤ 10k rows: stream synchronously with chunked transfer.
- > 10k rows: enqueue export job (existing `jobs/` queue), email a
  signed download link, expire after 72h.

## Non-goals
- No XLSX. No column selection UI. No scheduled exports.

## Acceptance
- Export of a filtered list matches the on-screen rows exactly.
- 50k-row export completes without exceeding 256MB worker memory.

Then the prompt:

text
Implement specs/invoice-csv-export.md. Follow the download pattern in
src/exports/statements.ts, not the legacy one in src/reports/. List
any spec ambiguities before writing code.

The delta: every decision the weak prompt left to chance is now written, reviewable, and permanent. The prompt adds only session-scoped direction — which precedent to follow, and an instruction to surface ambiguity instead of resolving it silently. Re-runs, teammates, and next quarter's PDF-export task all inherit the same truth. Full spec-writing technique in Writing Effective Specs; complete worked examples in Spec Examples.

The spec-code feedback loop

A spec is not write-once. It's a control loop with the code:

The two failure edges matter equally. When verification fails because the code is wrong, you re-prompt — cheaply, because the spec didn't change. When it fails because the spec was wrong (you discover mid-build that 10k rows was the wrong threshold), you amend the spec first, then re-run — so the correction is permanent instead of living in one session's chat. Specs that stop receiving these updates go stale and start lying; Keeping Specs Alive covers the maintenance discipline.

When a prompt alone is fine

Not everything deserves a spec. Renames, one-file bug fixes with a reproducing test, mechanical refactors, research questions — the prompt is the whole intent, and it's checkable on sight. The threshold: would a second person, or a second session, ever need these decisions? No → prompt. Yes → file. When in doubt, count the silent decisions the agent would have to make; more than two or three, write the spec.

  • Specs over Prompts — the operational version of this argument: adopting spec-driven agent work on a real team.
  • Writing Effective Specs — structure, sizing, and the acceptance-criteria discipline.
  • Mental Models — prompt-as-temporary-spec and spec-as-source-of-truth in the layered control stack.
  • Prompt Anatomy — what still belongs in the prompt once specs carry the truth.
  • Context and Instruction Hierarchy — why chat-resident knowledge decays even within a single session.
  • Idea to Spec — the workflow for getting from a vague feature idea to a committed spec.

A field manual for AI-native software engineering.