The state of the codebase
Turborepo. apps/web is a Vite + React SPA. After a year of “I’ll clean this up later,” several files had become unreviewable. The product-form component had three thousand lines of conditional rendering. api/types.ts had become a kitchen sink for every type the frontend touched. The reservation page had a charge-dialog, a refund-dialog, a rebook-dialog, and an add-on manager all in one file. The shape of the code wasn’t bad. There was just too much of it living in too few files.
The skill
/refactor-split is a custom skill that does multi-agent file-by-file refactoring. The interface is one command and a target list. Under the hood it runs a strict three-phase wave pattern.
The run
I gave the orchestrator the list of files. Twenty-one distinct subagents got spawned. The recovery row — B1 second pass: extract JSX cards — is the interesting one. The first execute pass on ReservationChargeDialog left some JSX cards inlined that should have been their own files. The orchestrator noticed during the analyze-pass of validation and re-spawned a targeted second-pass agent for just that file. Clean self-healing.
agent network · 3 phased waves · 21 agents · 17 files
File-by-agent ownership
Ownership is the orchestration trick. Everything else is a rounding error.
— Brett Ridenour
What a split plan looks like
The analyze wave doesn’t write code — it writes a plan for the execute agent to follow. One per file. Strict shape.
# File: pages/reservations.tsx (1,900 LOC)
## Proposed split
- pages/reservations.tsx → page shell only (~150 LOC)
- components/reservations/ReservationsTable.tsx → list view
- components/reservations/ReservationsFilters.tsx → filter UI
- components/reservations/ReservationsBulkActions.tsx → bulk ops
- hooks/useReservationsQuery.ts → data fetching
- types/reservations.ts → local types
- lib/reservations-helpers.ts → pure functions
## Ownership rule
One agent owns this file end-to-end. Do not touch any other file
in this PR except imports updated by the agent's own extractions.
## Validation
After split, run `npm run typecheck && npm run lint && npm run build`.
Confirm pages/reservations.tsx is under 250 LOC.
Confirm no orphaned imports.
Why no merge conflicts
Each agent’s blast radius is exactly one file. Two agents never touch the same file. The orchestrator coordinates by a written plan — not by chat between agents. That single rule (one file per agent, plan-mediated coordination) does all the work.
Lessons
- Ownership is the orchestration trick. One file per agent → zero merge conflicts. Everything else is a rounding error.
- Phased waves beat parallel free-for-all. Analyze first. Execute next. Validate last. Don’t skip a wave.
- Recovery is built in. A failed slice doesn’t poison the run — re-spawn one targeted agent for that slice with a sharper prompt.
- The orchestrator is a plan doc, not a chat. Agents coordinate by a written plan all of them can read. Not by talking to each other.
I never opened a single one of the files.
Related work
- 23 Agents, 11 PRDs, 1 Goal File — the upstream pattern: write the brief, then fan out. This refactor was a sub-task inside one of those
/goalruns. - 100 Agents, 88 Million Tokens, $313 — what the same pattern looks like when the work is content critique instead of code.
References & further reading
- Anthropic — Claude Code subagents — official docs on the subagent system the
/refactor-splitskill uses. - Anthropic — Skills — how custom slash-command skills like
/refactor-splitare defined. ccusage— for tracking token spend on multi-hour refactor runs.- Vite + React — the frontend stack the 17 split files live in.
- Sixteen Tests, Five Branches, Zero Standups — the same Claude Code setup applied to autonomous feature builds.