fanning-out-with-worktrees
Skill2 starsChanged 12 days agoMITView on GitHub
When you're the orchestrator for multi-PR feature work and these prerequisites are met: Skip for single-PR features — there's no fan-out, just one branch off main. Parallel fan-out compounds in complexity quickly: contract handoff, isolation, wave dependencies, propagation, state tracking, per-PR ripening. Wrapping the choreography in one skill keeps feature-dev-workflow:developing-a-feature focused on the single-vs-multi decision and the integration-PR endgame, and gives any future use case (parallel migration work, parallel refactor, cross-module sweep) a reusable orchestration entry point. Look at the…
In this repository19 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- addressing-review-feedbackSkill
- bounding-heavy-commandsSkill
- copilot-review-loopSkill
- developing-a-featureSkill
- drafting-a-releaseSkill
- maintaining-architectural-coherenceSkill
- opening-a-pull-requestSkill
- planning-a-featureSkill
- product-epicSkill
- reporting-a-skill-gapSkill
- resuming-a-featureSkill
- reviewing-feature-progressSkill
- stacking-dependent-prsSkill
- testing-a-featureSkill
- testing-end-to-endSkill
- writing-code-commentsSkill
- writing-docsSkill
- writing-github-issuesSkill
The file
We split this skill into the rules it gives an agent
7 rules. About 0 are common, 1 is distinctive, and 6 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈1
Distinctive · estimate
This author's own choices. Worth a look.
6
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 13
When you're the orchestrator for multi-PR feature work and these prerequisites are met:
- Very specific: line 30
Look at the plan's ## Contracts table.
- Very specific: line 101
Global view: Only the orchestrator holds the merge-order context (which contract rows are locked, which sibling PRs are still in flight, …
- Very specific: line 120
sub_pr_target: feature-branch: after the merge, git -C <feature_worktree> fetch origin && git merge --ff-only origin/<type>/<slug> to … - Very specific: line 124
sub_pr_target: main: no manual close needed. The closing keyword in the PR body (Fixes/Closes) fires on merge to the default branch and … - Very specific: line 129
When every sub-PR in wave N is self-merged AND every contract tied to wave N's producers is locked:
- Very specific: line 138
When every wave is complete (every sub-issue closed, every row self-merged, every contract locked), update the state file's frontmatter …
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
fanning-out-with-worktrees
When to invoke
When you're the orchestrator for multi-PR feature work and these prerequisites are met:
- The
<type>/<slug>integration branch and the main feature worktree exist (set up byfeature-dev-workflow:developing-a-featurebefore invoking this skill). - The plan (
docs/superpowers/plans/<date>-<slug>-plan.md) has a## Contractssection with a Realization strategy per row. - The plan also has a
## Conventionsblock (directory layout, naming scheme, locked vocabulary) — it's mandatory dispatch context for every subagent (Step 2), so the fan-out can't start without it. - The state file (
docs/superpowers/states/<date>-<slug>-state.md) has rows for each sub-issue.
Skip for single-PR features — there's no fan-out, just one branch off main.
Why this exists
Parallel fan-out compounds in complexity quickly: contract handoff, isolation, wave dependencies, propagation, state tracking, per-PR ripening. Wrapping the choreography in one skill keeps feature-dev-workflow:developing-a-feature focused on the single-vs-multi decision and the integration-PR endgame, and gives any future use case (parallel migration work, parallel refactor, cross-module sweep) a reusable orchestration entry point.
Workflow
1. Plan the waves
Look at the plan's ## Contracts table. Sub-PRs that are contract producers go in the FOUNDATIONAL wave; sub-PRs that are contract consumers go in subsequent waves, keyed by when their contract is realized:
data-onlyandpre-merge stub PRrealizations → consumers can start as soon as the producer's stub PR has merged into the feature branch (or the data-only contract is documented).stub-on-producer-branch→ consumers branch from the producer's branch (not the feature branch); dispatch is timed to after the producer's PR is open with the stub in place.
Sub-PRs with no contract dependency → all in one wave.
Record the wave assignments in the state file's ## Phases section before dispatching.
2. Create sub-worktrees and dispatch wave N
First classify each sub-PR in the wave. A sub-PR is a stack layer when it is based on another sub-PR's branch, or when another sub-PR is or will be based on its branch (the stack's bottom layer; a producer with a stub-on-producer-branch consumer in a later wave counts). A stack layer gets no worktree from the loop below, and it is set up and dispatched as the stack paragraph after the loop says. For every other sub-PR in the wave, the orchestrator creates the worktree first:
git worktree add .claude/worktrees/<slug>--<sub-name> -b <sub-type>/<slug>--<sub-name> <base-ref>The sub-branch name is derived, not invented. It is <sub-type>/<slug>--<sub-name>: the parent's slug, so every branch of one feature sorts together in the remote's branch list, then --<sub-name> for this slice. <sub-type> is the commit type of this sub-PR's headline change, which is often not the parent's — a feature branch's slices routinely include a refactor that clears the way and a test that backfills coverage. The <sub-name> follows the same rule as the parent slug (feature-dev-workflow:planning-a-feature step 2): it names the slice's subject and effect in two to four words, never part-2, phase-b, or the plan's organizing label — those are positions in a plan the reader does not have, and inheriting them violates the naming firewall in feature-dev-workflow:maintaining-architectural-coherence.
Record the branch in the state file's PR-table row as you create it; the resumed-session contract in feature-dev-workflow:resuming-a-feature reads that row as ground truth.
When the state file's frontmatter has sub_pr_target: main, <base-ref> is origin/main for every sub-PR in every wave (fetch origin/main first so wave N+1 picks up the commits that wave N merged). When sub_pr_target is feature-branch (the default), <base-ref> is <type>/<slug> for default sub-PRs, <type>/<slug> after the stub PR merged (for pre-merge stub PR consumers), or the producer's branch (for stub-on-producer-branch consumers).
A sub-PR based on another sub-PR's branch makes a stack, not a wave member, and so does the sub-PR it is based on. That covers a stub-on-producer-branch consumer and, in either sub_pr_target model, any strictly sequential chain whose PRs open before their parents merge. Its branches, bases, propagation, and merges go through gh stack, which needs one dedicated worktree per stack (never the main checkout): REQUIRED SUB-SKILL: feature-dev-workflow:stacking-dependent-prs, including its availability check, before creating the consumer's branch. The orchestrator decides per layer whether it can be built in parallel, and runs every gh stack command. A sequential layer's subagent works in the stack's worktree, one layer at a time. A parallel layer's subagent works in a temporary worktree of its own, and the layer joins the stack after that worktree is removed (see its §Parallel layers). Each isolation check names the worktree path and the layer's branch. A stack layer's subagent does not open its own PR (this replaces dispatch item 4 below); the orchestrator opens each stack PR as soon as that layer is ready, so a producer's PR is open before its stub consumer is dispatched, and links them as its §Opening the stack's PRs says. Parallel sub-PRs based directly on <base-ref> stay in the worktree-per-sub-PR model below. A stack has at most one child per layer, so only one consumer can stack on a given producer. When two or more consumers are based on the same producer's branch, that is a fork, not a stack: one of them joins the producer's stack, and each other one waits until the producer has merged and then branches from <base-ref> like a pre-merge stub PR consumer.
Then dispatch one subagent per sub-PR, except for a stack's sequential layers: those share the stack's worktree, so dispatch them one at a time, each after the layer below it is done. REQUIRED SUB-SKILL: superpowers:dispatching-parallel-agents.
Each dispatch prompt MUST include:
- Isolation verification as the first action.
cd <worktree-path> && pwd && git branch --show-current— the subagent confirms it's on the sub-branch in the right worktree before any edit. Commits land on the wrong branch otherwise. - Context handoff. State file path, plan path, spec path, the issue number it's working, the relevant contract row(s) (Name + Producer + Consumer + Shape + Realization), and the plan's
## Conventionsblock. The subagent implements against the contract and the conventions — it does not re-discover or re-design either, and it does not invent its own directory layout or naming scheme. A subagent handed contracts but not conventions will name and structure locally, and the merged feature reads as written by a committee (seefeature-dev-workflow:maintaining-architectural-coherence). - Implementation skills.
superpowers:test-driven-development+feature-dev-workflow:testing-a-featurefor every change, andfeature-dev-workflow:writing-code-commentsfor every comment the change adds, edits, or deletes. - PR completion. A stack layer's subagent skips this item and reports to the orchestrator, which opens the stack's PRs (see the stack paragraph above). A sequential layer's subagent reports its finished branch and head commit without pushing, because the orchestrator pushes the stack's worktree with
gh stack push. A parallel layer's subagent pushes its branch from its temporary worktree first, then reports. Every other subagent, when the implementation is done and verified, invokesfeature-dev-workflow:opening-a-pull-request. The base and body keyword depend onsub_pr_targetin the state file: whenfeature-branch, use--base <type>/<slug>andTowards #<sub-issue>in the body (Fixes/Closesdon't fire on non-default-branch merges;Towardskeeps the issue open until the orchestrator closes it manually after the merge); whenmain, use--base mainand the type-appropriate closing keyword in the body —Fixes #<sub-issue>for a bug sub-issue,Closes #<sub-issue>otherwise; either fires automatically on merge to the default branch (seefeature-dev-workflow:opening-a-pull-requestfor the distinction). No sub-PR keyword closes the epic, and in main mode the epic stays open for the user (see Step 7). The subagent reports the PR URL back to the orchestrator. - Bounded commands. The bounded command line for every heavy command the subagent will run (tests, lint, build, typecheck), copied from the orchestrator's record, and the rule to use no other form. A subagent does not see the orchestrator's project memory, so a prompt without them sends it to the plain commands, and a wave of plain test runs is what freezes the machine. REQUIRED SUB-SKILL:
feature-dev-workflow:bounding-heavy-commands(§Dispatching subagents) before writing the first dispatch prompt of a wave. When the wrapper cannot run on the machine, its §When the wrapper cannot run decides the prompts and the order of the dispatch. - A scratch folder of its own. The absolute path of a folder that only this subagent uses for files that do not belong in the repo: PR and comment bodies for
--body-file, review output, logs, and one-off scripts. Make it<scratchpad>/<sub-name>/when your harness gives you a scratchpad or temporary directory, or a freshmktemp -dwhen it does not, and create it before the dispatch. Tell the subagent to write such files there and nowhere else. A worktree isolates the repo, not the temporary files: subagents get the orchestrator's scratchpad, so two that write a file of the same name, such aspr-body.md, overwrite each other, and a PR goes out with its sibling's body. Use the same folder in every later message or re-dispatch to that subagent's sub-PR.
Each dispatch prompt also carries this instruction for the subagent: OPTIONAL SUB-SKILL: simple-english:simple-english for the prose of your commit bodies, code and doc comments, and PR body. If it is available, load it before you draft and write the sentences under it. Where its formatting rules (headings, bold, lists, or its register for chat replies) differ from the host skill or its template, the host skill and its template win. It sets sentence style only: the commit subject keeps the project's commit convention, and the project's comment rules still decide whether a comment exists and what it may say. If it is not available, do not stop or wait for it: write short, plain, active sentences and say in your report that it was missing. The orchestrator, not the subagent, gives the user the install hint (/plugin marketplace add AminBlg/SimpleEnglish, then /plugin install simple-english@simple-english), at most once per session.
3. Update the state file as subagents start work
As each subagent surfaces its worktree path and branch, the orchestrator fills in the row in the state file's ## PRs / worktrees table. When a subagent opens its draft PR, or the orchestrator opens a stack's PRs, the orchestrator fills in the PR column with the base ref (#<num> → <type>/<slug> or #<num> → main, per the sub_pr_target setting; a stack layer above the bottom shows its parent's branch) and flips status to draft.
A stale row is worse than no row — a resumed session reads the state file as ground truth.
4. Watch loop
While subagents run, the orchestrator is the integration point — not an idle waiter. Watch for concerns that bubble up from any subagent and propagate the resolution across every subagent the concern touches. Silent divergence is the failure mode this watch loop exists to prevent.
Categories of concerns to watch for:
- Contract drift. A row in the
## Contractstable needs to shift (reviewer feedback, an edge case the producer hit). Pause every affected consumer, update the plan's row, propagate. - Naming / layout divergence. A subagent introduces a path, package, file-naming scheme, identifier pattern, or fixture name that doesn't match the
## Conventionsblock or what a sibling PR already shipped. Reconcile before the merge — pick the convention (update the block if the new choice is better), and propagate to every subagent on the divergent pattern. Naming drift is invisible to contract checks; catching it here is far cheaper than at the integration PR. - Spec ambiguity surfaced mid-implementation. A subagent hits a case the spec didn't cover. Surface to the user, get a decision, amend the spec (or add a note to the plan), and propagate to every subagent whose scope touches the same surface.
- Discovered cross-PR dependency. A subagent finds it needs a helper, type, or behaviour from another PR that the plan didn't enumerate. Decide whether the helper becomes a new contract (file an issue, add a contract row), inlines into the current PR, or is something one of the other subagents is already producing.
- Test failure in shared infrastructure. One subagent breaks a test that another subagent's PR relies on. Coordinate the fix into the right PR; don't let both subagents fix it independently.
- External dependency change. A dependency version bump, a library update, an API shift — affects every running subagent.
- Resource conflict. Two subagents both editing the same file or symbol. Re-scope one to avoid the collision, or serialize the work.
How to propagate the resolution:
- Subagent still running →
SendMessagewith the subagent's id to push the resolution with full context. The subagent resumes with the update applied. - Subagent finished, PR still open → re-dispatch a focused follow-up with the PR number and the specific change.
- Subagent not yet dispatched (later wave) → update its dispatch prompt's context block before launching.
Append a dated entry to the state file's ## Bubble-up log (newest at top) naming the concern, the resolution, and the propagation path used. The orchestrator owns propagation; a concern raised by one subagent and not propagated to the others is how this whole pattern fails.
5. Per-sub-PR ripening — all orchestrator-driven
When a sub-PR is ready (subagent reports ready and the relevant verification commands pass), the orchestrator takes over for the rest of the lifecycle. Every action below — review, merge, sub-issue close, state-file update — is the orchestrator's, not the worktree subagent's. Three reasons this is the right division of labour:
- Review independence. The subagent that wrote the code is the wrong reviewer for the same code; the orchestrator's distance from the implementation is the whole point.
- Global view. Only the orchestrator holds the merge-order context (which contract rows are
locked, which sibling PRs are still in flight, which wave we're in). A subagent merging on its own would commit to ordering it can't see. - Worktree topology. Subagents live in their per-sub-PR worktrees; only the orchestrator's main feature worktree has
<type>/<slug>checked out, so the merge naturally happens on the orchestrator's side.
Per sub-PR, in order:
- Automated review-loop, if the state file's
sub_pr_review_loopison. OPTIONAL SUB-SKILL:feature-dev-workflow:copilot-review-loopagainst the sub-PR number, in fan-out mode — it requests the automated (Copilot) review, waits for it in the background, and drives the PR to review-clean. When a subagent runs the loop, its prompt names the skill and adds no wait instructions of its own: the skill's Step 3 says how to wait for the review and that no background shell may still run when the subagent reports back. In fan-out mode a comment the loop wants to push back on does not pause the fan-out: log it as a bubble-up concern in the## Bubble-up log(surfaced at the wave checkpoint byfeature-dev-workflow:reviewing-feature-progress) and continue. Skip this step whensub_pr_review_loopisoffor missing. It runs before the orchestrator's own review so the diff reviewed below is the post-automated-review diff that will actually merge. - Two-stage review — spec-compliance first, then code quality. Both stages are the
reviewskill, run against the sub-PR number with full PR context, scoped differently. This review is weaker than external review (which lands at the integration PR) but stronger than nothing; it catches issues that would otherwise pile onto the integration PR reviewer. The order is a gate, not a preference: a PR that doesn't yet implement its sub-issue is going back regardless, so quality findings on code about to change are wasted effort and noise. One blended "looks good" pass is the failure this split exists to prevent.- Spec-compliance pass (the gate). REQUIRED SUB-SKILL: the
reviewskill, scoped to intent: walk the sub-issue's acceptance criteria one by one and map each to real code in the diff and a test that exercises it. Confirm nothing is missing and nothing extra was built — unrequested scope is a finding, not a bonus (it may collide with a sibling PR or belong elsewhere). This pass must come back clean before the quality pass starts. - Code-quality pass. REQUIRED SUB-SKILL: the
reviewskill, scoped to craft: bugs the criteria didn't name, edge cases, error handling, test quality, simplification/reuse. Beyond bugs, check the diff against the## Conventionsblock — does its layout, naming, and vocabulary match the block and the sibling PRs already merged? A convention violation caught here is one the integration reviewer never sees.
- Fix-loop. When either pass returns findings, the orchestrator does not fix them in place — it routes them back to the worktree subagent via
SendMessage(the author has the context, and silent orchestrator fixes rob the parallel agents of shared understanding), then re-runs the same pass against the changed surface. Spec-compliance findings re-run the spec pass; only once it is clean does the quality pass run. Repeat until both passes are clean. The worktree subagent fixes; the orchestrator reviews — never the reverse. Each message that routes findings carries this instruction for the subagent: REQUIRED SUB-SKILL:feature-dev-workflow:addressing-review-feedbackbefore the first edit and again before the push, with its table of verdicts in the report back to the orchestrator. The message also says which text in it is a finding of a reviewer and which is an instruction of the user.
- Spec-compliance pass (the gate). REQUIRED SUB-SKILL: the
- Approval gate, per the state file's
sub_pr_approvalmode. Every gate covers the bundle: ready flip + CI gate + merge + sub-issue close + state-file update. The close is bodyless (no--commentflag) — GitHub automatically cross-references the sub-issue from the merge commit via the sub-PR's body keyword, so no custom comment is needed and there's no "specific body about to land" for the close mutation.autonomous(default) — proceed straight through the bundle in steps 4-8. The user opted into the mechanical bundle (review → ready flip → CI gate → merge → bodyless close → state update) infeature-dev-workflow:developing-a-featureStep 2.manual— pause and ask the user for explicit approval before the bundle. The prompt MUST surface: a one-line summary of the review findings ("review clean" / "<N>findings, none blocking" / specific concerns), the PR's title and diff size, and a note that closing sub-issue#<sub-issue>follows the merge. Wait for an explicit yes. On push-back, route the concern back to the worktree subagent viaSendMessageinstead of merging.
- Flip the PR ready. A draft cannot merge (
gh pr mergeandgh stack mergeboth refuse it), so flip the PR ready throughfeature-dev-workflow:opening-a-pull-request's steps for flipping a draft to ready; the approval gate above is the confirmation for that flip. - CI gate: every check on the PR's head passed. Run
gh pr checks <num>after the flip, because some pipelines skip drafts and start only when the PR is ready. When the CI configuration starts a run on the ready transition, a read right after the flip can still show the draft-time results,skippingamong them: read withgh pr checks <num> --json name,bucket,startedAtand wait in the background until that run's checks show astartedAtlater than the flip. Read every check, not only--required: a feature branch seldom has protection rules, so it has no required checks to list. The gate passes when every check ispassorskipping. A review loop that came back clean and a subagent's local run are not this gate: the subagent runs what fits on its machine and the tests it touched, and a change can break a test it never touched, which only CI runs.- Pending (exit code 8) — wait in the background, not in the foreground:
gh pr checks <num> --watch --fail-fastas a background command, and act on its result when it exits. - A check failed or was cancelled — do not merge. Route it to the worktree subagent via
SendMessagethe way item 2's fix-loop routes a finding: the check's name, its link, and its failed log (gh run view <run-id> --log-failedwhen the check is a GitHub Actions run). The failure is the sub-PR's even when it is in a test the diff did not touch. After the fix is pushed, the changed surface goes back through item 1 (when the loop is on), item 2, and item 3, because inmanualmode the user approved a diff that the fix changed. Then this gate runs again on the new head. - No checks reported — decide from the repo's CI configuration, as
feature-dev-workflow:developing-a-featureStep 7 does for the integration PR, not from the empty reading: if a pipeline runs on PRs into this base, wait in the background for its checks to register; if none does, the subagent's verified local run is the gate.
- Pending (exit code 8) — wait in the background, not in the foreground:
- Merge. Run
gh pr merge <num> --merge(or--squash/--rebaseper project preference). A stack layer merges withgh stack merge <num> --yesand the same merge-method flag instead, followed bygh stack synconce the PR has actually merged (a merge queue can hold it first), and only when it is the lowest unmerged layer of its stack:gh stack mergealso merges every unmerged layer below the one named, so a higher layer that passes its gates first waits until the layers below it have merged (seefeature-dev-workflow:stacking-dependent-prs§Merges stay under the merge guard). Before merging, push any local state-file commits to their remote — forfeature-branchthat isorigin/<type>/<slug>; formainthat isorigin/<type>/<slug>as well (the orchestrator stays on the feature branch for state management). The merge itself lands on GitHub's remote, and the pull-back differs by target:sub_pr_target: feature-branch: after the merge,git -C <feature_worktree> fetch origin && git merge --ff-only origin/<type>/<slug>to bring the merge commit back into the feature worktree. Keep local == origin at every merge boundary (unpushed local commits cause a "Not possible to fast-forward" failure; recover withgit rebase origin/<type>/<slug>).sub_pr_target: main: the merge lands onmain. The orchestrator remains on<type>/<slug>for state file management; no pull-back into the feature worktree is needed. Before dispatching wave N+1, rungit fetch originso the next wave's worktrees branch from the freshly updatedorigin/main.
- Close the sub-issue.
sub_pr_target: feature-branch:gh issue close <sub-issue>. Sub-PRs into a non-default branch don't triggerFixes/Closes— manual close is the workaround. The body'sTowards #<sub-issue>keyword left the issue open precisely so the orchestrator can close it here; the cross-reference from the merge commit (which references#<sub-pr>, which references#<sub-issue>) is preserved automatically without a custom comment.sub_pr_target: main: no manual close needed. The closing keyword in the PR body (Fixes/Closes) fires on merge to the default branch and auto-closes the sub-issue. Confirm it closed before marking the state-file rowself-merged.
- Update the state file. Flip the row's status to
self-merged. If the sub-PR was the realization of a contract (e.g. a pre-merge stub PR), flip the contract row's status tolockedand fill in theRealized inpointer.
6. Checkpoint review, then dispatch wave N+1
When every sub-PR in wave N is self-merged AND every contract tied to wave N's producers is locked:
- REQUIRED SUB-SKILL:
feature-dev-workflow:reviewing-feature-progress— run the alignment checkpoint at the wave boundary. Drift accumulated across wave N is cheapest to fix here, not at the integration PR. If the checkpoint surfaces gaps, address them (follow-up sub-PR in wave N, plan/issue refinement, or both) before moving on. - Once the checkpoint is clean, dispatch wave N+1. Wave N+1's subagents pick up the realized contracts because the orchestrator updated the state file's
## Contractstable.
Repeat Steps 2 → 6 for each wave.
7. All waves complete → hand back
When every wave is complete (every sub-issue closed, every row self-merged, every contract locked), update the state file's frontmatter status: to review and return control to feature-dev-workflow:developing-a-feature.
sub_pr_target: feature-branch: the next step is the integration PR (<type>/<slug>→mainwithCloses #<epic>), whichfeature-dev-workflow:developing-a-featureStep 6 owns — opening and review-looping only; the merge to main itself is the user's (see that skill's merge guard).sub_pr_target: main: the sub-PRs were already the deliverables to main; there is no integration PR.feature-dev-workflow:developing-a-featurepasses through Step 6 (verification only — no PR to open) and proceeds to Step 7 (teardown). Do not close the epic. Sub-PR closing keywords (Fixes/Closes) only close sub-issues, and closing the epic is the user's decision: it can still hold follow-up work, a rollout, or open questions. Report that every sub-PR merged and every sub-issue closed, and leave the epic open for the user.
Anti-patterns
- Dispatching parallel agents without contracts. "Two subagents on these two PRs" with no contract = divergent implementations that block at integration. If the plan didn't define a contract, don't dispatch — go back to
feature-dev-workflow:planning-a-featureStep 6 and add one. - Dispatching without the conventions block. Contracts make the work compile; conventions make it cohere. Hand a subagent contracts but no
## Conventionsand it invents its own layout and names — the drift surfaces at the integration PR when it's expensive. If the plan has no conventions block, go back toplanning-a-featureStep 6. - Skipping wave dependencies. Consumers dispatched before producers' contracts are realized produce code against an imagined shape. Dispatch wave N+1 only after wave N is fully self-merged and contracts locked.
- Self-merging without orchestrator review. The integration PR is where external review lands, but sub-PRs still need a review pass before going into the feature branch. Skipping it dumps issues onto the integration PR reviewer.
- Collapsing the two stages into one "looks good" pass. Spec-compliance and code-quality answer different questions — "does it do the job" vs "is it well-built". Reviewing them together lets a momentum-driven skim pass a PR that quietly misses an acceptance criterion or builds unrequested scope. Run the spec gate to clean first, then quality.
- Quality-reviewing before spec-compliance is clean. Polishing code that's about to change because it doesn't meet the spec wastes the pass and buries the real finding in nits. The spec pass is a gate; the quality pass waits behind it.
- Orchestrator fixing review findings in place. The worktree subagent wrote the code and holds the context; it fixes, then the orchestrator re-reviews. A silent orchestrator fix skips the author and erodes the shared understanding the parallel agents run on.
- Letting the worktree subagent review its own PR. A subagent reviewing the code it just wrote has the same blind spots in review that it had in implementation. The orchestrator owns sub-PR review precisely because it didn't write the code.
- Letting a bubble-up concern die in one subagent. Propagation is the whole point of the watch loop.
- Shrinking the wave to spare the machine. The number of subagents does not decide the load; the commands they run do. Dispatch the wave the plan calls for and hand every subagent the bounded commands (dispatch item 5). Subagents that wait in the queue cost time, not memory. On a machine on which the wrapper cannot run, no queue exists: dispatch the subagents of the wave that run a heavy command one after the other, as
feature-dev-workflow:bounding-heavy-commandssays. - Forgetting to manually close the sub-issue when
sub_pr_target: feature-branch. The keyword doesn't fire on non-default-branch merges; the issue page silently shows "open" even though the work shipped. - Using
Towards #<sub-issue>whensub_pr_target: main.Closesfires on merge to the default branch;Towardsintentionally blocks auto-close. Using the wrong keyword silently leaves sub-issues open after they merge to main and forces a manual cleanup pass. - Letting the state file go stale. A resumed session reads it as ground truth. Update every row as reality moves; commit and push the state-file diff per phase transition — an unpushed local commit diverges the feature branch the moment the next sub-PR squash-merges on GitHub (see Step 5.6).
Red flags
| Thought | Reality |
| "The plan says parallel but I don't see contracts — I'll just guess" | Plan is incomplete. Stop and define the contract, or sequence the work. |
| "I'll dispatch wave 2 now, wave 1 is almost done" | Almost-done producers haven't locked their contract rows. Wave 2 will diverge. Wait. |
| "The subagent will figure out the worktree on its own" | Create the worktree yourself and embed cd <path> && pwd && git branch --show-current in the dispatch. |
| "Self-review feels redundant, the integration PR catches everything" | Integration PR reviewer can't catch every issue across 5 sub-PRs in one sitting. Catch them per PR. |
| "The subagent already verified the diff, no need for the orchestrator to review again" | Verification (tests pass) is not review (does the diff express intent cleanly). Different signals. |
| "Tests pass and the diff looks clean — one review pass is enough" | Spec-compliance and quality are different questions. The spec gate runs to clean first, then quality; one blended pass skims past a missed acceptance criterion. |
| "The spec pass found a gap but I'll quality-review now to save a round-trip" | Quality findings on code about to change are noise. Send the gap back, re-run the spec pass to clean, then quality. |
| "The review loop is clean and the subagent's tests pass locally, so I can merge" | Neither reads CI. The subagent ran what fits on its machine; a red check on a test the diff never touched is still this PR's break. Read gh pr checks on the head before every merge (Step 5, item 5). |
| "Both sub-PRs pass CI, so the naming difference between them is fine" | Contract checks don't see naming. Two schemes for one kind of thing is drift — reconcile it at the wave, not the integration PR. |
| "I'll close the sub-issue once the integration PR merges" | Issues that read "open" while their work has shipped clutter the triage view. Close manually at self-merge (feature-branch mode) or confirm auto-close fired (main mode). |
"Towards is always the safe keyword for sub-PRs" | Towards intentionally blocks auto-close. In sub_pr_target: main mode use Closes — it fires on merge to the default branch and removes the manual close step. |
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

