microsoft/review-external-pr
Triage an external contributor's PR and prepare it for merge. Detects push permission, base branch, draft state, size, and history quality, then picks one of three paths (review-only, direct push to contributor branch, or a `reviews/` staging branch). Use when triaging or reviewing a community PR, deciding whether maintainer changes are needed, choosing a merge strategy (squash/merge/rebase), or merging an external contribution.
npx skills add https://github.com/microsoft/vscode-documentdb --skill review-external-pr
A triage-first workflow for handling community PRs. The skill inspects first, asks two questions, then executes. It never creates branches preemptively.
pr/<owner>/<PR_NUMBER> branch (created by gh pr checkout)Resolve, in order:
pr/<owner>/<PR_NUMBER> → extract <PR_NUMBER>.gh pr status → active PR for current branch.gh pr view <PR_NUMBER> --json number,title,author,url,state,isDraft,\
headRefName,baseRefName,headRepositoryOwner,maintainerCanModify,\
mergeable,mergeStateStatus,additions,deletions,changedFiles,commits,labels
| Signal | Rule |
| --------------- | ----------------------------------------------------------------------------------------------------------------------------- | ----- | -------------- | ---- | ------ | ----- |
| canPushToHead | headRepositoryOwner.login == "microsoft" OR maintainerCanModify |
| baseBranch | baseRefName (do not hardcode main) |
| isDraft | warn if true |
| mergeable | warn if mergeable != "MERGEABLE" (values: MERGEABLE, CONFLICTING, UNKNOWN) |
| mergeReady | warn if mergeStateStatus is not CLEAN (other values: DIRTY, BLOCKED, BEHIND, UNSTABLE, HAS_HOOKS, UNKNOWN) |
| commitCount | commits.length |
| messyHistory | any commits[].messageHeadline (the first line of the commit message, returned by gh pr view --json commits) matches /wip | fixup | address review | typo | merge( | $)/i |
| changedLines | additions + deletions |
| sizeBucket | small ≤ 50 changed lines, medium ≤ 300, large > 300 (uses changedLines) |
| Condition | Recommend |
| ------------------------------------------------- | ------------------------------------------------------- |
| commitCount == 1 | No squash (rebase or merge) — history already clean |
| commitCount ≤ 3 AND no messy subjects AND small | Ask, default no squash |
| commitCount > 3 OR messy subjects detected | Squash (default) |
PR #<PR_NUMBER> — <title>
Author: <login> (<fork|same-repo>)
Base: <baseBranch>
State: <state>, <draft?>, mergeable=<mergeable>, mergeStateStatus=<mergeStateStatus>
Push to head: <✅ allowed reason | ❌ blocked reason>
Size: +<additions> / -<deletions> across <changedFiles> file(s), <commitCount> commit(s)
History: <clean | messy: "<sample messageHeadline>">
Recommendation:
• Path: <direct push | reviews/ branch | review-only>
• Merge: <--squash | --merge | --rebase> (<reason>)
Stop here and present the report.
Ask only these. Pre-select the recommended option.
canPushToHead, otherwise Path Creviews/ staging branch)If canPushToHead == false, omit the "direct push" option and explain: _"Contributor disabled maintainer edits; we must use a reviews/ branch."_
Offer --squash, --merge, --rebase with the recommended option marked. Justify the default in one short sentence (e.g., _"4 commits including 'fix typo' — squash recommended"_).
Run commands non-interactively, echoing each one. After merge, print a one-line summary with the merged commit/PR URL.
gh pr checkout <PR_NUMBER> # optional, for local inspection
# review, leave comments via the PR UI or `gh pr review`
gh pr merge <PR_NUMBER> --<strategy> # against the PR's actual base
Requires canPushToHead == true.
gh pr checkout <PR_NUMBER> # sets up a remote tracking the fork branch
# make changes, commit
git push # updates the existing PR in place
gh pr merge <PR_NUMBER> --<strategy>
The existing PR updates in place; the contributor keeps authorship of their commits and maintainer commits are attributed to the maintainer. No second PR is needed.
reviews/ staging branchUse when push to head is blocked, or when the maintainer explicitly wants to isolate rework.
Branch slug sanitization — derive <slug> from the PR title:
[a-z0-9] characters with a single -.-.- again if the cut left one.Example: "fix(tree): sort _id_ index first / cleanup" → fix-tree-sort-id-index-first-c.
Full branch name: reviews/<slug>-pr-<PR_NUMBER>.
git fetch origin
git checkout -b reviews/<slug>-pr-<PR_NUMBER> origin/<baseBranch>
git push -u origin reviews/<slug>-pr-<PR_NUMBER>
Retarget the contributor's PR:
gh pr edit <PR_NUMBER> --base reviews/<slug>-pr-<PR_NUMBER>
gh pr view <PR_NUMBER> --json baseRefName # verify
> ⚠️ gh pr edit --base may print a deprecation warning about Projects (classic). Cosmetic only — the base change succeeds.
Merge the contributor's PR into the review branch:
gh pr merge <PR_NUMBER> --<strategy>
Pull and create the finalization PR back to the original base:
git checkout reviews/<slug>-pr-<PR_NUMBER>
git pull origin reviews/<slug>-pr-<PR_NUMBER>
gh pr create \
--base <baseBranch> \
--head reviews/<slug>-pr-<PR_NUMBER> \
--title "<original title> [reviewed]" \
--body "Finalizes review of @<author>'s contribution in #<PR_NUMBER>.
Original PR: <PR_URL>"
Comment on the original PR:
gh pr comment <PR_NUMBER> \
--body "Thanks for the contribution! Review continues in #<NEW_PR_NUMBER> where maintainer changes are finalized before merging to \`<baseBranch>\`."
| Strategy | When to use |
| ---------- | -------------------------------------------------------------------------------------------------------------------- |
| --squash | Default for messy/multi-commit external PRs. One revert undoes the change. Contributor still gets authorship credit. |
| --merge | Large feature where individual commits are meaningful and worth preserving. |
| --rebase | Single clean commit, or a series of clean atomic commits you want linear on the base. |
main as the base — always read baseRefName.reviews/ branch in Phase 1.mergeable == "CONFLICTING" or mergeStateStatus != "CLEAN", stop and surface that before any merge command.| Phase | What happens | Output |
| ----- | ---------------------------------------------------------- | --------------------------- |
| 1 | Read PR metadata, derive push capability + recommendations | Triage report |
| 2 | Ask Q1 (path) and Q2 (merge strategy) | Decision |
| 3 | Execute the chosen path with the chosen merge strategy | Merged PR / finalization PR |
Take microsoft/review-external-pr from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.