validate-merge-prs
Orchestrates the full PR-merge lifecycle for all open PRs in the current repo. Discovers PRs, builds a dependency graph, validates each in parallel via review-cycle, computes a safe merge order, and presents a merge plan for approval before executing.
Workflow
digraph validate_merge {
rankdir=TB;
discover [label="Discover open PRs\n(gh pr list)" shape=box];
graph [label="Build dependency graph\n(branches + files + metadata)" shape=box];
validate [label="Parallel validation\n(sub-agent per PR\nrunning review-cycle)" shape=box];
classify [label="Classify: ready vs blocked" shape=diamond];
order [label="Compute merge order\n(topo sort + overlap tie-break)" shape=box];
report [label="Present report\n+ merge plan" shape=box];
approve [label="User approves?" shape=diamond];
merge [label="Sequential merge\n(rebase between steps)" shape=box];
done [label="Done — report results" shape=doublecircle];
blocked [label="Report blockers only" shape=doublecircle];
discover -> graph;
graph -> validate;
validate -> classify;
classify -> order [label="some ready"];
classify -> blocked [label="all blocked"];
order -> report;
report -> approve;
approve -> merge [label="yes"];
approve -> done [label="no / adjust"];
merge -> done;
}
Phase 1: Discovery & Dependency Analysis
1. Discover Open PRs
gh pr list --author @me --state open --json number,title,headRefName,baseRefName,url,reviewDecision,statusCheckRollup,mergeable,body,isDraft,createdAt
If zero PRs are found, report “No open PRs found” and stop.
Print a summary table of discovered PRs before continuing:
| # | Title | Branch | Base | CI | Reviews | Draft |
2. Build Dependency Graph
Construct a directed “must merge before” graph from three signal sources:
Branch topology (hard dependency): If PR-A’s headRefName equals PR-B’s baseRefName, A must merge before B.
PR metadata (hard dependency): Scan each PR’s body and title for patterns: depends on #N, after #N, blocks #N, requires #N. These create directed edges.
File overlap (soft signal): For each PR pair, compare changed files:
gh pr diff <number> --name-only
Compute pairwise file intersections. Overlapping files don’t create hard dependencies — they inform merge ordering as a tie-breaker.
3. Cycle Detection
Check the dependency graph for cycles. If found:
- Flag all PRs in the cycle as errored
- Exclude them from the merge plan
- Report the cycle: “Dependency cycle detected: #A → #B → #C → #A”
Phase 2: Parallel Validation
Dispatch one sub-agent per PR to validate it. All PRs validate concurrently — validation happens on each PR’s own branch and doesn’t require merge order.
4. Dispatch Validation Agents
For each PR, spawn a sub-agent (via Agent tool) with this prompt template:
You are validating PR #<number> (<title>) on branch <headRefName>.
1. Check out the branch: git checkout <headRefName>
2. Run /review-cycle <number>
3. After review-cycle completes, check current status:
- gh pr view <number> --json statusCheckRollup,reviewDecision,mergeable
4. Report back with:
- PASS or FAIL
- What review-cycle fixed (if anything)
- What remains broken (if anything)
- Current CI status (passing/failing/pending)
- Current review status (approved/changes_requested/review_required/none)
- Mergeable state (mergeable/conflicting/unknown)
Parallelism: Launch all validation agents simultaneously using multiple Agent tool calls in a single message. Use run_in_background: true for each agent.
Wait for all agents to complete before proceeding to Phase 3.
5. Classify Results
After all validation agents report back, classify each PR:
Ready to merge:
- CI passing (all required status checks green)
- At least one approving review (or reviews not required per repo settings)
- No merge conflicts with base branch
- review-cycle completed without unresolved issues
Blocked (with reason):
- CI failing after review-cycle exhausted its iterations →
"CI failing: <failure summary>" - Missing required review approvals →
"Missing required review approval" - Merge conflicts →
"Merge conflict with base branch" - Draft PR →
"PR is in draft status" - Depends on a blocked PR →
"Blocked by #<number> which is also blocked"
Phase 3: Merge Plan & Report
6. Compute Merge Order
For all “ready” PRs, compute the merge order:
- Topological sort on the dependency graph — hard dependencies determine base ordering
- File overlap tie-break — among PRs at the same topological level, merge those that share files with later PRs first (so later PRs can rebase cleanly)
- Final tie-break — oldest PR first (by
createdAt)
7. Detect Merge Method
Auto-detect the repo’s merge convention:
git log --merges --oneline -20 <default-branch>
- If most recent merges show “Squash” pattern → use
--squash - If most recent merges show standard merge commits → use
--merge - If no merge commits found (linear history) → use
--rebase - If unable to determine → ask the user
8. Present Report — HARD GATE
Present the full report in this format:
## PR Queue Status
### Ready to Merge (in order)
1. #<number> - <title> (base: <baseRefName>) — CI: <status>, Reviews: <count> approved
↳ depends on #<dep>, will rebase after merge [only if applicable]
### Blocked (needs attention)
- #<number> - <title> — <block reason>
### Merge Order Rationale
- #X before #Y: <reason>
### Merge Method
Detected: <squash|merge|rebase> (based on repo history)
ASK THE USER: “This is the proposed merge plan. Approve to proceed, or tell me what to adjust.”
DO NOT merge anything until the user explicitly approves. This gate is non-negotiable.
Phase 4: Merge Execution
Triggered only after the user approves the merge plan.
9. Sequential Merge
For each PR in the computed merge order:
a. Pre-merge re-check:
gh pr view <number> --json statusCheckRollup,reviewDecision,mergeable
Verify CI is still passing, reviews are still approved, and PR is still mergeable. If any check fails, skip this PR and report why — do not merge stale PRs.
b. Merge:
gh pr merge <number> --<method> --delete-branch
Where <method> is the detected merge method from step 7.
c. Rebase downstream PRs:
If any queued PR had its baseRefName pointing at the just-merged branch:
gh pr edit <downstream-number> --base <default-branch>
The downstream PR’s CI will re-run automatically after the base change.
d. Continue to the next PR in the merge order.
10. Failure Handling
If a merge fails:
- Stop the affected dependency chain — do not merge any PR that depends on the failed one
- Continue with independent PRs — PRs with no dependency on the failed one can still merge
- After all possible merges are attempted, present a final status report
11. Final Report
After all merges complete (or fail), present:
## Merge Results
### Successfully Merged
- #<number> - <title> ✓
### Failed
- #<number> - <title> — <failure reason>
### Skipped (dependency on failed PR)
- #<number> - <title> — blocked by #<failed-number>
### Still Blocked (from Phase 2)
- #<number> - <title> — <original block reason>
Key Design Decisions
| Decision | Choice | Rationale |
|---|---|---|
| Single invocation | One skill does discovery through merge | User wants full automation, not multi-step manual process |
| Parallel validation | Sub-agent per PR via Agent tool | PRs validate independently on their own branches |
| Topo sort + overlap | Dependency-aware merge ordering | Handles stacked branches and minimizes rebase conflicts |
| Merge method auto-detect | Inspect recent git history | Consistent with existing project conventions |
| Batch blocker reporting | One report at the end | User wants a coherent picture, not interruptions |
| Approval gate before merge | Present plan, wait for explicit approval | Autonomous validation but human-approved merging |
Safety Rails
- Never force-push. If a rebase is needed, use
gh pr edit --baseto retarget the PR. Let CI re-run naturally. - Re-check before every merge. CI and review status can change between validation and merge. Always verify immediately before merging.
- Stop the chain on failure. If PR #42 fails to merge, do not merge #45 that depends on it. Independent PRs can still proceed.
- Skip draft PRs. Flag them as blocked — they are not ready for merge.
- Delete branches after merge. Use
--delete-branchto clean up merged branches consistently. - Detect cycles. If the dependency graph has a cycle, exclude those PRs and report the cycle rather than entering an infinite loop.
Common Mistakes
| Mistake | Fix |
|---|---|
| Merging without user approval | The hard gate at step 8 is non-negotiable — always wait for explicit approval |
| Merging in wrong order | Always follow the computed topological sort — never skip ahead |
| Force-pushing during rebase | Use gh pr edit --base to retarget, never force-push |
| Ignoring draft PRs | Draft PRs must be flagged as blocked, not validated and merged |
| Trusting stale CI results | Always re-check statusCheckRollup and reviewDecision immediately before merging |
| Continuing a dependency chain after failure | If a parent PR fails, all downstream PRs in that chain must be skipped |
| Merging PRs that are in a cycle | Exclude cyclic PRs and report the cycle to the user |