My Claude Code a six-stage development pipeline.
When you hand a non-trivial task to a single coding agent, three failure modes show up almost every time. It skips planning and starts…
My Claude Code a six-stage development pipeline.

When you hand a non-trivial task to a single coding agent, three failure modes show up almost every time. It skips planning and starts editing. It “improves” things you never asked about and quietly expands scope. And it declares the work complete when half of it is still broken. One model wearing every hat tends to be a confident generalist with no checks on itself.
So I stopped using one agent. I built a six-stage gated pipeline where each stage has one job, one model, and one terminal verdict that decides whether the next stage even runs. The six stages are survey (Stage 0), plan (Stage 1), plan review (Stage 2), implement (Stage 3), implementation review (Stage 4), and finalize (Stage 5). Each stage from 1 onward stops and waits for me. Stage 0 has no gate — it feeds straight into Stage 1. Nothing advances on vibes — it advances on an explicit verdict and my approval.
This article walks through how it’s wired: the orchestrator, the model tiering, the agent frontmatter, the terminal contracts, the permission setup, and how to replicate the whole thing.
Architecture Overview
The orchestrator is a slash command, /pipeline <task>, that runs on the main model — claude-opus-4-8[1m], the 1M-context Opus variant. That long context matters: the orchestrator has to hold the original task, every stage’s output, and my feedback across the entire loop without losing the thread.
The orchestrator drives four core agents in strict order across six stages. Each agent ends its turn by emitting a terminal verdict string, and that string gates the next stage. A review that says the plan is good moves forward; a review that says it isn’t routes back. Three routing paths exist: a failed plan review goes back to the planner (at most 3 revisions); a failed implementation review with a localized finding goes back to the implementer to patch in place (at most 2 retries); a failed implementation review with a structural or architectural finding routes back to the planner to re-plan, then re-implements from scratch. The orchestrator delegates all heavy lifting to subagents to keep its own context window lean across the full multi-stage run.

Here’s the same flow as a sequence, showing who talks to whom and where the human gates sit:

