Take an open PR from wherever it is to "ready to merge", and report exactly
what still needs a human when automation can't finish the job.
-
Detect the forge and pick the CLI: Read the remote
(git remote get-url origin) and choose the matching CLI, verifying it is
installed and authenticated before proceeding:
| Host in remote URL | CLI | PR concept | Auth check |
|---|
| github.com / GHE | gh | pull request | gh auth status |
| gitlab.com / self-hosted GitLab | glab | merge request (MR) | glab auth status |
| Gitea / Forgejo / Codeberg | tea | pull request | tea login list |
The steps below are written with gh; on another forge, translate each
operation to the equivalent verb (gh pr view -> glab mr view --output json / tea pr <n>, gh pr comment -> glab mr note, gh run view -> glab ci view, gh pr update-branch -> glab mr rebase, review
threads -> glab api projects/:id/merge_requests/:iid/discussions).
Confirm exact flags with --help rather than guessing. If the forge has
no CLI (e.g. Bitbucket), fall back to git plus the forge's REST API via
curl, and list anything you cannot automate as a blocker in the report.
-
Identify the PR: Resolve the argument (number or URL) or the current
branch's PR via gh pr view. If no PR exists, stop and suggest the pr
skill. If it is a draft, continue fixing but only mark it ready
(gh pr ready) at the end, once everything else passes.
-
Assess: Take one snapshot of the PR state:
gh pr view <n> --json number,title,body,url,state,isDraft,mergeable,mergeStateStatus,reviewDecision,reviewRequests,latestReviews,statusCheckRollup,baseRefName,headRefName,maintainerCanModify,closingIssuesReferences
Then fetch unresolved review threads (only GraphQL exposes resolution):
gh api graphql -f owner=<owner> -f repo=<repo> -F pr=<n> -f query='
query($owner:String!,$repo:String!,$pr:Int!){
repository(owner:$owner,name:$repo){ pullRequest(number:$pr){
reviewThreads(first:100){ nodes{
id isResolved isOutdated path line
comments(first:20){ nodes{ author{login} body } }
}}
}}
}'
Then discover the merge gates: gh api repos/{owner}/{repo}/rules/branches/<base>
lists required status checks, required approving review count, and whether
code-owner review is required (readable without admin). If that returns
nothing, infer gates from mergeStateStatus and reviewDecision.
Build a blocker list and split it in two: fixable by automation
(conflicts, failing checks, unaddressed comments, stale description,
missing bot trigger, draft state) vs human-only (required approving
reviews from people or CODEOWNERS, org settings, missing secrets).
-
Sync with base: If mergeStateStatus is BEHIND, run
gh pr update-branch <n>; if that fails, merge the base locally and push.
If DIRTY (conflicts), check out the branch, git fetch origin and
git merge origin/<base>, resolve each conflict by reading the surrounding
code and preserving the intent of both sides (never resolve by blindly
taking one side), then commit the merge and push. Never force-push.
-
Get CI green: For each failing entry in statusCheckRollup, pull the
logs (gh run view <id> --log-failed), diagnose the root cause, fix it,
commit conventionally, and push (the fix-and-retry workflow). If a
failure is flaky or external (network, rate limit), re-run it instead:
gh run rerun <id> --failed. For third-party bot checks that re-trigger
via a comment command, find the documented phrase (step 7) rather than
pushing an empty commit.
-
Address review comments: For each unresolved, non-outdated thread:
-
Actionable code feedback: apply the fix, commit, push, reply briefly
to the thread stating what changed, then resolve it via GraphQL:
gh api graphql -f id=<threadId> -f query='
mutation($id:ID!){ resolveReviewThread(input:{threadId:$id}){ thread{ isResolved } } }'
-
Question: answer it in a reply; resolve only if fully answered.
-
Disagreement or judgment call: reply with your reasoning and leave
the thread unresolved for the human to close.
-
Bot approvals and re-reviews: If a required check or review comes from
a bot that is triggered by a comment (Claude, CodeRabbit, Copilot, CLA
bots, /retest-style CI bots), find its exact trigger phrase from prior
comments on this PR, recent merged PRs in the repo, or
CONTRIBUTING/README, then post it: gh pr comment <n> --body '@claude review'.
Never invent a trigger phrase; if none is discoverable, list the bot as a
blocker in the report. If a bot approved before you pushed new commits,
its approval may be stale; re-trigger it after your last push.
-
Issues and description hygiene:
- Linked issues: check
closingIssuesReferences; if empty, look for an
issue number in the branch name, commit messages, or by searching open
issues for the feature/bug. If the PR clearly fixes one, add
Closes #<n> to the body.
- Title: conventional-commit style, under 70 chars, describing the
current diff (it may have drifted as commits were added).
- Body: ensure a
## Summary reflecting the full current diff and a
## Test plan. Augment what a human wrote rather than rewriting it.
Apply with gh pr edit <n> --title ... --body ... (HEREDOC for body).
-
Re-assess and loop: After pushes, repeat step 3. Wait for new CI runs
by matching headSha to the new HEAD (see gotchas), not by watching the
latest run. Loop until every fixable blocker is cleared or only human-only
blockers remain. Then, if the PR is a draft and everything else is green,
gh pr ready <n>.
-
Report using this template: