# Pr Review

> Use when authoring a code review of a pull request or merge request — "review this PR", "do a code review on PR

- Skill: `provectus/pr-review` (Agent Skill, multi-file: 6 files)
- Install (CLI): `npx skillmds@latest add provectus/pr-review`
- Raw SKILL.md: https://api.skillmd.com/api/skills/provectus/pr-review/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: provectus (https://skillmd.com/u/provectus)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/provectus/pr-review

---


<!-- No `context: fork`: a forked skill runs as a subagent, and subagents cannot use AskUserQuestion — the results gate in step 5 depends on it. (The Agent tool is not the constraint: subagents can dispatch nested subagents, so the step 2 engines would run fine.) For isolation from other work, invoke this skill in a dedicated session instead. -->

# Author a Code Review

Produce a code review that reads like a sharp human wrote it and opens a conversation. You draft, the user steers, the user approves before anything is posted or saved.

## Modes

Decide the mode before starting the workflow, and state it in one line — the workflow branches on it.

- **public** (default): review a PR **someone else authored** on the hosting platform. Read the existing conversation, post the result as a **draft (pending) review** the user finalizes and submits. This is the primary use. Uses the platform reference selected below.
- **local**: review **your own working branch** for yourself. Nothing is posted or published — produce the review as a file. Use this when the request says "locally", "for myself", "just my branch", "don't post", or otherwise targets in-progress work rather than someone else's PR. The built-in `/review`-style tools also do this, but less reliably and without the human-gated, house-style flow here. Uses [references/local.md](references/local.md).

**Choosing:** if the request clearly signals local (the trigger words above, or a bare branch with no PR), use local. If it clearly targets a specific remote PR (a PR URL or `owner/repo#N`), use public. If it's ambiguous, ask with `AskUserQuestion`, offering Public as the default.

## Platform (public mode)

Resolve the platform before step 1 and state it alongside the mode. Resolve in this precedence order, taking the first that answers — a later signal never overrides an earlier one:

1. the host in the PR/MR URL the user gave;
2. the host of the repo's `git remote` (`git remote get-url origin`);
3. which CLI is authenticated (`gh auth status` / `glab auth status`).

`github.com` or a GitHub Enterprise host → [references/github.md](references/github.md). `gitlab.com` or a self-managed GitLab host → [references/gitlab.md](references/gitlab.md). If none of the three resolves, ask with `AskUserQuestion` — never guess, since the wrong reference posts nothing or posts to the wrong place.

The workflow below is platform-agnostic and names operations (`preflight`, `fetch-pr-context`, `create-draft-review`, …); the selected reference defines them. It says "PR" throughout — on GitLab read merge request, and `<NUM>` as the MR `iid`. Local mode needs none of this.

This skill orchestrates existing review engines rather than reinventing analysis (both modes). It depends on two plugins and degrades gracefully if absent — see [references/analysis.md](references/analysis.md):

- **code-review** — a confidence-scored multi-agent sweep for breadth.
- **pr-review-toolkit** — specialized agents (`code-reviewer`, `comment-analyzer`, `pr-test-analyzer`, `silent-failure-hunter`, `type-design-analyzer`) for depth on the dimensions a diff actually touches.

Review voice and formatting rules are in [references/house-style.md](references/house-style.md).

## Input

`args` is a PR reference (public) or a branch/base hint (local): a PR URL, `owner/repo#N`, a bare `N` inside the repo, a branch name, or empty (use the current branch). Parse what you can; if public mode needs a PR you can't resolve, ask for a PR URL.

## Workflow

```
- [ ] 1. Gather the change and context
- [ ] 2. Find issues (code-review + applicable pr-review-toolkit agents)
- [ ] 3. Triage in a fresh subagent (merge, discipline; public: reconcile)
- [ ] 4. Draft in house style: summary, architectural notes, inline findings
- [ ] 5. Results gate: print the draft and ask — back with sources / proceed / change
- [ ] 6. Deliver (public: draft review; local: review file)
- [ ] 7. Summarize; loop on re-review (public)
```

### 1. Gather the change and context

