The 3-Part Spec Contract: What to Write Before You Let the Agent Run

You prompt Claude Code with "add Google OAuth to the app." Forty-five minutes later, you have a technically correct implementation that uses a library you don't want, creates a database table you already have, and ignores your existing auth flow entirely.
The model did what you asked. The problem is what you didn't ask. The agentic spec contract exists to close that gap between your intent and the agent's interpretation.
Why prompts break down in agentic coding
A prompt is a request. A spec is a contract. The difference matters when the agent has write access to your codebase and can run commands without asking.
You describe the destination. The agent decides how to get there. Sometimes it decides well. Often it doesn't, and you spend more time correcting than you saved.
I've watched sessions where every correction spawned a new problem. The agent was solving the wrong problem with increasing conviction. Not because the model was bad. Because the input was thin. The agent didn't know I already had an auth utility. Didn't know the database schema was frozen this sprint. Didn't know the last person who touched that module spent a week getting the edge cases right.
A prompt can't carry all of this. The 3-part spec contract can.
The agentic spec contract: context, intent, constraints
The spec contract gives the agent three things before it writes a line of code. Each one closes a specific failure mode.
Context: what the agent needs to know
Context tells the agent what already exists and where to look.
Claude Code reads your file tree, your CLAUDE.md, and whatever files it decides to explore. But "decides to explore" is the problem. Without direction, it reads too much or too little. It finds an old pattern in a deprecated module and copies it. It misses the utility function that already does half the work.
Context in the spec means you point the agent at the right code before it starts exploring on its own.
Context:
- Auth lives in src/auth/. Session management uses iron-session.
- User model in src/models/user.ts already has an oauthProvider field.
- Existing flow to follow: src/auth/github-oauth.ts.Three lines. The agent knows where to look and which pattern to follow. Without this, it would have spent tokens exploring, possibly landed on the wrong pattern, and you'd have corrected it twice before arriving here.
Intent: what "done" looks like
Intent defines the verifiable end state. Not the feature name. What should exist when the work is finished and how you'll know it's correct.
Most prompts describe the feature: "add Google OAuth." A spec describes the outcome.
Intent:
- Google OAuth as a login option alongside GitHub OAuth.
- New Google users get an account. Existing users with matching
email get linked automatically.
- Existing tests pass. New test covers the Google callback handler.Intent has two jobs. It tells the agent what to build, and it gives the agent a target it can verify. That last line, the one about tests, turns a vague request into something the agent can converge on. Claude Code runs tests and iterates until they pass. Give it that loop and it closes without you.
The official Claude Code best practices say it directly: the most useful specs name the files and interfaces involved, state what is out of scope, and end with a verification step that proves the feature works.
Constraints: what stays off limits
Constraints define what the agent should not touch. Most people skip this part. It prevents the most rework.
Without constraints, the agent optimizes for the shortest path to your stated intent. That path might include installing a dependency you don't want or changing a database schema when you only needed an application-level change.
Constraints:
- No new npm dependencies. Use the existing next-auth setup.
- No database schema changes.
- Do not modify src/auth/session.ts.
- Scope: Google OAuth only. No refactoring existing flows.Every constraint is a correction you won't make mid-session. Unlike mid-session corrections, these don't consume context tokens or leave failed approaches cluttering the conversation history.
The assembled spec
Here's the full contract for the OAuth example:
## Context
- Auth: src/auth/. Sessions: iron-session.
- Pattern to follow: src/auth/github-oauth.ts.
- User model: src/models/user.ts (oauthProvider field exists).
## Intent
- Add Google OAuth alongside GitHub.
- New users via Google get a new account. Matching email auto-links.
- Existing tests pass. New test covers Google callback.
## Constraints
- No new npm deps. Use existing next-auth.
- No DB schema changes.
- Don't touch session config (src/auth/session.ts).
- PR scoped to Google OAuth only.Paste this into Claude Code directly, or write it to a SPEC.md file and start a fresh session with "implement the spec in SPEC.md." The fresh session gets clean context focused on execution. The spec survives across sessions even if context gets compacted.
I go deeper on the spec contract and how it fits into the explore-plan-implement loop in Chapter 3: The Human in the Loop of the agentic coding course.
When to skip the spec
Not every task needs one. If you can describe the diff in one sentence, prompt directly. The spec contract is for tasks where the agent has real decision-making latitude: multi-file changes, feature work, refactors that touch shared code.
The heuristic: if the wrong implementation would cost more than five minutes to fix, spend two minutes writing a spec. If you've prompted the same kind of task before and had to course-correct, that's the spec you should have written.
Plan mode is not a spec
Claude Code has built-in plan mode (Shift+Tab twice, or type /plan). Plan mode produces a plan inside a single conversation turn. The plan lives in memory. It doesn't survive compaction. It doesn't survive /clear.
A spec is a file on disk. It gets reviewed before execution starts. It persists across sessions. Plan mode is a tool you use inside the loop. The spec contract is the input you prepare before the loop begins.
Both have value. For complex work, I write the spec first, then use plan mode to let Claude validate it against the codebase before implementation starts. The spec defines the contract. Plan mode lets the agent figure out how to fulfill it.
The spec contract changed how I think about the boundary between human intent and agent execution. The frameworks in the agentic coding course are built from months of this exact workflow. Start the course.
Learn the agentic coding workflow
I use in production
How I set up my repos, manage context, and run agents in production. Written down so you can do the same.