parallel-pr — one PR per unit against an upstream repo
The default failure mode is squashing N independent improvements into one giant PR (reviewer rejects the whole thing because one bullet is wrong) or, worse, merging them locally on a repo you do not own the trunk of. This skill enforces:
- one worktree per unit
- non-overlapping file scopes stated in the prompt
- one assistant response emits all agents in parallel
- terminal step for each agent is
gh pr create --base <base> against the upstream repo — NOT a local merge
- parent aggregates the N returned PR URLs and reports them together
When to trigger
- User says "each as its own PR", "각각 PR로 올려", "one PR per finding", "fan out and open N PRs", "split these into separate upstream PRs".
- User has ≥ 2 independent units and the target repo has a PR-review culture (OSS project, team repo, any repo where a maintainer other than the author reviews before merge).
- User just finished an evaluation / audit / survey (e.g.
pr-impact-scan, oss-survey) and is now converting each finding into an upstream PR.
- Target repo's CONTRIBUTING.md exists and requires PR review — a local merge would violate the contract.
When NOT to trigger
- Only ONE unit → open a single PR directly, no fan-out.
- Units share a file → they cannot be separate PRs anyway; either serialize or merge into one PR.
- Target repo is personal / solo and the user owns the trunk → use
parallel-dev (local merge is fine).
- Read-only lookup / status sweep → use
parallel-dispatch.
- Any unit depends on another's merge landing first → serialize; parallel-pr assumes independent PRs that reviewers can merge in any order.
Phase 1 — Enumerate units and read the contract
Split the request into concrete, independently-shippable PR-sized units. If the user gave a number, match it. Otherwise pick the natural split — usually 2–5.
Before spawning anything, read the target repo's CONTRIBUTING.md (or equivalent) and extract:
- Base branch for PRs (
main, dev, develop, next, release branch, etc.). Do NOT assume main.
- Scope rule ("one thing per PR", size limits, "no unrelated refactors").
- Attribution policy (some repos ban
Co-Authored-By: Claude / Generated with Claude Code trailers — surface this to every subagent).
- Sign-off / DCO (
Signed-off-by: required?).
- Commit-message conventions (Conventional Commits,
[component] prefix, etc.).
- CI / verification the maintainer expects to pass before review.
If these constraints look recurring for this upstream, save them to memory so future runs skip the re-read.
For each unit write a one-line spec: unit name, primary directories/files it will touch, whether it touches schema/config/CI.
Phase 2 — Prepare worktrees
For each unit, from the main checkout:
git fetch origin
git worktree add -b <slug> <path> origin/<base-branch>
<slug> should be descriptive (fix/null-deref-in-parser, not unit-1). <path> sits outside the main checkout (e.g. ../<repo>-pr-<slug>).
Non-overlapping file scopes are mandatory. If two units both need to touch the same file, either give ownership to one and route the other around it, serialize, or refuse parallelism for that pair and tell the user. Common conflict zones: shared router / dispatcher files, DB schema (at most ONE unit per fan-out), shared protocol / API contract, CI config.
Phase 3 — Fan out (one assistant response, all in parallel)
Emit every Agent call in the same response with isolation: "worktree" and run_in_background: true. Each brief must be self-contained.
Brief template per subagent:
Repo path — the main checkout, for reference only.
Worktree path + branch — where the agent works. It must cd here and stay here.
Upstream contract (verbatim from CONTRIBUTING.md) — base branch, scope rule, attribution policy (explicitly: "do NOT add Co-Authored-By: Claude if the repo bans it"), sign-off / DCO, commit-message convention.
Scope for this unit — numbered list of what to change. Include file paths.
Do NOT touch — explicit list of the other units' file territory, naming the other units.
Verification — exact commands to run before push (typecheck, lint, tests, project-specific make check).
Commit shape — one commit preferred; message explains why. If the repo bans AI-attribution, use git -c commit.gpgsign=false commit -m with a plain heredoc body, no Claude trailer.
Push + PR — exact command shape:
git push -u origin <slug>
gh pr create --base <base-branch> --head <slug> \
--title "<terse title>" \
--body "$(cat <<'EOF'
<PR body matching the repo's template>
EOF
)"
Deliverable — return the PR URL, worktree path, branch name, commit SHA, and any deviations flagged during the run. Cap at 300 words.
Prompt length: 400–800 words per agent. Terse prompts produce shallow PRs that maintainers reject.
Concurrency cap: 4 agents. Beyond 4, review-by-parent (Phase 5) becomes the bottleneck and reviewer bandwidth on the upstream side is also finite. Queue the rest.
Phase 4 — Wait
Do not poll agents. Completion notifications arrive; act on them. If the user stacked unrelated one-liners in the same turn, work those in the interim.
Phase 5 — Aggregate
Once all agents return, produce ONE aggregated response listing:
- N PR URLs, each with its title and target base branch.
- Any deviations each agent flagged (e.g. "had to also touch shared config; scope broadened by one file").
- Any agent that failed to push or open a PR — surface the error inline; do not silently retry.
- Suggested reviewer / label if the CONTRIBUTING calls it out.
Do NOT merge anything. Merge is the upstream maintainer's job.
Pre-flight checklist
Before Phase 3, verify:
Failure modes
- Unauthenticated
gh — agent's gh pr create fails at the last step. Pre-flight catches this.
- Base branch missing on origin —
gh pr create errors with "base branch not found". Usually the repo uses dev or develop, not main.
- Two units touching the same file — second push conflicts on the shared file or the two PRs conflict on the upstream review side. Caught in Phase 2 if scopes are honest.
- Agent bypassed CONTRIBUTING — added an AI-attribution trailer to a repo that bans it, or opened the PR against the wrong base. Parent must review each PR URL in Phase 5 and, if wrong, force-push a fixup or close and reopen.
- PR opened against wrong base — usually
main when the repo wants dev. gh pr edit --base <correct> fixes it without closing.
- Fork-vs-upstream confusion — agent pushed to
origin but origin is the upstream (read-only for the user). Pre-flight the remote model before Phase 3.
1---2name: parallel-pr3description: When the user has N independent improvements against a single upstream repo and each unit must land as its own upstream PR ("각각 PR로 올려", "open a PR for each", "fan out and send N PRs", "split these findings into separate PRs", "one PR per unit against upstream"), fan out N general-purpose subagents — each in its own git worktree with non-overlapping file scope — where every agent commits, pushes, and runs `gh pr create --base <base>` against the upstream repo, then the parent reports the N PR URLs. Distinct from parallel-dev (which merges locally into the base branch and is right for solo/personal repos) and parallel-dispatch (which is read-only status/lookup fan-out with no writes and no worktrees).4---56# parallel-pr — one PR per unit against an upstream repo78The default failure mode is squashing N independent improvements into one giant PR (reviewer rejects the whole thing because one bullet is wrong) or, worse, merging them locally on a repo you do not own the trunk of. This skill enforces:910- one worktree per unit11- non-overlapping file scopes stated in the prompt12- one assistant response emits all agents in parallel13- terminal step for each agent is `gh pr create --base <base>` against the upstream repo — NOT a local merge14- parent aggregates the N returned PR URLs and reports them together1516## When to trigger1718- User says "each as its own PR", "각각 PR로 올려", "one PR per finding", "fan out and open N PRs", "split these into separate upstream PRs".19- User has ≥ 2 independent units and the target repo has a PR-review culture (OSS project, team repo, any repo where a maintainer other than the author reviews before merge).20- User just finished an evaluation / audit / survey (e.g. `pr-impact-scan`, `oss-survey`) and is now converting each finding into an upstream PR.21- Target repo's CONTRIBUTING.md exists and requires PR review — a local merge would violate the contract.2223## When NOT to trigger2425- Only ONE unit → open a single PR directly, no fan-out.26- Units share a file → they cannot be separate PRs anyway; either serialize or merge into one PR.27- Target repo is personal / solo and the user owns the trunk → use `parallel-dev` (local merge is fine).28- Read-only lookup / status sweep → use `parallel-dispatch`.29- Any unit depends on another's merge landing first → serialize; parallel-pr assumes independent PRs that reviewers can merge in any order.3031## Phase 1 — Enumerate units and read the contract3233Split the request into concrete, independently-shippable PR-sized units. If the user gave a number, match it. Otherwise pick the natural split — usually 2–5.3435Before spawning anything, **read the target repo's `CONTRIBUTING.md`** (or equivalent) and extract:3637- **Base branch** for PRs (`main`, `dev`, `develop`, `next`, release branch, etc.). Do NOT assume `main`.38- **Scope rule** ("one thing per PR", size limits, "no unrelated refactors").39- **Attribution policy** (some repos ban `Co-Authored-By: Claude` / `Generated with Claude Code` trailers — surface this to every subagent).40- **Sign-off / DCO** (`Signed-off-by:` required?).41- **Commit-message conventions** (Conventional Commits, `[component]` prefix, etc.).42- **CI / verification** the maintainer expects to pass before review.4344If these constraints look recurring for this upstream, save them to memory so future runs skip the re-read.4546For each unit write a one-line spec: unit name, primary directories/files it will touch, whether it touches schema/config/CI.4748## Phase 2 — Prepare worktrees4950For each unit, from the main checkout:5152```sh53git fetch origin54git worktree add -b <slug> <path> origin/<base-branch>55```5657`<slug>` should be descriptive (`fix/null-deref-in-parser`, not `unit-1`). `<path>` sits outside the main checkout (e.g. `../<repo>-pr-<slug>`).5859**Non-overlapping file scopes are mandatory.** If two units both need to touch the same file, either give ownership to one and route the other around it, serialize, or refuse parallelism for that pair and tell the user. Common conflict zones: shared router / dispatcher files, DB schema (at most ONE unit per fan-out), shared protocol / API contract, CI config.6061## Phase 3 — Fan out (one assistant response, all in parallel)6263Emit every `Agent` call in the same response with `isolation: "worktree"` and `run_in_background: true`. Each brief must be self-contained.6465Brief template per subagent:66671. **Repo path** — the main checkout, for reference only.682. **Worktree path + branch** — where the agent works. It must `cd` here and stay here.693. **Upstream contract (verbatim from CONTRIBUTING.md)** — base branch, scope rule, attribution policy (explicitly: "do NOT add `Co-Authored-By: Claude` if the repo bans it"), sign-off / DCO, commit-message convention.704. **Scope for this unit** — numbered list of what to change. Include file paths.715. **Do NOT touch** — explicit list of the other units' file territory, naming the other units.726. **Verification** — exact commands to run before push (typecheck, lint, tests, project-specific `make check`).737. **Commit shape** — one commit preferred; message explains **why**. If the repo bans AI-attribution, use `git -c commit.gpgsign=false commit -m` with a plain heredoc body, no Claude trailer.748. **Push + PR** — exact command shape:7576 ```sh77 git push -u origin <slug>78 gh pr create --base <base-branch> --head <slug> \79 --title "<terse title>" \80 --body "$(cat <<'EOF'81 <PR body matching the repo's template>82 EOF83 )"84 ```85869. **Deliverable** — return the PR URL, worktree path, branch name, commit SHA, and any deviations flagged during the run. Cap at 300 words.8788Prompt length: 400–800 words per agent. Terse prompts produce shallow PRs that maintainers reject.8990**Concurrency cap: 4 agents.** Beyond 4, review-by-parent (Phase 5) becomes the bottleneck and reviewer bandwidth on the upstream side is also finite. Queue the rest.9192## Phase 4 — Wait9394Do not poll agents. Completion notifications arrive; act on them. If the user stacked unrelated one-liners in the same turn, work those in the interim.9596## Phase 5 — Aggregate9798Once all agents return, produce ONE aggregated response listing:99100- N PR URLs, each with its title and target base branch.101- Any deviations each agent flagged (e.g. "had to also touch shared config; scope broadened by one file").102- Any agent that failed to push or open a PR — surface the error inline; do not silently retry.103- Suggested reviewer / label if the CONTRIBUTING calls it out.104105Do NOT merge anything. Merge is the upstream maintainer's job.106107## Pre-flight checklist108109Before Phase 3, verify:110111- [ ] `gh auth status` clean and pointed at the account that should own the PRs.112- [ ] `origin` in the main checkout points at the intended remote (fork vs. upstream — know which model the repo uses; some workflows require pushing to a fork and PR'ing across forks).113- [ ] Base branch exists on `origin` (`git ls-remote --heads origin <base>`).114- [ ] CONTRIBUTING.md read; base branch, scope rule, attribution policy, sign-off, commit convention all known.115- [ ] Each unit has a non-overlapping file scope written down.116117## Failure modes118119- **Unauthenticated `gh`** — agent's `gh pr create` fails at the last step. Pre-flight catches this.120- **Base branch missing on origin** — `gh pr create` errors with "base branch not found". Usually the repo uses `dev` or `develop`, not `main`.121- **Two units touching the same file** — second push conflicts on the shared file or the two PRs conflict on the upstream review side. Caught in Phase 2 if scopes are honest.122- **Agent bypassed CONTRIBUTING** — added an AI-attribution trailer to a repo that bans it, or opened the PR against the wrong base. Parent must review each PR URL in Phase 5 and, if wrong, force-push a fixup or close and reopen.123- **PR opened against wrong base** — usually `main` when the repo wants `dev`. `gh pr edit --base <correct>` fixes it without closing.124- **Fork-vs-upstream confusion** — agent pushed to `origin` but `origin` is the upstream (read-only for the user). Pre-flight the remote model before Phase 3.