- **both modes:** if the request links or references an off-platform discussion — a Slack thread, meeting notes, a roadmap or ticket, a design doc — read it **before** analysis (via whatever tool or link gives you access). It carries the change's intent and any decisions already settled, which the diff and the on-platform threads don't show; reviewing without it risks re-raising something the author and reviewer already worked out elsewhere.
- **public:** run `preflight`, `fetch-pr-context`, and `fetch-existing-comments` from the platform reference (selected above), **before** any analysis — so you know what the PR does, what's already been said, which threads are open, and whether you (or the user) have reviewed it before. `preflight` also settles **whether draft delivery is available on this platform and instance** — carry that answer to step 5, which needs it before it can ask the user anything. `fetch-existing-comments` includes an explicit pass to list your own prior comments; do it — they're the easiest set to duplicate. When the existing conversation is large, don't read the raw dump yourself: hand it to a subagent that returns a structured scratchpad — open threads, settled points, your own prior comments, each with `path:line` — and run that digest in parallel with fetching the diff. It's extraction, not judgment, so a small/fast model suffices if agent dispatch lets you pick one; with no agent dispatch, compact it inline. Either way the scratchpad, not the raw conversation, is what the analysis pass carries. Comment only on lines the PR changed.
- **local:** run `resolve-base` and `get-local-diff` from [references/local.md](references/local.md). There's no existing conversation to fetch.

### 2. Find issues

Follow [references/analysis.md](references/analysis.md) — the same engines work on a PR diff or a local diff. Run the `code-review` plugin's confidence-scored sweep and dispatch the `pr-review-toolkit` agents that match what the diff changed. Collect both engines' raw findings with each one's confidence and source; the merge, the false-positive discipline, and reconciliation all happen inside step 3's triage subagent, not here.

### 3. Triage in a fresh subagent

A review is worth only as much as its independence, and the merge is where independence quietly dies: deciding which findings survive, and at what confidence, is exactly the judgment a session that wrote, planned, or debated this change would bend toward its own decisions. A model is a poor judge of its own anchoring, so don't self-assess independence; remove the need for it: triage runs in a **fresh subagent** that never sees this conversation, whether the session touched the change or not.

Dispatch one triage subagent with the Agent tool (`subagent_type: "general-purpose"` — a fresh context; **not** `"fork"`, which inherits this conversation and defeats the isolation). Hand it exactly:

- the diff and the repo checkout path;
- both engines' raw findings — file, line, what, why, suggested fix, confidence, source;
- **public:** the scratchpad from step 1 — open threads, settled points, `$ME`'s prior comments, each with `path:line` — plus any off-platform source material (verbatim or an extractive digest of what was decided, never your conclusions about the change);
- the path to [references/analysis.md](references/analysis.md), with the instruction to apply its "Merge and carry forward" and "False-positive discipline" sections.

Withhold everything else — what this session intended, designed, or argued about the change. The diff, the engines' output, and the recorded conversation are the subagent's whole world, so its verdicts can't be a defense of decisions it never saw.

The subagent merges and dedupes both engines into one findings list, then applies the false-positive discipline — it has repo access, and the verification work there (`Read` the file, `Grep` the sibling artifact) is its job; for a long list it may fan the mechanical per-finding checks out to its own nested subagents (duplicate-of-thread, `$ME`-commented line, line-in-diff — matching, not judgment, so a small/fast model suffices). **Public:** it also reconciles against the scratchpad: for any finding on a `path:line` `$ME` already commented on, plan a `reply-to-thread` that builds on that thread rather than a second comment — even if the prior thread is resolved; for any open thread, plan a `reply-to-thread` (agree, build on, or push back) instead of a duplicate inline comment; drop points already raised and settled — in a PR thread or off-platform — and keep only what's new. It returns the surviving findings (confidence and source intact) and the thread-reply plan. **Local:** same subagent, no scratchpad — nothing to reconcile.

If agent dispatch is unavailable (rare — e.g. running at the subagent nesting depth limit, where the engines already degraded to the inline pass): merge, apply the discipline, and reconcile inline, re-deriving each verdict from the diff and the engines' output rather than from what you remember intending, and carry a one-line independence caveat into the step 7 summary (never into the posted review).

### 4. Draft in house style

Turn the survivors into a review per [references/house-style.md](references/house-style.md). Separate the two buckets explicitly:

- **Inline findings** — anchored to `path:line`, each a plain-voice comment.
- **Architectural notes** — cross-cutting observations not tied to a single line. These go in the summary body (public) or the "Architectural notes" section of the file (local).

No severity badges, plain citations. Order by what matters, explained in words. Draft a one-line **verdict** intent for public mode (request changes / comment / approve), but don't act on it until delivery.

**Pick the verdict from what the remaining findings can cost, not from how many there are.** Classify each survivor by two things: how often that code actually runs, and what goes wrong when it does.

