| name | batch |
| description | Use when a plan or spec splits into many independently-mergeable units — a codebase-wide migration, rename, or repeated pattern change — and the user wants them implemented in parallel as separate PRs rather than one sequential pass. The fan-out alternative to afk:implement. |
Batch
Batch is the parallel, PR-per-unit way to implement a plan. Where afk:implement
drives one working tree through sequential TDD slices, Batch decomposes the work
into many independent units and farms each out to its own worker in
its own git worktree. Each worker implements, simplifies, tests, and opens a PR
on its own branch.
Core principle: only fan out units that are genuinely independent — each one
mergeable on its own with no shared contract still being designed. If the units
collide on a shared abstraction, this is the wrong skill; use afk:implement's
freeze-then-fan-out recipe instead.
When to Use
Use this skill when:
- A
brain/plans/<slug>.md plan from afk:grill, or a clear spec, breaks into
5–30 units that can each land as a standalone PR.
- The work is a codebase-wide migration, rename, dependency bump, lint-rule
rollout, or the same pattern change applied across many files or packages.
- The user asks to "batch", "fan this out", "parallelize this across the repo",
or wants many small PRs instead of one large change.
Do not use this skill for:
- Work that needs a shared interface, type, or component designed first and then
applied at call sites — that shared contract makes the units dependent. Use
afk:implement (it owns the freeze-then-fan-out recipe).
- A single feature, bug fix, or change that lives in one or two coupled files.
Use
afk:implement.
- Producing one reviewed working-tree diff with no PRs. Use
afk:implement or
afk:ship.
Process
1. Ground and scope
Read the plan or spec. Dispatch read-only scouts (or read directly) to map every
affected file, call site, and pattern. You must know the full blast radius before
decomposing — a missed call site becomes a unit nobody owns.
2. Decompose into independent units
Split the work into 5–30 units. Each unit must be:
- Independently mergeable — its PR can land alone, in any order, without
waiting on another unit.
- Non-overlapping — no two units edit the same file. Overlap is the signal
the work is dependent; merge those units into one or stop and re-scope.
- Self-verifiable — has a concrete check (unit tests, a build, a curl, a
browser step) proving it works in isolation.
- A complete vertical slice — one end-to-end behavior with its test and
implementation together. Never make a unit a test-only or implementation-only
PR; "independently mergeable" does not make a horizontal slice acceptable.
If a clean independent split is not possible, STOP — see Stop and Ask.
3. Write the plan and get approval
Write a numbered unit list: for each unit, its files, the exact change, and its
verification recipe. State the shared verification every worker runs (the
project's test command from CLAUDE.md) and the per-unit e2e recipe. Present
this plan to the user and wait for approval before spawning any worker.
4. Spawn one worker per unit, in parallel
After approval, launch one worker per unit with isolation: "worktree" (its own
git worktree) by sending all the Agent calls in a single message — the harness
runs them concurrently. Do not run the workers in background mode: a
background subagent auto-denies any tool call that would otherwise prompt, so a
worker's Bash verification (the test command, the e2e recipe, gh pr create)
fails silently and the worker reports a green PR it never proved. Synchronous
concurrent workers keep those prompts answerable — that review-each-result model
is the safety mechanism (see docs/skills-and-agents-reference.md).
Every worker brief is fully self-contained (subagents start with zero context).
Each must include:
- The unit's exact files, the change to make, and files to read first.
- Code conventions to follow, with a concrete file to mimic.
- The local loop to run, in order: implement the smallest correct change, then
run the project test command and fix failures, then the unit's e2e recipe.
- Hard boundaries: edit only this unit's files, no neighboring refactors, no new
dependencies, no renames outside the brief.
- The finish, in order: if the unit's diff is substantial — multi-line logic,
a new file, an extraction, or a non-trivial rewrite — run
afk:simplify on it
and re-run the test command so the PR carries cleaned-up, still-passing code;
skip simplify when the change is a trivial one-liner (a version bump, a string
or constant edit, a rename) where there is nothing to clean up. Then commit,
push the branch, open a PR with gh pr create, and report back the single line
PR: <url> (or BLOCKED: <reason>).
5. Track progress to a status table
Maintain a status table of every unit: number, summary, state (PR open / failed
/ blocked), and PR link. Fill it in as each worker returns its result. Do not
invent a PR link or a pass a worker did not report.
6. Report and triage
When all workers settle, give the final tally (e.g. "22/24 units landed as PRs")
and list every failed or blocked unit with its reason. For a small number of
failures, re-dispatch once with the specific correction; if a unit fails twice,
finish it in the lead and say so.
Stop and Ask
STOP and ask the user when:
- The units are not actually independent — they share an interface, type, or file
still being designed. Recommend
afk:implement and its freeze-then-fan-out
recipe instead of forcing a parallel split.
- Two units would need to edit the same file. That is a dependency, not a
parallelism opportunity.
- The change is a migration, security-sensitive, or destructive, and the safe
per-unit boundary is unclear.
- PR creation, branch naming, or the target remote depends on a convention the
repo does not state.
Decompose and decide boundaries yourself from the plan and repo; ask only for the
missing decision or for approval before the spawn in step 3.
Red Flags
| Thought | Reality |
|---|
| "I'll fan these out even though they touch the same file." | Same-file edits are dependent. Merge into one unit or route to afk:implement. |
| "There's a shared component to build first, but workers can figure it out." | Then you've delegated architecture across N parallel agents. Freeze the contract in the lead first — that's afk:implement, not batch. |
| "I'll spawn the workers now and confirm the plan after." | Spawning is expensive and creates branches/PRs. Get plan approval in step 3 before any worker starts. |
| "A worker said it opened a PR, so it's done." | Record only the PR: line it actually reported. Don't invent links or assume green CI. |
| "Each worker can skip tests and e2e to go faster." | The per-unit loop — test, e2e, then simplify on substantial diffs — is what makes each PR mergeable on its own. Tests and e2e are never optional; simplify is skipped only for trivial one-line edits. |
| "30 units is fine, I'll just make 60." | Past ~30 units the tracking and review cost outweighs the parallelism. Re-group into coarser units. |
Output
Keep a status table, filled in as workers return:
| # | Unit | State | PR |
|---|------|-------|-----|
| 1 | Migrate <file> to <pattern> | PR open | <url> |
| 2 | … | blocked | — |
Finish with this shape:
Batch: <n landed>/<total> units as PRs
Plan: brain/plans/<slug>.md or "spec, reason"
PRs: <list of urls>
Failed/blocked: <unit # + reason, or "none">
Next: <re-dispatch, finish-in-lead, or review-and-merge>
If units turned out to be dependent, stop before spawning and hand off to
afk:implement with the reason.
References
afk:implement — the sequential, single-working-tree alternative; owns the
freeze-then-fan-out recipe when a shared contract must be built first.
afk:simplify — the cleanup pass each worker runs on its own diff when the
unit's change is substantial (skipped for trivial one-liners).
afk:grill — produces the brain/plans/<slug>.md that batch decomposes.