Install any skill in seconds. Free to start, no credit card required.
Get Started Free →The authority on pulling a pull request — Azure DevOps or GitHub — into an isolated local worktree so a human can review it in their editor, and on posting human-controlled review comments back to the PR (ADO via the ado PR-thread MCP tools or the Azure DevOps REST API, GitHub via the gh CLI). Auto-detects the platform and all identifiers from the PR URL; not tied to any specific repository. The AI assists an interactive human review and only ever posts comments the human explicitly requests. If
.claude/skills/microsoft-review-pr-local/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-08 | ✗→✓ | ▲ Improved | 49% | 0% |
| case-10 | ✗→✓ | ▲ Improved | 54% | 0% |
| case-12 | ✗→✓ | ▲ Improved | 47% | 0% |
| case-13 | ✗→✓ | ▲ Improved | 85% | 0% |
| case-14 | ✗→✓ | ▲ Improved | 115% | 0% |
Check out a pull request into an isolated git worktree — never disturbing the user's current checkout — surface its changes in the editor, run an interactive review where the human drives, and post only the comments the human asks for. All identifiers are derived from the PR URL, so the skill works against any ADO or GitHub repository.
This is the core of the skill. Violating it defeats the purpose.
post comment on line 53 of src/foo.ts - this returns before the lock is released). Post it verbatim.add a comment on the null check in bar.ts). Draft it terse and high-signal, show it, and post only after the human approves.file:line and is 1–3 sentences.Detect the platform and extract every identifier from the URL — nothing is hardcoded.
| Platform | URL shape | Extract | |----------|-----------|---------| | Azure DevOps | https://<org>.visualstudio.com/<project>/_git/<repo>/pullrequest/<id> or https://dev.azure.com/<org>/<project>/_git/<repo>/pullrequest/<id> | org, project, repo, id | | GitHub | https://github.com/<owner>/<repo>/pull/<number> | owner, repo, number |
If given a bare number instead of a URL, use AskUserQuestion to get the full URL (or the platform + identifiers).
| Platform | Ensure tooling | Auth check → recovery | |----------|----------------|-----------------------| | Azure DevOps | az extension show --name azure-devops — if absent, az extension add --name azure-devops | az account show; on failure prompt the user to run az login, then stop | | GitHub | gh --version | gh auth status; on failure prompt the user to run gh auth login, then stop |
For ADO, pass the org explicitly on every command: --organization https://<org>.visualstudio.com. If any later az call fails with an auth error, prompt the user to re-run az login.
| Platform | Command | Fields | |----------|---------|--------| | Azure DevOps | az repos pr show --id <id> --organization https://<org>.visualstudio.com --output json | sourceRefName, targetRefName, lastMergeSourceCommit.commitId (head), lastMergeTargetCommit.commitId (base) | | GitHub | gh pr view <number> --repo <owner>/<repo> --json headRefName,baseRefName,headRefOid,baseRefOid | headRefName, baseRefName, headRefOid (head), baseRefOid (base) |
Never run git checkout / gh pr checkout in the user's working directory. Always use a separate worktree.
git rev-parse --show-toplevel.<repo-name>-pr-<id-or-number>.git worktree list, skip to Step 5.| Platform | Fetch head | Fetch base | |----------|------------|------------| | Azure DevOps | git fetch origin <source-branch> | git fetch origin <head-commit> <base-commit> | | GitHub | git fetch origin pull/<number>/head (works for forks) | git fetch origin <base-branch> |
git worktree add --detach <worktree-path> <head-commit>
This writes the full tree and can take minutes on a large monorepo — use a long timeout and let it finish.
The editor's Source Control panel shows only uncommitted changes, so a committed PR branch looks empty. Soft-reset the detached worktree to the PR's merge-base so the PR's changes become staged changes with per-file diffs.
git -C <worktree-path> merge-base <head-commit> <base-commit>git -C <worktree-path> diff --stat <merge-base> <head-commit>git -C <worktree-path> reset --soft <merge-base>code <worktree-path> — changed files appear under Staged Changes. Tell the user not to run git pull there (it re-applies the commits and hides the diff); an already-open editor needs a Source Control refresh.<merge-base>..<head-commit>) and the modified files for context.file:line + a one-line reason. Default to few.Parse each request into file, line, and body (draft the body only if the human asked the AI to write it, then get approval). Post one comment per request. Read existing threads first to avoid duplicates.
Anchor identifiers come from Step 1 (org/project/repo/id) and Step 3 (<head-commit>). File paths are repo-relative. In the examples below, substitute the values parsed in Step 1 for every <...> placeholder.
Preferred: the ado/repo_create_pull_request_thread MCP tool with a threadContext:
organization: <org>
project: <project>
repositoryId: <repo>
pullRequestId: <id> # integer
content: "This returns before the lock is released."
threadContext:
filePath: "/<repo-relative-path>" # leading slash
rightFileStart: { line: <n>, offset: 1 }
rightFileEnd: { line: <n>, offset: 5 }REST fallback (when the ado MCP server is not configured) — uses the az login token:
az rest --method post \
--resource 499b84ac-1321-427f-aa17-267ca6975798 \
--uri "https://dev.azure.com/<org>/<project>/_apis/git/repositories/<repo>/pullRequests/<id>/threads?api-version=7.1" \
--headers "Content-Type=application/json" \
--body @thread-body.jsonwhere thread-body.json is { "comments": [{ "parentCommentId": 0, "content": "...", "commentType": 1 }], "status": "active", "threadContext": { "filePath": "/<repo-relative-path>", "rightFileStart": { "line": <n>, "offset": 1 }, "rightFileEnd": { "line": <n>, "offset": 5 } } }. Generate the body with a JSON serializer, not string interpolation. Delete the temp file afterward.
Same MCP tool or REST call, omit threadContext (and the body's threadContext).
gh api --method POST /repos/<owner>/<repo>/pulls/<number>/comments \
-f body="This returns before the lock is released." \
-f commit_id=<head-commit> \
-f path=<repo-relative-path> \
-F line=<n> \
-f side=RIGHTTo post several inline comments as one review, batch them via gh api /repos/<owner>/<repo>/pulls/<number>/reviews (event COMMENT).
gh pr comment <number> --repo <owner>/<repo> \
--body "Validation approach looks solid overall."Rules for all paths: call ADO MCP tools server-qualified (ado/repo_*) — never ado-repo_* aliases; pullRequestId is an integer; prefer inline over general when the human gives a line. Confirm each post back to the human with the PR link.
When finished, remove the worktree (never affects the user's own branch):
git worktree remove --force <worktree-path>If the directory is locked (an editor still has it open), close that editor window, then re-run the remove and git worktree prune.
origin: if the three-dot diff looks far larger than the PR, the local base ref is stale — re-fetch the base commit/branch and recompute the merge-base.pull/<number>/head; don't assume the head branch exists on origin.| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→fail | 14,877 | 23,203 | +56% | 1 | 1 | 0% | 3,013 | 3,244 | +8% | 0 | 0 | — |
case-02 | fail→fail | 17,148 | 11,642 | -32% | 1 | 1 | 0% | 2,616 | 2,918 | +12% | 0 | 0 | — |
case-03 | fail→fail | 10,867 | 9,031 | -17% | 1 | 1 | 0% | 2,057 | 3,043 | +48% | 0 | 0 | — |
case-04 | pass→pass | 8,591 | 5,271 | -39% | 1 | 1 | 0% | 1,475 | 3,199 | +117% | 0 | 0 | — |
case-05 | pass→pass | 14,283 | 5,706 | -60% | 1 | 1 | 0% | 2,566 | 3,547 | +38% | 0 | 0 | — |
case-06 | fail→fail | 2,988 | 19,219 | +543% | 1 | 1 | 0% | 502 | 3,102 | +518% | 0 | 0 | — |
case-07 | fail→fail | 9,624 | 5,016 | -48% | 1 | 1 | 0% | 1,854 | 3,228 | +74% | 0 | 0 | — |
case-08 | fail→pass | 12,950 | 5,523 | -57% | 1 | 1 | 0% | 2,217 | 3,297 | +49% | 0 | 0 | — |
case-09 | pass→pass | 13,388 | 4,758 | -64% | 1 | 1 | 0% | 2,400 | 3,279 | +37% | 0 | 0 | — |
case-10 | fail→pass | 10,831 | 2,524 | -77% | 1 | 1 | 0% | 1,866 | 2,880 | +54% | 0 | 0 | — |
case-11 | pass→pass | 8,782 | 5,581 | -36% | 1 | 1 | 0% | 1,272 | 3,411 | +168% | 0 | 0 | — |
case-12 | fail→pass | 16,157 | 8,090 | -50% | 1 | 1 | 0% | 2,456 | 3,621 | +47% | 0 | 0 | — |
case-13 | fail→pass | 11,241 | 5,237 | -53% | 1 | 1 | 0% | 1,718 | 3,183 | +85% | 0 | 0 | — |
case-14 | fail→pass | 7,873 | 2,849 | -64% | 1 | 1 | 0% | 1,337 | 2,877 | +115% | 0 | 0 | — |
case-15 | pass→fail | 11,184 | 3,191 | -71% | 1 | 1 | 0% | 1,497 | 2,915 | +95% | 0 | 0 | — |
case-16 | fail→pass | 8,335 | 9,948 | +19% | 1 | 1 | 0% | 1,667 | 3,426 | +106% | 0 | 0 | — |
case-17 | pass→pass | 10,247 | 4,821 | -53% | 1 | 1 | 0% | 2,102 | 3,392 | +61% | 0 | 0 | — |
case-18 | pass→pass | 11,584 | 4,305 | -63% | 1 | 1 | 0% | 1,141 | 3,239 | +184% | 0 | 0 | — |
case-19 | pass→pass | 11,345 | 7,322 | -35% | 1 | 1 | 0% | 2,024 | 3,895 | +92% | 0 | 0 | — |
case-20 | fail→pass | 8,506 | 5,048 | -41% | 1 | 1 | 0% | 1,465 | 3,431 | +134% | 0 | 0 | — |
case-21 | pass→pass | 20,578 | 13,790 | -33% | 1 | 1 | 0% | 3,604 | 4,973 | +38% | 0 | 0 | — |
case-22 | pass→pass | 11,086 | 6,199 | -44% | 1 | 1 | 0% | 1,810 | 3,269 | +81% | 0 | 0 | — |
case-23 | pass→pass | 8,836 | 6,571 | -26% | 1 | 1 | 0% | 1,594 | 3,658 | +129% | 0 | 0 | — |
case-24 | pass→fail | 9,350 | 8,367 | -11% | 1 | 1 | 0% | 1,446 | 2,890 | +100% | 0 | 0 | — |
case-25 | fail→fail | 10,028 | 11,227 | +12% | 1 | 1 | 0% | 1,634 | 3,940 | +141% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 25 cases were attempted, and 20 counted toward the lift figure. The other 5 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of +20 percentage points is the difference between those two pass rates over the 20 comparable cases. 6 cases got worse with the skill loaded, and they are included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.