A cross-cutting change — swap the logging API in 40 files, replace a deprecated HTTP client everywhere, thread a tenant-id through every handler — is too big for one agent session and too boring for a team.
Tier: Advanced · Workflow area: Refactoring & Migration
The pattern proven by Stripe-style agent-fleet harnesses: decompose into independently verifiable subtasks, run agents in parallel with a written spec, verify each shard mechanically, and aggregate into human-reviewable PRs. The engineering skill being trained here is the decomposition and the verification harness, not the prompting.
If a codemod can do it all, use pb-23's approach instead — determinism beats parallelism.
claude -p/API calls.git worktree familiarity — parallel agents editing one checkout corrupt each other; one worktree+branch per shard.Write the transformation spec once, with before/after pairs. This is the contract every agent gets verbatim:
# SPEC: migrate logger.* to structlog
- `logger.info("msg %s", x)` → `log.info("msg", value=x)`
- `logger.exception("...")` → `log.error("...", exc_info=True)` inside except blocks
- Module setup: replace `logging.getLogger(__name__)` with `structlog.get_logger()`
- DO NOT change log message text, log levels, or surrounding logic.
- DO NOT touch files outside your assigned list.
- If a call site doesn't match any pattern above, leave it and append it
to UNRESOLVED.md with file:line and reason.
The UNRESOLVED escape hatch is what keeps agents from inventing creative interpretations at weird call sites.
Shard by natural seams, sized for verification. Group by directory/package so each shard compiles and tests independently; 5–15 files per shard is the sweet spot (big enough to amortize context, small enough to review). Generate the assignment mechanically:
grep -rln "logging.getLogger" src/ | sort > /tmp/targets.txt # 43 files
# shard by top-level package
awk -F/ '{print $2}' /tmp/targets.txt | sort | uniq -c
Launch parallel agents, one worktree each. Scripted form:
for shard in api workers billing ingest; do
git worktree add ../wt-$shard -b refactor/structlog-$shard
(cd ../wt-$shard && claude -p "Apply SPEC.md to exactly these files: $(cat shards/$shard.txt). \
Then run: pytest tests/$shard -x. Fix failures within the spec's rules only. \
Output UNRESOLVED.md entries for anything the spec doesn't cover." \
--allowedTools "Edit,Bash(pytest*),Bash(git diff*)" ) &
done; wait
Equivalent flows: Claude Code subagents fanned out from one session, or one GitHub issue per shard assigned to the Copilot coding agent. Cap parallelism at what you can review the same day.
Verify each shard mechanically before any human reading. The aggregator is a script, not vibes — per shard:
# 1. Scope: only assigned files touched
git diff --name-only main | diff - shards/$shard.txt
# 2. Completeness: no old-API stragglers in assigned files
grep -n "logging.getLogger\|logger\." $(cat shards/$shard.txt) || echo CLEAN
# 3. Behavior: shard tests + full-suite smoke
pytest tests/$shard && pytest -m smoke
# 4. No collateral edits: diff contains only spec-shaped hunks (spot pattern)
git diff main -- $(cat shards/$shard.txt) | grep '^-' | grep -v "logger\|getLogger" || true
Check 4 is the agent-specific one: it surfaces drive-by "improvements" outside the spec. Any check fails → the shard goes back to its agent with the failure, or you fix it; it does not proceed to review.
Aggregate for human review, merge shard-wise. Collate all UNRESOLVED.md entries first — resolve them yourself or extend the spec and re-run affected shards (spec extensions re-run everywhere relevant, or your codebase ends half-migrated in two styles). Open one PR per shard (reviewable) rather than one 40-file PR (not), each carrying its verification log in the description. Land a repo-wide final gate in CI: grep -rn "logging.getLogger" src/ && exit 1 so the old pattern can never return.
Parallel agents don't remove the verification burden — they batch it. The harness (scope check, completeness grep, tests, collateral-edit scan) is the deliverable that makes 40 files of agent output trustworthy; without it you have 40 files of plausible diffs.