A pipeline of single-purpose subagents that hand off through files on disk, with gates that re-run the checks and humans answering the product

I lead the frontend of a ~120k-line Next.js/TypeScript SaaS where agents write most of the code. The first thing I learned is that one long agent session that specs, designs and codes a feature drifts. Early decisions get lost, the context fills with file dumps, and small mistakes compound into a PR nobody wants to review.

So I stopped asking one agent to do everything. I built a pipeline in Claude Code where each stage is a separate subagent with one job, and the stages talk to each other through files on disk. The generic version is open source: agentic-feature-pipeline.

This post is about the split that makes it work: what the agents decide, and what stays with a human.

pipeline.png

The shape of the pipeline

/spec functional spec ─▶ repo-scout ─▶ flow-designer ─▶ tech-architect ─▶ impl-planner brief 01-user-flow 02-technical 03-steps ▲ human answers open questions /build 03-steps ─▶ step-runner × N (fresh context per step, verified + committed each) ─▶ draft PR 

Two commands, eight files' worth of handoff:

Stage Job Writes
repo-scout Find the real code to reuse. Read-only. 00-context-brief.md
flow-designer What the user sees and does, plus acceptance criteria 01-user-flow.md
tech-architect Files, types, data access, test plan 02-technical-definition.md
impl-planner Ordered steps, each with a self-contained prompt 03-implementation-steps.md
step-runner × N Implement exactly one step, code + tests commits

Each subagent also gets a narrow tool set. The scout can only Read, Grep and Glob. The flow designer can read and write documents but can't run commands. Only the runners touch code and run Bash, and only for the verification commands.

What the agents decide

Quite a lot, honestly:

  • Which existing code to imitate. The scout returns a brief of real paths: the closest screens, the data hooks, one representative test. Every path must exist because it opened it; if it couldn't find something, it goes under "Gaps" instead of being guessed.
  • The user flow details. States (empty, loading, error, success), edge cases, and acceptance criteria in Given/When/Then.
  • The technical design. Which files change, the exact types, which test covers which acceptance criterion.
  • How to split the work. The planner breaks the design into steps of usually 1–3 files, types and data access before UI, each leaving the project compiling.
  • The code itself, one step at a time. ## What I decide

Three things, and the pipeline is built so it can't skip them.

1. Product questions

The flow designer is told explicitly: do not resolve product decisions yourself; list them. After that stage, if 01-user-flow.md has open questions, the orchestrator stops and shows them to me:

## Human checkpoint After stage 2, if `01-user-flow.md` lists open questions, show them to the user and wait. Product decisions are not the pipeline's to make. Continue only with answers, recording them in 01 under "Decisions". 

This is the single most valuable rule in the whole thing. An agent will happily pick "sensible defaults" for what happens when a user has no permissions, or whether a filter persists across sessions. Those are product calls. Writing the answer into the file also means the next stages and the PR reviewer see the decision, not a guess.

2. Anything the backend doesn't confirm

The architect must mark any endpoint or field the backend doesn't provide yet as ASSUMED. Those assumptions travel all the way to the PR body, under "Needs confirmation". I've been bitten by an unverified assumption about what a backend field already included, and I'd rather see the list than discover it in production.

3. Whether the PR is good

The PR opens as a draft. Merging is still a human decision. The pipeline's job is to hand me a PR where every step already passed its checks, so my review is about design and product, not about whether it compiles.

Files are the interface

Stages don't share a conversation. Each subagent starts with a clean context and reads only the files it needs. That has three effects I didn't fully expect:

  1. Less drift. The implementer of step 5 never sees the 40 files the scout opened.
  2. Everything is reviewable. The brief, the flow, the design and the plan sit in a folder next to the code. A teammate can review the design before a single line is written.
  3. Restarts are cheap. If step 4 goes wrong, I fix 03-implementation-steps.md and rerun from there. ## Self-contained step prompts

The step prompts are where the pipeline lives or dies. The planner writes each one so a fresh agent can execute it with no other context. Every prompt must include, inline:

  • the goal in one sentence;
  • the exact files to create or change, and the ones not to touch;
  • the types and signatures it needs, copied in full;
  • one existing file to imitate, by path;
  • the tests to write and which acceptance criteria they cover;
  • the verification commands. And one rule I repeat to the planner: a step never says "as described above". The executor will not see anything above.

Gates, not trust

The step-runner reports its own verification results. The orchestrator ignores that report:

2. When it returns, re-run the step's "Done when" commands yourself. Trust the result, not the report. 3. Green → commit with `step N: <title>` and continue. Red → send the failure output back to `step-runner` once. Still red → stop, leave the branch as it is, and report which step failed and why. 

Stopping at the first red step matters more than it looks. The worst failure mode of an agent isn't a broken step; it's five more steps built on top of a broken one.

The runner also has a hard rule: fix the cause, never skip, weaken or delete a test to make it pass.

One conventions file

Every agent reads .claude/pipeline/conventions.md before doing anything: stack, where things go (with a reference example per kind of file), rules an agent would get wrong, and the verification commands. Those commands are what "done" means for every step:

typecheck: npx tsc --noEmit test: npx jest --findRelatedTests {files} lint: npx eslint {files} 

That's the only file that changes between repos. The agents are stack-agnostic.

Caveats

  • It's slower per feature than one chat session. Four documents before any code feels heavy for a one-line change. I use it for features, not for typos.
  • The plan can be wrong. /build executes; it doesn't reinterpret the architecture. If a step can't be done as written, it stops and says so. That's on purpose, but it means a bad 02 costs a rerun.
  • Gates are only as good as the tests. A green typecheck and related tests don't catch a wrong product behavior. That's why acceptance criteria are written before the design, and why E2E and a staging smoke test still happen after.
  • This is my workflow, not a benchmark. [COMPLETAR: si querés, sumar un dato propio, p. ej. cuántas features pasaron por el pipeline o cuántos PRs] ## Try it
claude plugin marketplace add diego-prieri/agentic-feature-pipeline claude plugin install feature-pipeline@agentic-feature-pipeline 

Copy the conventions template into .claude/pipeline/, fill in the verification commands, and run /spec on the example spec in examples/ticket-tracker/. There's also a /triage → /fix pair for bug lists, test-first, which I'll write about separately.

The repo is MIT-licensed: github.com/diego-prieri/agentic-feature-pipeline.

Where do you draw the line between what the agent decides and what you decide? I'd like to hear how other teams split it. Tell me in the comments.