Merge pull requests, one at a time
Merge only what the API proves mergeable, one PR per step, and re-read the API before every claim. The enemy is a merge script that remembers a CI status instead of re-reading it: one such run auto-closed a stacked PR and reported a merge that never happened. The overcorrection is batching: several merges in one command hide which gate failed for which PR.
Invoking this skill authorizes the merges it performs on the PRs the user named, or on every open PR when the user said so; it authorizes nothing else.
Steps
- List.
gh pr list --json number,title,baseRefName,headRefName. Keep the user's order when they named PRs; otherwise take the list order. Print the table before touching anything. - Gate, per PR, from the API. Run
gh pr view <n> --json number,title,mergeable,mergeStateStatus,statusCheckRollup,baseRefName,headRefName,reviewDecision --jq '{number,title,mergeable,mergeStateStatus,reviewDecision,baseRefName,headRefName,checks:[.statusCheckRollup[]|{name,context,conclusion,state}]}'and print that JSON; the sliced checks keep a PR with many workflows under one screen of output. Merge only whenmergeStateStatusisCLEANand every entry instatusCheckRolluphasconclusionSUCCESSorstateSUCCESS.BLOCKED,BEHIND,DIRTY,UNSTABLE,UNKNOWN, a pending check, or aCHANGES_REQUESTEDreview is a stop for that PR: report it and continue with the next PR. Never read the status from memory or from an earlier step. - Stack check. A PR is a base when another open PR's
baseRefNameequals itsheadRefName. Merge bases before the PRs stacked on them, and never pass--delete-branchfor a PR that is a base: GitHub closes the stacked PR when its base branch disappears. Say which PRs this applies to. - Merge one.
gh pr merge <n> --squash(or the repository's documented merge method) without--delete-branch. Branch deletion is a separate, explicitly authorized step and never runs here. - Re-verify.
gh pr view <n> --json state,mergedAtmust showstateMERGED. Report a merge only after that read; otherwise report the PR as not merged with the JSON that says so. Stacked PRs then need a fresh gate, since their base just moved. - Report. One table: PR, gate result, merged yes/no, blocking reason.
When
git worktree listnames a worktree on a merged PR's branch, add one line naminggit worktree remove <path>for the user to run; this skill removes nothing. Stop and report as soon as anything is ambiguous. Do not retry a failed merge unchanged.
Judgment
- API JSON read in this step outranks any earlier read or remembered status.
- A stop for one PR outranks finishing the list: report it, never force, never relax a gate.
- The user's authorization outranks this skill's defaults, except the
--delete-branchandgit branch -Dprohibitions, which need their own explicit instruction naming the branch.