Parallel Agent Refactor
Overview
A large refactor is fast and safe only when the work is sliced so that parallel write-agents never touch the same file. This skill is the orchestration discipline for that: partition by file ownership (not by topic), fan out one write-agent per independent slice, and put a barrier — a single typecheck + build + committed checkpoint — between every wave. The orchestrator owns the shared files, the spec, the verification, and the commits; the agents own disjoint file sets and return structured results, not conversation.
The whole value is a small set of invariants that make concurrency correct: disjoint ownership (no write race), barriers between waves (a consistent tree at every commit), and one shared house-rules spec (every agent produces the same house style). Break any one and you get corruption, red builds, or a stylistically incoherent diff. This method comes from a real Next.js/Tailwind redesign run with ~20 agents across five waves — all merged.
When to use
- "Adopt
<component library> across every route." / "Migrate all pages to the new primitives."
- "Do the dark-mode / design-token migration across the app."
- "Run this rename / codemod everywhere." / "Apply this rubric to every route/module."
- Per-route or per-module modernization where the app is roughly one file (or one folder) per route — the clean unit of ownership.
- Any breadth change that decomposes into independent file sets and is large enough that serial editing is the bottleneck.
When NOT to use this skill
- Interdependent foundation work — a shared config, a design-token layer, the app shell, tightly-coupled modules. Parallelizing these creates write races and inconsistent assumptions. Do them inline / single-agent, FIRST, as wave A. Fan-out comes after the foundation is committed.
- Trivial changes — a handful of files. The orchestration overhead (spec, waves, barriers) costs more than just doing it. Just do it.
- Work that can't be partitioned into disjoint file sets — if every slice needs to edit the same three shared files, you don't have parallelism; you have a queue. Restructure, or serialize.
Cardinal rules (these are the method)
- Partition by FILE OWNERSHIP, not by topic. Parallel writes are safe only when the agents' file sets are disjoint. In a one-file-per-route app, route-per-agent is the clean unit. Assign each file to exactly one owner before any agent starts.
- Single owner for shared / high-conflict files.
package.json, globals.css / the theme file, the app shell/layout, a README or route manifest — these get one owner (the orchestrator, or exactly one named agent), never two. Two agents editing package.json concurrently corrupt it.
- Read-only fan-out for discovery; disjoint-ownership fan-out for writes. Use cheap parallel read-only agents to map the codebase and draft the ownership plan. Only fan out writers once ownership is disjoint and the spec is frozen.
- Barriers BETWEEN waves, not within. A wave's agents run concurrently; the wave ends at a barrier where the orchestrator runs one verification (typecheck + build) and commits a checkpoint — then the next wave starts. Do not pipeline agent→agent (context bloat + latency + serialization); the orchestrator consumes structured returns and gates.
- One shared house-rules spec for every write-agent. Allowed classes/tokens, exact API-adaptation notes, forbidden patterns, and — for mechanical changes — a mapping table. Same spec in, same house style out. See
templates/house-rules-spec.md.
- Structured returns, not transcripts. Each agent returns
files-touched + what-changed (old→new) + anything-unsure. The orchestrator synthesizes. This keeps each agent's exploration noise out of the orchestrator's context.
- Right-size model / effort / tools per agent. Read-only agents get search+read only. Mechanical write-agents run cheaper / lower-effort with a turn cap. The hardest reasoning gets more budget. Don't pay Opus-at-max for a find-and-replace.
- Same-tree parallel is safe when ownership is disjoint — and it's cheaper. Reserve git worktrees only for the rare case where agents must touch a shared file concurrently (usually you avoid that with rule 2 instead).
Partition: the ownership model
Classify every file before you launch anything. Ownership determines who may write it and in which wave.
| File class |
Example |
Owner |
Parallel-safe? |
| Per-route leaf |
app/pricing/page.tsx, app/settings/page.tsx |
one write-agent each |
Yes — disjoint, fan out one agent/route |
| New primitive (new file) |
components/ui/select.tsx (didn't exist) |
one author per new file (or inline) |
Yes — creating distinct new files can't collide |
| Shared / high-conflict |
package.json, app/globals.css, app/layout.tsx, route manifest, README.md |
single owner (orchestrator or one named agent) |
No — never assign to two agents |
| Foundation / token layer |
Tailwind theme, CSS-var definitions, shared config |
orchestrator, inline, wave A |
No — everything depends on it; do it first |
Two hard tests before you fan out:
- Disjointness: union every agent's file list. Any file appearing twice is a race — reassign it to a single owner or move it to the shared-file bucket the orchestrator handles.
- Foundation-first: anything the leaves depend on (tokens, primitives they import, shared types) must be committed before the wave that consumes it. If a leaf agent needs a token that doesn't exist yet, it will invent one — and the outputs diverge.
Wave design (worked example)
Order waves by dependency: foundation → centralized value → parallel leaves → accelerators → parallel leaves. Each wave is behind a typecheck + build barrier and committed and pushed as a durable checkpoint. Real five-wave shape from the redesign (~20 agents total):
| Wave |
Purpose |
Shape |
Parallelism |
| A — Foundation |
Author new primitive files; establish the token layer FIRST |
1 agent per new file, or inline; token layer inline |
Low — foundation must land before anything reads it |
| B — Core value |
The centralized, high-value change everything else assumes |
Inline / single-agent |
None (deliberately serial) |
| C — Per-route component migration |
Swap each route onto the new primitives |
1 agent per route, concurrent |
High |
| D — Accelerators |
Shared helpers/hooks/utilities that make the leaf work easier |
Small fan-out or inline |
Medium |
| E — Per-route token/color migration |
Tokenize colors/dark-mode per route |
1 agent per route, concurrent |
High |
Full copy-paste wave plan with ownership lists and barrier commands: templates/wave-plan.md.
Per-wave barrier checklist (the orchestrator copies this into its own working notes and ticks it every wave — this is what stops a red tree being committed):
[ ] All agents in wave returned (completion notifications received)
[ ] Merged structured returns; noted every `anything-unsure`
[ ] Ran ONE typecheck (whole tree) — clean
[ ] Ran ONE build — clean
[ ] Ran post-wave cleanup greps (forbidden classes, invisible pairings — see Pitfalls)
[ ] Committed checkpoint + PUSHED
[ ] Only now: launch next wave
The shared house-rules spec
Write this once, before wave C, and hand the same file to every write-agent (plus a disjoint file list and one reference file to match house style). It is the difference between a coherent diff and twenty personal styles. It must contain:
- Allowed classes / tokens — the exact token names and utility classes agents may emit (
bg-primary, text-muted-foreground, …). Agents copy stock library snippets otherwise, and stock snippets reference vars your app doesn't define.
- Forbidden patterns — classes/APIs that silently do nothing or break in your target (see the Tailwind-v4 pitfall below). List them explicitly; agents won't infer them.
- Exact API-adaptation notes — call-site signatures for the new primitives, so every migrator adapts them identically (Radix handlers are not the native DOM API). The one that bites every route is in Pitfalls below; the full table lives in
templates/house-rules-spec.md §3.
- Pairing rules — foreground/background classes that must move together (a tokenized
bg-primary needs a token foreground, not a hardcoded text-white).
- A mapping table for mechanical changes — old → new, exhaustive, so a codemod agent has zero discretion.
text-gray-500 → text-muted-foreground, onChange → onValueChange (Select), etc.
Full annotated example: templates/house-rules-spec.md.
Orchestration mechanics (Claude Code)
- Fan out with the Agent tool, launching all of a wave's subagents in a SINGLE message — that is what makes them run concurrently as background subagents. Then wait for their completion notifications before doing anything at the barrier.
- The orchestrator runs the barrier, not an agent: one whole-tree typecheck, one build, one commit, one push. Never let two agents run typecheck/build concurrently — run exactly one verification, at the barrier.
- For deterministic multi-stage runs, drive the fan-out → barrier → fan-out structure through an orchestration/workflow harness (pipeline + parallel + barrier stages) so the structure is enforced by the harness rather than by hand.
- Custom subagents load
CLAUDE.md / AGENTS.md — tell every write-agent to honor project rules, and give it (1) a reference file to match house style, (2) its disjoint file list, and (3) the shared spec.
- Right-size each agent:
| Agent role |
Model / effort |
Tools |
Turn cap |
| Discovery (read-only fan-out) |
cheap / low |
search + read only, no write |
tight |
| Mechanical migrator (codemap-driven) |
cheap / low–mid |
read + edit on its file set |
capped |
| Reasoning migrator (nontrivial per-route) |
stronger / higher |
read + edit on its file set |
generous |
| Orchestrator (you) |
strongest |
full: edit shared files, run verify, git |
— |
Output
The agent → orchestrator return is structured (paste this shape into every write-agent's brief so returns are uniform and synthesizable):
FILES TOUCHED:
- path/to/a.tsx
- path/to/b.tsx
WHAT CHANGED (old → new):
- <file>: <concise before → after per change>
ANYTHING UNSURE:
- <ambiguity, deviation from spec, or thing the orchestrator must decide>
(empty if none)
The orchestrator's running artifact is a checkpoint log — one row per wave: wave id · agents launched · files owned · typecheck/build result · commit SHA (pushed) · unresolved anything-unsure items carried forward. That log is the recovery point: a context reset resumes from the last pushed checkpoint, never from scratch.
Pitfalls
- Fanning out primitive authorship before the token layer exists. Agents copy stock library code that references
bg-background, border-input, etc. — CSS vars your target never defined — and you ship dead styles. Establish the token layer FIRST (wave A), commit it, then author primitives against it.
- Tailwind v4 has no
tailwindcss-animate by default. animate-in, fade-in-*, zoom-in-*, data-[state=…]:animate-* classes silently produce nothing — no error, no warning. Agents copy them from stock shadcn snippets and think it worked. Forbid them in the spec and grep for them at the barrier.
- Radix API mismatch at call-sites.
Select → onValueChange(value) (not onChange(e)); Switch → onCheckedChange(boolean); empty-string SelectItem value is illegal (use "all"). One migrator gets it wrong per route unless the spec spells it out for all of them.
- Paired-class invisibility after a mechanical swap. A
text-white sitting next to a newly-tokenized bg-primary becomes white-on-near-white — invisible in dark mode, and no test catches it. Add pairing rules to the spec and run a cleanup grep after the wave (text-white, hardcoded hex, bg-white).
- Races on shared files. Two agents editing
package.json / globals.css / the layout corrupt it — enforce the single-owner rule (rule 2). The concurrent-verification race is the same failure: run one verification, at the barrier (rule 4).
- Stranded work / context loss. Un-pushed progress evaporates on a context reset. Commit AND push each verified wave as a durable checkpoint before starting the next.
- Committing a red tree. The barrier exists so the tree is consistent at every commit. If typecheck or build is red, fix at the barrier before committing — never start the next wave on a broken foundation.
- Pipelining agents. Chaining agent→agent balloons context and serializes what should be parallel. Agents return to the orchestrator; the orchestrator gates.
Combining with other skills
production-agent-audit — the read-only fan-out counterpart. This skill is its write/implement twin: same disjoint-fan-out + barrier discipline, applied to editing instead of analysis.
dark-mode-token-migration and shadcn-tailwind-v4-primitives — the concrete instances of waves A/E and the house-rules spec; use them for the domain specifics (which tokens, which primitives, the v4 gotchas) while this skill supplies the orchestration.
empirical-responsive-audit — verify each wave empirically (render + measure), not just typecheck+build, before you commit the checkpoint.
ux-decision-rubrics — the rubric a "apply this everywhere" fan-out distributes to every leaf agent so their judgment calls are consistent.
ui-ux-audit — run before (to source the backlog of routes/issues to fan out) and after (to confirm the sweep landed).
godaddy-api, other platform-ops skills — orthogonal; this skill is about how to parallelize edits, not what the edits are.
1---2name: parallel-agent-refactor3description: Orchestrate many parallel subagents to run a large multi-file refactor, migration, or codemod sweep SAFELY and fast — partition by disjoint file ownership, fan out one write-agent per independent slice behind typecheck+build barriers, and synthesize their structured returns. Use when adopting a component library across routes, migrating design tokens / dark mode, running a rename or codemod sweep, modernizing per-route, or applying one rubric across a whole codebase — any breadth change that decomposes into independent file sets. Not for interdependent foundation work (shared config, a token layer, coupled modules) — do that inline.4---56# Parallel Agent Refactor78## Overview9A large refactor is fast **and** safe only when the work is sliced so that parallel write-agents never touch the same file. This skill is the orchestration discipline for that: **partition by file ownership** (not by topic), **fan out one write-agent per independent slice**, and put a **barrier** — a single typecheck + build + committed checkpoint — between every wave. The orchestrator owns the shared files, the spec, the verification, and the commits; the agents own disjoint file sets and return **structured results**, not conversation.1011The whole value is a small set of invariants that make concurrency correct: **disjoint ownership** (no write race), **barriers between waves** (a consistent tree at every commit), and **one shared house-rules spec** (every agent produces the same house style). Break any one and you get corruption, red builds, or a stylistically incoherent diff. This method comes from a real Next.js/Tailwind redesign run with ~20 agents across five waves — all merged.1213## When to use14- "Adopt `<component library>` across every route." / "Migrate all pages to the new primitives."15- "Do the dark-mode / design-token migration across the app."16- "Run this rename / codemod everywhere." / "Apply this rubric to every route/module."17- Per-route or per-module modernization where the app is roughly **one file (or one folder) per route** — the clean unit of ownership.18- Any breadth change that **decomposes into independent file sets** and is large enough that serial editing is the bottleneck.1920## When NOT to use this skill21- **Interdependent foundation work** — a shared config, a design-token layer, the app shell, tightly-coupled modules. Parallelizing these creates write races and inconsistent assumptions. **Do them inline / single-agent, FIRST**, as wave A. Fan-out comes *after* the foundation is committed.22- **Trivial changes** — a handful of files. The orchestration overhead (spec, waves, barriers) costs more than just doing it. Just do it.23- **Work that can't be partitioned into disjoint file sets** — if every slice needs to edit the same three shared files, you don't have parallelism; you have a queue. Restructure, or serialize.2425## Cardinal rules (these are the method)261. **Partition by FILE OWNERSHIP, not by topic.** Parallel writes are safe **only** when the agents' file sets are **disjoint**. In a one-file-per-route app, **route-per-agent** is the clean unit. Assign each file to exactly one owner before any agent starts.272. **Single owner for shared / high-conflict files.** `package.json`, `globals.css` / the theme file, the app shell/layout, a README or route manifest — these get **one** owner (the orchestrator, or exactly one named agent), **never two**. Two agents editing `package.json` concurrently corrupt it.283. **Read-only fan-out for discovery; disjoint-ownership fan-out for writes.** Use cheap parallel read-only agents to map the codebase and draft the ownership plan. Only fan out writers once ownership is disjoint and the spec is frozen.294. **Barriers BETWEEN waves, not within.** A wave's agents run concurrently; the wave **ends at a barrier** where the orchestrator runs **one** verification (typecheck + build) and commits a checkpoint — **then** the next wave starts. Do **not** pipeline agent→agent (context bloat + latency + serialization); the orchestrator consumes structured returns and gates.305. **One shared house-rules spec for every write-agent.** Allowed classes/tokens, exact API-adaptation notes, forbidden patterns, and — for mechanical changes — a **mapping table**. Same spec in, same house style out. See `templates/house-rules-spec.md`.316. **Structured returns, not transcripts.** Each agent returns `files-touched` + `what-changed` (old→new) + `anything-unsure`. The orchestrator synthesizes. This keeps each agent's exploration noise out of the orchestrator's context.327. **Right-size model / effort / tools per agent.** Read-only agents get search+read only. Mechanical write-agents run cheaper / lower-effort with a turn cap. The hardest reasoning gets more budget. Don't pay Opus-at-max for a find-and-replace.338. **Same-tree parallel is safe when ownership is disjoint** — and it's cheaper. Reserve **git worktrees** only for the rare case where agents must touch a shared file concurrently (usually you avoid that with rule 2 instead).3435## Partition: the ownership model36Classify every file **before** you launch anything. Ownership determines who may write it and in which wave.3738| File class | Example | Owner | Parallel-safe? |39|---|---|---|---|40| Per-route leaf | `app/pricing/page.tsx`, `app/settings/page.tsx` | one write-agent each | **Yes** — disjoint, fan out one agent/route |41| New primitive (new file) | `components/ui/select.tsx` (didn't exist) | one author per new file (or inline) | **Yes** — creating distinct new files can't collide |42| Shared / high-conflict | `package.json`, `app/globals.css`, `app/layout.tsx`, route manifest, `README.md` | **single owner** (orchestrator or one named agent) | **No** — never assign to two agents |43| Foundation / token layer | Tailwind theme, CSS-var definitions, shared config | orchestrator, inline, **wave A** | **No** — everything depends on it; do it first |4445Two hard tests before you fan out:46- **Disjointness:** union every agent's file list. Any file appearing twice is a race — reassign it to a single owner or move it to the shared-file bucket the orchestrator handles.47- **Foundation-first:** anything the leaves *depend on* (tokens, primitives they import, shared types) must be **committed** before the wave that consumes it. If a leaf agent needs a token that doesn't exist yet, it will invent one — and the outputs diverge.4849## Wave design (worked example)50Order waves by **dependency**: foundation → centralized value → parallel leaves → accelerators → parallel leaves. Each wave is behind a **typecheck + build barrier** and committed **and pushed** as a durable checkpoint. Real five-wave shape from the redesign (~20 agents total):5152| Wave | Purpose | Shape | Parallelism |53|---|---|---|---|54| **A — Foundation** | Author new primitive files; **establish the token layer FIRST** | 1 agent per new file, or inline; token layer inline | Low — foundation must land before anything reads it |55| **B — Core value** | The centralized, high-value change everything else assumes | Inline / single-agent | None (deliberately serial) |56| **C — Per-route component migration** | Swap each route onto the new primitives | **1 agent per route**, concurrent | **High** |57| **D — Accelerators** | Shared helpers/hooks/utilities that make the leaf work easier | Small fan-out or inline | Medium |58| **E — Per-route token/color migration** | Tokenize colors/dark-mode per route | **1 agent per route**, concurrent | **High** |5960Full copy-paste wave plan with ownership lists and barrier commands: `templates/wave-plan.md`.6162**Per-wave barrier checklist** (the orchestrator copies this into its own working notes and ticks it every wave — this is what stops a red tree being committed):63```64[ ] All agents in wave returned (completion notifications received)65[ ] Merged structured returns; noted every `anything-unsure`66[ ] Ran ONE typecheck (whole tree) — clean67[ ] Ran ONE build — clean68[ ] Ran post-wave cleanup greps (forbidden classes, invisible pairings — see Pitfalls)69[ ] Committed checkpoint + PUSHED70[ ] Only now: launch next wave71```7273## The shared house-rules spec74Write this once, before wave C, and hand the **same file** to every write-agent (plus a disjoint file list and one reference file to match house style). It is the difference between a coherent diff and twenty personal styles. It must contain:7576- **Allowed classes / tokens** — the exact token names and utility classes agents may emit (`bg-primary`, `text-muted-foreground`, …). Agents copy stock library snippets otherwise, and stock snippets reference vars your app doesn't define.77- **Forbidden patterns** — classes/APIs that **silently do nothing** or break in your target (see the Tailwind-v4 pitfall below). List them explicitly; agents won't infer them.78- **Exact API-adaptation notes** — call-site signatures for the new primitives, so every migrator adapts them identically (Radix handlers are **not** the native DOM API). The one that bites every route is in Pitfalls below; the full table lives in `templates/house-rules-spec.md` §3.79- **Pairing rules** — foreground/background classes that must move together (a tokenized `bg-primary` needs a token foreground, not a hardcoded `text-white`).80- **A mapping table** for mechanical changes — old → new, exhaustive, so a codemod agent has zero discretion. `text-gray-500 → text-muted-foreground`, `onChange → onValueChange` (Select), etc.8182Full annotated example: `templates/house-rules-spec.md`.8384## Orchestration mechanics (Claude Code)85- **Fan out with the Agent tool, launching all of a wave's subagents in a SINGLE message** — that is what makes them run concurrently as background subagents. Then **wait for their completion notifications** before doing anything at the barrier.86- **The orchestrator runs the barrier**, not an agent: one whole-tree typecheck, one build, one commit, one push. **Never let two agents run typecheck/build concurrently** — run exactly one verification, at the barrier.87- **For deterministic multi-stage runs**, drive the fan-out → barrier → fan-out structure through an orchestration/workflow harness (pipeline + parallel + barrier stages) so the structure is enforced by the harness rather than by hand.88- **Custom subagents load `CLAUDE.md` / `AGENTS.md`** — tell every write-agent to **honor project rules**, and give it (1) a reference file to match house style, (2) its **disjoint** file list, and (3) the shared spec.89- **Right-size each agent:**9091| Agent role | Model / effort | Tools | Turn cap |92|---|---|---|---|93| Discovery (read-only fan-out) | cheap / low | search + read only, **no write** | tight |94| Mechanical migrator (codemap-driven) | cheap / low–mid | read + edit on its file set | capped |95| Reasoning migrator (nontrivial per-route) | stronger / higher | read + edit on its file set | generous |96| Orchestrator (you) | strongest | full: edit shared files, run verify, git | — |9798## Output99The **agent → orchestrator return** is structured (paste this shape into every write-agent's brief so returns are uniform and synthesizable):100```101FILES TOUCHED:102- path/to/a.tsx103- path/to/b.tsx104WHAT CHANGED (old → new):105- <file>: <concise before → after per change>106ANYTHING UNSURE:107- <ambiguity, deviation from spec, or thing the orchestrator must decide>108 (empty if none)109```110The **orchestrator's running artifact** is a checkpoint log — one row per wave: wave id · agents launched · files owned · typecheck/build result · commit SHA (pushed) · unresolved `anything-unsure` items carried forward. That log is the recovery point: a context reset resumes from the last pushed checkpoint, never from scratch.111112## Pitfalls113- **Fanning out primitive authorship before the token layer exists.** Agents copy stock library code that references `bg-background`, `border-input`, etc. — CSS vars your target never defined — and you ship dead styles. **Establish the token layer FIRST** (wave A), commit it, then author primitives against it.114- **Tailwind v4 has no `tailwindcss-animate` by default.** `animate-in`, `fade-in-*`, `zoom-in-*`, `data-[state=…]:animate-*` classes **silently produce nothing — no error, no warning**. Agents copy them from stock shadcn snippets and think it worked. **Forbid them in the spec** and grep for them at the barrier.115- **Radix API mismatch at call-sites.** `Select` → `onValueChange(value)` (not `onChange(e)`); `Switch` → `onCheckedChange(boolean)`; empty-string `SelectItem` value is illegal (use `"all"`). One migrator gets it wrong per route unless the **spec** spells it out for all of them.116- **Paired-class invisibility after a mechanical swap.** A `text-white` sitting next to a newly-tokenized `bg-primary` becomes white-on-near-white — **invisible in dark mode**, and no test catches it. Add **pairing rules** to the spec **and** run a **cleanup grep** after the wave (`text-white`, hardcoded hex, `bg-white`).117- **Races on shared files.** Two agents editing `package.json` / `globals.css` / the layout corrupt it — enforce the **single-owner rule** (rule 2). The concurrent-verification race is the same failure: run **one** verification, at the barrier (rule 4).118- **Stranded work / context loss.** Un-pushed progress evaporates on a context reset. **Commit AND push each verified wave** as a durable checkpoint before starting the next.119- **Committing a red tree.** The barrier exists so the tree is consistent at every commit. If typecheck or build is red, **fix at the barrier before committing** — never start the next wave on a broken foundation.120- **Pipelining agents.** Chaining agent→agent balloons context and serializes what should be parallel. Agents return to the **orchestrator**; the orchestrator gates.121122## Combining with other skills123- `production-agent-audit` — the **read-only** fan-out counterpart. This skill is its **write/implement** twin: same disjoint-fan-out + barrier discipline, applied to editing instead of analysis.124- `dark-mode-token-migration` and `shadcn-tailwind-v4-primitives` — the **concrete instances** of waves A/E and the house-rules spec; use them for the domain specifics (which tokens, which primitives, the v4 gotchas) while this skill supplies the orchestration.125- `empirical-responsive-audit` — **verify each wave** empirically (render + measure), not just typecheck+build, before you commit the checkpoint.126- `ux-decision-rubrics` — the rubric a "apply this everywhere" fan-out distributes to every leaf agent so their judgment calls are consistent.127- `ui-ux-audit` — run before (to source the backlog of routes/issues to fan out) and after (to confirm the sweep landed).128- `godaddy-api`, other platform-ops skills — orthogonal; this skill is about *how* to parallelize edits, not *what* the edits are.