Notice the orchestrator never edits anything itself — it only delegates, relays verdicts, and enforces the gates. All real work happens inside the subagents.
The Model-Tiering Strategy
Here’s the part that makes the pipeline efficient rather than six-times-Opus expensive. The pipeline uses two tiers: Opus for stages that require the highest-leverage reasoning, Sonnet for stages that execute and verify. The agent frontmatter uses an alias, and settings.json resolves the alias to a concrete model. The active session model is claude-opus-4-8[1m] (1M-context Opus), and the five entries in availableModels are claude-opus-4-6, claude-opus-4-7, claude-opus-4-8, claude-opus-4-8[1m], and claude-sonnet-4-6.
[embed]
The logic is: Opus to plan and review, Sonnet to implement and verify.
Planning and plan review are the highest-leverage, highest-reasoning steps — a bad plan poisons everything downstream — so both run on Opus. Once there’s an approved plan, implementation is mostly mechanical: apply the agreed edits, don’t freelance. That’s a job for Sonnet, which is capable and fast, and the tight plan keeps it on rails. Verification needs solid judgment but is also a structured comparison task — Sonnet reviews the diff against the plan and catches mistakes before they reach me.
The payoff: the expensive Opus model is reserved for the two stages where reasoning compounds most (planning and plan review), while Sonnet handles the two execution stages (implementation and verification). You get most of the quality of an all-Opus pipeline at significantly lower cost and latency.
One note on aliases: settings.json also defines a haiku alias (claude-haiku-4-5-20251001), but no core pipeline agent uses it — it is a configured-but-unused alias.
Inside an Agent Definition
Each agent is a Markdown file in ~/.claude/agents/: a YAML frontmatter header that configures the model and tools, followed by the system prompt that defines the agent’s behavior. The frontmatter is the contract with the harness; the body is the contract with the model.
Here’s the planner in full. Note the inline CSV tools line, the read-only toolset (no Edit/Write), and the fixed verdict string the orchestrator depends on:
---
name: planner
description: Creates detailed, step-by-step implementation plans for features,
refactors, and bug fixes. Use proactively at the start of any non-trivial
task, before any code is written.
tools: Read, Grep, Glob, Bash # <-- inline CSV form
model: opus
color: purple
---
You are a senior software architect. You PLAN ONLY. You never edit or write source files.
When invoked:
1. Run `git status` and `git diff` to understand current state.
2. Explore the relevant code with Read/Grep/Glob to ground the plan in reality.
3. Produce a detailed, numbered implementation plan.
Your plan MUST include:
- Goal: one-sentence summary of the desired outcome.
- Affected files/modules: explicit list of paths you expect to change or create.
- Step-by-step changes: ordered, each step small and independently verifiable.
- Risks & assumptions: edge cases, backward-compatibility, security concerns.
- Test strategy: how implementation will be verified.
- Out of scope: what you are deliberately NOT doing.
Constraints:
- Consider security and backward compatibility before proposing changes.
- Prefer the smallest change that fully solves the problem.
- Do NOT modify any files. Output the plan as Markdown only.
- End with: "PLAN COMPLETE — awaiting review."
The two reviewer agents follow the same shape but produce a graded verdict instead of a plan. Here’s the heart of the impl-reviewer — a checklist plus a forced verdict line:
---
name: impl-reviewer
description: Verifies that an implementation correctly and completely fulfills
the approved plan. Use immediately after the implementer finishes writing code.
tools: Read, Grep, Glob, Bash
model: sonnet
color: orange
---
You are a meticulous code reviewer and QA engineer. You verify an
implementation against its approved plan. You do NOT write or edit code.
When invoked:
1. Run `git diff` to see exactly what changed.
2. Read the approved plan provided to you.
3. Check the implementation against the plan, step by step.
Verification checklist:
- Completeness: was every plan step implemented? Anything missing?
- Correctness: does the code actually do what the plan intended?
- Scope: were any unplanned/unrelated changes introduced?
- Quality: clear naming, no duplication, proper error handling.
- Security: no exposed secrets or API keys, input validation present.
- Tests: adequate coverage; run the test suite / build / linter via Bash if available.
- Regressions: any risk to backward compatibility?
Report findings organized by priority:
- CRITICAL (must fix)
- WARNINGS (should fix)
- SUGGESTIONS (consider)
For each issue, cite the file/line and show how to fix it.
Then give an explicit verdict on its own line:
- "VERDICT: PASS" if the implementation fully satisfies the approved plan, or
- "VERDICT: FAIL" with a concise list of what must be corrected.
The implementer is the only agent that can mutate files — its frontmatter adds Edit, Write to the toolset — and its body forbids scope creep explicitly. It also carries a structural-fail rule: if re-invoked after a FAIL that cites a structural or architectural problem, it prefers scrapping the prior approach and re-implementing cleanly rather than patching the existing diff:
---
name: implementer
description: Implements an already-approved plan exactly as specified.
tools: Read, Edit, Write, Grep, Glob, Bash # <-- adds Edit, Write
model: sonnet
color: green
---
You are a careful implementation engineer. You execute an APPROVED plan.
When invoked:
1. Read the approved plan provided to you.
2. Implement each step in order, making the smallest correct change.
3. After each file change, briefly note which plan step it satisfies.
Rules:
- Follow the approved plan. Do NOT add scope or "improve" things beyond it.
- If you discover the plan is wrong or impossible, STOP and report the
discrepancy instead of improvising rather than guessing.
- Do not touch files outside the plan's "Affected files" list without flagging it.
- Keep changes minimal, readable, and consistent with existing code style.
- If you are re-invoked after a verification FAIL that cites a structural or
architectural problem (not a small localized fix), prefer scrapping the prior
approach and re-implementing the affected part cleanly — using everything the
failed attempt revealed — rather than patching the existing diff.
When finished:
- Summarize what changed, file by file.
- List any deviations from the plan and why.
- End with one of:
- "IMPLEMENTATION COMPLETE — ready for verification." or
- "IMPLEMENTATION BLOCKED — <state the discrepancy or obstacle and exactly
what you need (a plan fix, missing info, or access) to proceed>."
So the four core agents (planner, plan-reviewer, implementer, impl-reviewer) share a normalized shape: an alias model, a color for the terminal UI, and a CSV tools line. Only the implementer gets write access — every other stage is read-only by design, which is what makes “the reviewer literally cannot edit the code it’s reviewing” a structural guarantee rather than a polite request. Stage 0 uses built-in Exploresubagents (there is no explore.md) and Stage 5 uses the dead-code bonus agent — neither is a new core agent.
The two legacy agents look different
The bonus agents predate the pipeline. They use the YAML-list tools form, carry no color field, and pin a raw model ID instead of an alias:
---
name: dead-code
description: Finds unreferenced code and reports it.
model: claude-opus-4-6 # <-- raw ID, not an alias
tools: # <-- YAML-list form
- Read
- Grep
- Glob
---
Two formats coexist happily — worth knowing when you read these files, so the inconsistency doesn’t look like a bug.
The Gated Workflow and Terminal Contracts
The whole pipeline hinges on each agent ending with a verdict string the orchestrator can branch on. These are spelled out in the agent instructions:
- The planner finishes with
"PLAN COMPLETE — awaiting review." - The plan-reviewer returns
"VERDICT: APPROVED"or"VERDICT: NEEDS REVISION". - The implementer finishes clean with
"IMPLEMENTATION COMPLETE — ready for verification.", or emits the full BLOCKED string:"IMPLEMENTATION BLOCKED — <state the discrepancy or obstacle and exactly what you need (a plan fix, missing info, or access) to proceed>." - The impl-reviewer returns
"VERDICT: PASS"or"VERDICT: FAIL".
The orchestrator reads these and routes accordingly. NEEDS REVISION sends the plan back to the planner, capped at most 3 times. If three revisions still produce NEEDS REVISION, the orchestrator stops and surfaces the outstanding blockers with the convergence gate verbatim: “⚠️ Stage 2 did not converge after 3 revisions. How do you want to proceed? (give feedback / simplify scope / abort)”.
For FAIL verdicts at Stage 4, routing is dual: localized fixes (a missed step, a small correctness issue) go back to the implementer to patch in place; structural or architectural findings go back to the planner to re-plan with the reviewer’s diagnostics, then re-implement from the revised plan. Either path is capped at most twice. If the second retry still reads FAIL, the orchestrator stops with the Stage 4 convergence gate: “⚠️ Stage 4 did not converge after 2 retries. How do you want to proceed? (give feedback / revise plan / abort)”. On PASS, the orchestrator asks “Finalize?” before advancing to Stage 5.
If the implementer can’t proceed, it stops and says why rather than guessing — so a blocked implementation surfaces loudly instead of silently shipping a half-change.
Because the contract is just a string, the routing is deterministic and easy to reason about. There’s no hidden state deciding what happens next — the verdict is right there in the agent’s last message, and so is my approval gate.
The orchestrator command itself
The /pipeline command is just a Markdown file in ~/.claude/commands/. Its frontmatter declares a description and an argument-hint; its body uses $ARGUMENTS to inject whatever task you typed. Here’s the shape, lightly trimmed:
---
description: Run the full plan → verify-plan → implement → verify-implementation
pipeline, pausing for approval at every step.
argument-hint: <describe the task to accomplish>
---
You are orchestrating a 4-stage pipeline for the following task:
**Task:** $ARGUMENTS
Worth noting: the live pipeline.md header says “4-stage pipeline” — that line is stale and lags behind the six-stage body below it, which defines Stages 0 through 5. The rest of the file is current:
Delegate the heavy lifting to subagents at every stage — not only for review
quality, but to keep *your own* (the orchestrator's) context window lean so you
stay coherent across a long multi-stage run.
## Stage 0 — Survey the codebase (skip for trivial tasks)
- For any non-trivial task, dispatch one or more `Explore` subagents (in parallel)
to produce a short, plain-English architecture summary of the areas the task
touches: key files, existing patterns/utilities to reuse, and likely blast radius.
- For a trivial, well-scoped change (typo, one-line fix, rename), skip this stage.
- Pass the summary into the Stage 1 `planner` prompt so the plan is grounded
without the planner having to re-explore from scratch.
- This is read-only; no approval gate. Proceed directly to Stage 1.
## Stage 1 — Write the plan
- Delegate to the `planner` subagent to produce a detailed implementation plan.
- Show the full plan to the user verbatim.
- Then ask: "✅ Stage 1 (Plan) complete. Proceed to plan review? (proceed / give feedback)"
- STOP and wait for the user's reply.
## Stage 2 — Verify the plan
- Delegate to the `plan-reviewer` subagent, passing it the approved plan from Stage 1.
- If the verdict is "NEEDS REVISION", send the required changes back to the
`planner`, regenerate the plan, and re-review. Repeat this revise→re-review
cycle **at most 3 times**.
- If it still reads "NEEDS REVISION" after the third revision, STOP. Surface the
outstanding blockers and ask: "⚠️ Stage 2 did not converge after 3 revisions.
How do you want to proceed? (give feedback / simplify scope / abort)"
## Stage 3 — Implement the plan
- Delegate to the `implementer` subagent, passing it the APPROVED plan.
- Show a file-by-file summary of what changed and any deviations.
- Then ask: "✅ Stage 3 (Implementation) complete. Proceed to verification? (proceed / give feedback)"
- STOP and wait for the user's reply.
## Stage 4 — Verify the implementation
- Delegate to the `impl-reviewer` subagent.
- If the verdict is "FAIL":
- For **localized fixes**, send the required fixes back to the `implementer`
to patch in place.
- For **structural/architectural** findings, route back to the `planner` to
re-plan, then re-implement ("scrap it and implement the elegant solution").
- Re-verify after either path. Repeat **at most twice**.
- If it still reads "FAIL" after the second retry, STOP and ask:
"⚠️ Stage 4 did not converge after 2 retries.
How do you want to proceed? (give feedback / revise plan / abort)"
- Once it reads "VERDICT: PASS", ask: "Finalize? (proceed / give feedback)"
## Stage 5 — Finalize & capture learnings (after the user approves)
1. **Dead-code sweep (offered):** "Run a dead-code/duplication pass over the
changes? (yes / skip)" — run only if user accepts; surface findings, never
auto-delete.
2. **Self-improvement:** If corrections reflect a generalizable mistake class,
propose a single concise rule and offer to persist it. Ask before writing;
never edit CLAUDE.md/memory without explicit approval.
3. Report: "🎉 Pipeline complete. Summary of all changes: ..."
That last detail is the important one: the fix→re-verify loop is bounded at both seams. The orchestrator will bounce a NEEDS REVISION back to the planner at most 3 times, and a FAIL back to the implementer at most twice — then it stops and hands control back to me instead of grinding forever on a problem it can’t solve. The state machine looks like this:

Permissions as Convenience Tuning
settings.json also carries a permissions block, and it’s important to frame this honestly: it’s friction reduction, not a security sandbox.
defaultMode is set to plan, so a fresh session leans toward thinking before touching anything. The allow list is deliberately broad — git push, brew install, pip3 install, and wide Read globs — so I’m not approving the same routine commands all day. (The allow list is large and contains some visible duplicates; it’s grown organically.) The deny list blocks a handful of obvious footguns:
Read(./.env)
Read(./.env.*)
Read(./secrets/**)
Bash(rm -rf:*)
WebFetch(domain:*.internal)
Here’s the caveat that matters: those deny patterns are cwd-relative. Read(./.env) protects the .env in the current working directory — it does nothing for an absolute path elsewhere on disk. So treat this list as “stop me from fat-fingering the obvious,” not as a boundary that contains a determined or confused agent. It cuts approval prompts; it does not make the agent safe to run unattended.
The Plugin Ecosystem
The setup also leans on a small set of enabled plugins that round out the workflow:
claude-code-setup@claude-plugins-official— project scaffolding and setup automationcontext-mode@context-mode— in-session context management and sandbox executionfeature-dev@claude-plugins-official— structured feature development workflowssuperpowers@claude-plugins-official— expanded capabilities and toolingclaude-mem@thedotmack— cross-session memory persistence
They are orthogonal to the pipeline itself, but part of the same environment.
Bonus Agents, Kept Separate
The two legacy agents live outside the pipeline as standalone utilities you invoke directly, not stages in the loop.
dead-code scans for unreferenced code and reports it. It runs on raw model ID claude-opus-4-6, which is present in availableModels — not drift. It produces section-based output (no VERDICT line): ## Unused Exports, ## Orphaned Files, and ## Cleanup Candidates; it ends with “Be conservative. If uncertain, mark as ‘verify before removing.’” It surfaces candidates and never auto-deletes.
pr-summarizer drafts a PR summary from a diff and pins raw model ID claude-sonnet-4-5. That’s worth flagging: claude-sonnet-4-5 is not in the availableModels list in settings.json — genuine config drift. It still resolves, but it’s the kind of thing that quietly breaks when an old ID is eventually retired. Pinning raw IDs in one-off agents is convenient until it isn’t. Like dead-code, it produces section-based output (no VERDICT): ## What, ## Why, ## Changes, ## Testing; it ends with “Output ready to paste into GitHub. Nothing else.”
Takeaways — Replicate It
If you want this on your own machine, the moving parts are small:
- Create one Markdown file per agent in
~/.claude/agents/—planner.md,plan-reviewer.md,implementer.md,impl-reviewer.md— each with frontmatter (name,description,modelalias,color,tools) plus instructions that end in a fixed verdict string. - Create
~/.claude/commands/pipeline.mdas the orchestrator: adescriptionandargument-hintin frontmatter, and a body that uses$ARGUMENTSto run the six stages (0–5) in order with a stop-and-wait gate between each from Stage 1 onward. Stage 0 uses the built-inExploresubagent (noexplore.mdneeded) and has no gate. Stage 5 uses thedead-codebonus agent and offers the dead-code sweep before reporting complete. - Set the model aliases in
settings.jsonsoopusandsonnetresolve to the snapshots you want. Thehaikualias (claude-haiku-4-5-20251001) is defined but used by no core agent. - Run
/pipeline <task>and approve each gate as it comes.
This shines on non-trivial or risky changes — migrations, refactors, anything where a bad plan or a premature “done” costs you. For a one-line fix it’s overkill; just edit the file. The real win isn’t automation for its own sake. It’s that the six stages force a plan, make scope explicit, bound the review loops (≤ 3 plan revisions, ≤ 2 impl retries), and refuse to call anything finished until a separate reviewer agrees — with a human gate at every step.
메타데이터
- post_id
- cc7d19e5fdc9
- slug
- my-claude-code-a-four-stage-development-pipeline-cc7d19e5fdc9
- url
- https://medium.com/@vandrieiev/my-claude-code-a-four-stage-development-pipeline-cc7d19e5fdc9
- canonical_url
- https://medium.com/@vandrieiev/my-claude-code-a-four-stage-development-pipeline-cc7d19e5fdc9
- author_url
- https://medium.com/@vandrieiev
- status
- ok
- fetched_at
- 2026-08-19 09:19:56