Spec-First Workflow for AI Agent Teams
Most teams did not decide to become AI agent teams. One developer adopted a coding agent, another wired one into CI, and within a quarter half the pull requests were machine-written. The code arrives faster than anyone can decide what should be built or verify what was built. A spec-first workflow fixes that imbalance: it moves the human effort to the two places agents cannot replace, deciding intent and reviewing evidence.
spec.md, tasks.md, acceptance criteria, and evidence requirements before agents implement anything.
The bottleneck moved, the workflow did not
Before coding agents, the slowest step in delivery was implementation, so processes optimized for developer throughput. With agents, implementation is close to free, and two other steps become the constraint: deciding exactly what to build, and confirming the result matches that decision. Teams that keep their old workflow feel this as a specific kind of pain. Pull requests pile up faster than reviewers can read them. Two agents solve overlapping problems in incompatible ways. A prompt that lived only in one developer's chat session produced a product decision nobody approved.
The failure is not the agents. It is that the team's intent exists nowhere an agent, or a reviewer, can check. Chat transcripts are not reviewable, not reusable, and not comparable against the final diff. The spec-first answer is to make intent durable: before any agent writes code, the team writes a small set of artifacts, and every later stage checks its output against them.
The five-stage workflow at a glance
The workflow below assumes nothing about which agent you run. It works with Claude Code, Cursor, Copilot coding agents, or a mix, because the contract lives in files, not in any tool's memory.
| Stage | Owner | Artifact | Gate to pass |
|---|---|---|---|
| 1. Intake | Feature owner | spec.md packet | Goal, non-goals, and acceptance criteria approved by a human |
| 2. Task split | Tech lead or planning agent | tasks.md | Every task has a write scope and a verifiable outcome |
| 3. Implementation | One agent per task | Branch or worktree diff | Diff stays inside the task's write scope |
| 4. Evidence | Same agent | evidence.md | Tests, logs, and checks named in the spec exist and pass |
| 5. Review | Human reviewer | PR with linked artifacts | Checklist review against criteria, not against vibes |
Stage 1: turn the ticket into a spec packet
Everything downstream inherits the quality of this step, and it is the step teams most want to skip. The input is usually a ticket like "let support admins retry failed exports." The output is a one-page packet that fixes four things: the goal in observable terms, the non-goals that bound the change, acceptance criteria a test can check, and the evidence a reviewer will demand.
Write it before choosing which agent implements it. The packet is where product ambiguity gets resolved by a person instead of leaking into an agent's assumptions. If you have never written one, the spec packet generator produces the skeleton from a plain-language description, and the spec packet guide walks through each section. The discipline that matters most is non-goals: "no schema changes, no email template edits, no new dependencies" removes the three most common ways agents helpfully expand scope.
Stage 2: split the spec into bounded tasks
A spec packet is still too big to hand to one agent as one prompt. The reliable unit of agent work is a task that a single agent can complete, and a single human can review, in one sitting. Splitting is where a lead earns their title in an agent team: the split decides what can run in parallel and what must serialize.
Each task in tasks.md needs three fields beyond its description. A write scope listing the files the agent may modify. Acceptance criteria copied or derived from the packet. An evidence requirement naming the test or check that proves completion. The SDD tasks plan template gives you this structure ready to fill in.
Task 2 of 3: add retry endpoint Write scope: - src/exports/retry.ts - src/exports/retry.test.ts Depends on: task 1 (retry state column) merged. Acceptance: - POST /api/exports/:id/retry on a failed export returns 202 and the same retry_id on duplicate calls - retrying a non-failed export returns 409 Evidence: - test: export_retry_idempotent - test: export_retry_wrong_state_conflict
Tasks that share files must not run in parallel. If two tasks both need to touch billing/index.ts, either merge them into one task or serialize them explicitly with a dependency line. Merge conflicts between agents are not a tooling problem; they are a task-splitting problem.
Stage 3: run agents in parallel inside write scopes
With bounded tasks, parallelism becomes safe and boring, which is the goal. Give each agent one task, its packet, and an isolated branch or git worktree. The write scope in the task is the enforcement line: an agent that edits a file outside its scope has its diff rejected before review, no discussion needed. Most modern agents respect an instruction like "modify only the files listed under write scope; if the task requires touching anything else, stop and report instead of editing."
That stop-and-report clause matters more than it looks. The most expensive agent failure is not a wrong implementation; it is a quiet decision, an extra column, a renamed function, a new dependency, buried in an otherwise plausible diff. Scope enforcement converts those quiet decisions into loud questions a human answers in seconds.
Stage 4: collect evidence before requesting review
An agent's claim that work is complete is worth nothing; the artifact chain is what makes completion checkable. Before a task's PR is opened, the same agent fills in evidence.md: which named tests were added and their pass output, which acceptance criterion each test covers, and any logs, screenshots, or contract checks the packet demanded. The SDD evidence log template keeps the format consistent across agents so reviewers stop re-learning each PR's shape.
Evidence is also where hallucinated completeness dies. An agent that says "all tests pass" but cannot paste the run output for export_retry_idempotent has not finished. Teams that adopt test-evidence gates report that the gate catches more bad merges than the code review itself, because it is mechanical: the named test either exists and passes or it does not.
Stage 5: review the PR against the checklist
Human review is the scarcest resource in the whole system, so spend it only on what the earlier gates cannot check: does the diff match the intent, and did anything unstated slip in? The AI coding PR review checklist structures this pass. The reviewer confirms the diff stays in scope, maps each change to a task, spot-checks the evidence, and looks specifically for the changes no task asked for.
Reviews get faster as the artifacts get better. When a reviewer can see the criterion, the test, and the diff side by side, approving a bounded task takes minutes. When any of the three is missing, the review degenerates into re-deriving the spec from the code, which is the exact work the workflow exists to eliminate.
Worked example: one feature, three agents
Here is the shape of a real run. The feature: "support admins can retry a failed data export." The packet fixes the policy (admins only, one retry at a time, no schema redesign) and the evidence bar (idempotency test, audit log entry, no changes to export file format).
spec: exports/retry-failed-export/spec.md
tasks:
1. retry state column + migration agent A, scope: db/migrations, models/export.ts
2. retry endpoint + idempotency agent B, scope: src/exports/retry.ts + test
3. admin console retry button agent C, scope: console/exports/*.tsx + test
serialization: task 1 merges first; tasks 2 and 3 then run in parallel
review: one human, three PRs, checklist pass each,
total review time ~40 minutes for the feature
The instructive failure in this run: agent B added a helpful retry_count column to the model, outside its write scope. The scope check flagged it before review. The team decided a count was genuinely useful, wrote it into the packet as a follow-up task, and rejected the out-of-scope edit. That is the workflow doing its job: the good idea survived, the unreviewed decision did not.
What to measure in the first 30 days
Adopt the workflow on one feature stream, not the whole team, and measure three numbers. Review time per agent PR: it should fall week over week as artifacts standardize. Out-of-scope edits caught before review: it should be non-zero early (the gate is working) and decline later (the prompts are learning). Rework rate, meaning PRs that needed a second implementation pass after review: this is the number that justifies the process to skeptics. The 30-day adoption plan covers the rollout sequencing, and the pattern comparison in OpenSpec vs Superpowers vs Spec Kit shows where these stages come from if you want the deeper lineage.
Failure modes to expect
| Symptom | Root cause | Fix |
|---|---|---|
| Agents produce conflicting diffs | Tasks share files | Re-split so write scopes are disjoint, or serialize with dependency lines |
| Packets take longer than implementation | Packet scope too large | One packet per reviewable feature slice, not per epic |
| Evidence logs turn into boilerplate | Criteria not testable | Rewrite acceptance criteria as observable outcomes before splitting |
| Reviewers rubber-stamp green checklists | Checklist replaced judgment instead of focusing it | Reviewer owns the "what did nobody ask for?" question on every PR |
The steady state is unglamorous: specs are short, tasks are boring, agents are interchangeable, and review is fast. That is what it looks like when the humans spend their time on intent and evidence, and the machines spend theirs on everything in between.