- **request changes** — it changes what the code does on a path that runs normally, or it loses data, corrupts state, or opens a security hole. Rarity doesn't rescue those: a one-in-a-million path that corrupts data still blocks.
- **approve** — nothing major remains. A finding is *not* major when it is confined to code that runs only in rare situations **and** its worst outcome is limited to visibility — log fields, alert payloads, diagnosability — or to performance. Docs, comments and test hygiene never block on their own.
- **comment** — the residue: a real defect on an ordinary path that isn't severe enough to block, or a question whose answer could change the design. If you're reaching for comment because approving *feels* presumptuous, that's not a reason — apply the rule.

Holding a PR open over log-field quality and comment accuracy costs more in cycle time than those findings cost in risk — and it costs most on a late round, where the remainder is nearly always visibility and hygiene. Approving is a statement about the verdict, never a reason to drop or soften a finding: post them all, and say plainly in the summary why you're approving anyway. This is the verdict *intent* either way — the user picks the verdict at delivery.

**Materialize the draft with `Write`** to the `review/` folder of **the repo whose code is under review** — the same one local mode delivers into (create it if missing; it stays out of commits, gitignored or per the user's preference): `review/pr-<N>-draft.md`. In a multi-repo or orchestrator checkout, that means the service's own clone, not the parent — say which path you used, since a sibling `review/` from an earlier session is easy to confuse it with. A draft composed only in thinking does not exist — the `Write` call is the verifiable proof it does, and an in-repo file is one the user can open in their editor no matter what happens to the chat. Don't proceed to the gate without this file.

### 5. Results gate

Print the complete draft **as message text** — summary, architectural notes, and the inline findings (each with `path:line`) — then ask the user with `AskUserQuestion` how to proceed. The user can only approve what they can read: if the draft isn't in the message, the gate is void. Any session-wide brevity or compression mode (terse-output instructions, token-saving styles) governs your commentary, never the deliverable — a file path, a recap, or "the review is above" does not satisfy this step.

**Read the draft once more before printing it**, against [references/house-style.md](references/house-style.md)'s "What never goes in a posted review". Four things to strike, every one of which reached a real MR: a finding that opens on mechanism instead of the defect; a sentence carrying more than one claim; any phrasing that implies you ran, tried, or reproduced something (this skill never executes anything); and any line about the review itself — what you read, how you checked, what you couldn't check. Then confirm the summary opens on the MR and your overall read, not on the first bug.

**Pre-gate protocol — the draft is the step 4 file, not your memory.** Present it by printing the file's full content as message text, then call `AskUserQuestion` — and always include the file path in the question itself ("full draft in `review/pr-<N>-draft.md`"), so even if the print gets squeezed out, the user opens the draft in their editor from the path alone. The documented failure of this step (three sessions running): composing the draft in thinking, then gating on "the draft is above" while the message contains nothing — your memory of having printed is not evidence; only the `Write` call from step 4 and text visible in this turn are. If there is no step 4 file, you have no draft: go back and write it.

**Check delivery capability before you ask, not after.** `preflight` established whether this platform and instance support a draft. If they don't (a GitLab instance without the Draft Notes API, a token missing the scope, an MCP fallback with no draft tool), **the options below are wrong as written** — "Proceed" would publish the review immediately under a label the user read as "draft". Say plainly in the gate that draft delivery isn't available here and why, then offer **publish now** (post the findings and summary for real, right away) or **write to a file and post nothing** (local mode's artifact, so nothing reaches the platform) — and let the user pick with full knowledge of what lands. Never present a publishing action as a draft.

- **Proceed** — deliver as-is (post the draft review, or write the file).
- **Back findings with external sources** (optional) — before delivering, run the evidence pass: for each contestable finding, verify against a trusted source (official docs, the language/library spec, a high-signal StackOverflow answer, an issue in the project's own hosted repo — GitHub/GitLab/Gerrit/… — or, for an architectural claim about how the system fits together, the project's own sibling repos and artifacts, not just external docs), attach the link in the comment, and **drop claims you can't substantiate**. "Substantiate" means verified against the code or the spec — a project-specific finding grounded in the diff stands on its own and needs no external citation. Then re-present the revised draft and return to this gate — don't deliver until the user picks Proceed.
- **Change something** — take the user's edits (reword, drop, split a point into its own inline comment, re-anchor), restate, and confirm.

Respect the user's granularity choices — don't fold a distinct observation into the summary if they want it inline, and don't merge separate points. Post or write nothing before the user picks Proceed.

### 6. Deliver

- **public:** first run `find-pending-review`. If a draft already exists, apply the **never-destroy rule** (never delete or recreate it — it may hold the user's own comments; stop and ask, or append if the platform supports it and the user agrees). Otherwise `create-draft-review` — a pending review the user submits in the platform UI, the **default**. Only if the user explicitly chose to submit now, `submit-review` with the verdict. Send any approved `reply-to-thread` replies. Verify the summary actually posted, in whatever form the platform carries it. If the gate established that drafts aren't available here, deliver what the user chose there instead — publish now, or write the file and post nothing.
- **local:** `write-review-file` and print the path. Nothing is sent anywhere.

Posting/saving is automated after approval; judgment is not. In public mode, if the platform rejects a comment for an out-of-diff line, move it into the summary body and retry rather than dropping it silently.

### 7. Summarize and loop

Print what was delivered (the draft review URL and inline count, or the file path and counts) with the PR URL on its own line in public mode.

**Public mode: end the turn with the summary body verbatim, copy-paste ready.** Print the full summary text in a fenced markdown block, then the verdict intent and any thread replies sent, and make clear it's a draft awaiting their submit. A recap or description of the summary does not satisfy this — only the verbatim text does, and no session-wide brevity or compression mode shrinks it. Run the same self-check as the results gate: if the turn's final message doesn't visibly contain the fenced summary block, it wasn't delivered — text composed in thinking renders nothing. It applies to **every** turn that ends with the draft created or partially delivered, including turns cut short by errors or permission walls. The platform may not show the draft's summary until submit — or may have silently dropped it at creation — so this final message can be the user's only copy of the text to paste when submitting.

**Amendments after delivery (public).** The workflow doesn't end at step 6 — the user will ask for changes to what you just posted ("add architectural notes", "that finding is unclear", "cut the last one"). **Every one of those re-enters step 5 before anything is written to the platform:** draft the new or revised text, update the step 4 file, print it, `AskUserQuestion`, then post. Amend in place with the platform's edit operation; never delete and recreate.

A request to change something approves the **action**, never the **wording** — "yes, add architectural notes" is permission to draft them, not to publish whatever you draft. The failure this prevents was observed across six consecutive amendments in one session: each was drafted and posted in a single step, with the text shown to the user only afterwards, so the gate that governs first delivery silently stopped applying to everything after it. Post-delivery is exactly when the user is most engaged and most likely to be surprised.

**Re-review loop (public).** This skill works under `/loop`. On a later round, repeat steps 1–6, but diff against your previous review's timestamp and treat your own prior comments as part of the conversation — raise only what's new or unaddressed and converge toward approve. **Don't itemize the fixes the author made since the last round** — not even a one-line recap of which items now look right; "everything from the last round is addressed" covers it. Confirm whether it's all addressed or say what still stands, thank them, and go straight to what's new — see the re-review summary example in [references/house-style.md](references/house-style.md). The user still approves each round; the loop automates the cadence, not the judgment.

## Boundaries

- Never post, submit, or save anything the user hasn't approved at the results gate — including every amendment made after delivery.
- Never write the review as if you executed anything. This skill reads code; it doesn't run it, so "I tried", "I couldn't reproduce" and "I went looking" are always false here.
- Never narrate the review inside the review — method notes, what you read, and coverage caveats go to the user in step 7, not to the author on the platform.
- Never author an engine's findings yourself. An engine that reports nothing has failed; say so and degrade, rather than reconstructing its output and passing it to triage as engine input.
- Never poll for agent results with `sleep`/`until` loops, and never read agent transcripts to recover them — see [references/analysis.md](references/analysis.md).
- Hand the triage subagent only the diff, the engines' findings, the recorded conversation, and the code — never this session's reasoning, intent, or debate about the change, and never a fork that inherits it.
- Never delete or recreate an existing pending review draft without explicit approval — it may hold the user's own comments.
- In public mode: comment only on lines in the PR diff; never resolve other people's threads; never auto-approve — the user chooses that verdict; default to a draft, not a direct submit.
- Don't re-raise a point already settled — in a PR thread or off-platform — unless the new changes make it live again; don't post a finding you couldn't verify — lower its confidence and drop it.
- No severity badges, no performative praise, no "generated by" footer.
- Session-wide brevity or compression modes never shrink a deliverable: the step 5 draft and step 7 summary print in full, verbatim, as message text.
- Don't run builds, typecheck, or lint to find issues — CI covers those; flagging them is noise.

