Local PR review
Review a PR against what its ticket asked for, verify every finding by
running code, and write it all to a local scratchfile — never to GitHub.
Flow
- Target — first that applies: given PR number (
gh pr view/diff <N>);
current branch's open PR (gh pr view); local diff vs base
(git diff <base>...HEAD). Say which you used.
- Spec — find a ticket reference anywhere: branch name, PR title, PR
description. Teams differ; there is no fixed pattern. Fetch the ticket via
the Jira/Atlassian MCP tools. MCP missing or ticket unreachable → the PR
description becomes the spec. Neither exists → infer intent from the code
and say so in the overview. Beyond ticket-hunting, the PR description is
not review input — judge the changes, not the pitch.
- Big picture — establish what the project does and what the touched
area is for: README, CLAUDE.md, directory layout, the modules around the
change. A diff can be locally correct and still wrong for the system.
- What changed — describe the change at business level: "fixes the
duplicate image on the product page", never "renamed a to b, added an if".
No code in the overview.
- Scope check — ticket vs changes: matches / misses pieces / does
unrelated extras. Fundamental mismatch (solves a different problem) →
stop and ask whether to review anyway. Anything less → record it in the
overview's verdict line, keep going.
- Find problems — correctness (edge cases, wrong data, unhandled
errors, races) and design (should this exist in this shape, consistency
with sibling code, silent breaking changes). Ground every candidate in
code you actually read: open the definitions the diff calls, check the
data model, compare with siblings.
- Verify — every finding gets tested before it's written up, as you go
or in one batch at the end, whichever is cheaper. Prefer a failing test
that reproduces the bug — include it in the comment; it's the most useful
artifact you can hand the author. When a test can't capture it, run the
app and interact with it. Testing needs the PR's code: work in place if
already on the branch with a clean tree, otherwise a temporary git
worktree. Delete temp tests and worktrees after. Genuinely impractical to
test (network, third parties)? High-confidence inference is acceptable —
hedge honestly in the comment and mark the proof line. Discard whatever
fails verification: a killed false positive is the system working.
- Write — fill the template below.
- Humanize — run the prose through the
writing:humanize skill. No
fake-personal voice in either direction ("I really like this PR…"):
genuine strengths go under Quality points as factual bullets; the user
writes their own compliments from them.
Comment format
Comments are grouped by file: one ## per file, one ### per comment under
it, so the user can fold each file and each handled comment while working
through the list. The ### heading is Lines N-M — plain-language title.
Everything between the heading and the proof line is the pasteable comment.
A comment is, in order:
- The alert block: tier + the consequence in a few words.
- One paragraph, at most two sentences: what breaks and what it costs,
consequence first, in terms a non-engineer could follow.
- At most one evidence block — a ```diff fix, a small table, or
input → expected vs got. It shows what the paragraph claims; it never
restates the paragraph.
Lines 41-48 — retried webhooks silently drop orders
[!WARNING]
Should-fix — orders can disappear with no trace
When the payment provider retries a webhook, the second save fails and the error is swallowed — the order is lost and nothing is logged.
- } catch (e) {}
+ } catch (e) { logger.error(e); throw e; }
Verified: test double-firing the webhook — order row gone, no log line.
Match that example's length and density. Hard limits:
- Budget: pasteable prose ≤ 500 characters per comment (alert text +
paragraph + any bullet text). Count it, don't eyeball it.
- Named exception — incident risk: a warning about data loss, a security
hole, or breaking prod keeps whatever length it needs. Cut explanation,
never warnings.
- Mandatory cut pass: draft the comment, then cut half of it; only the
cut version lands in the file. First drafts calibrate to "thorough".
- Never hard-wrap prose anywhere in the file. GitHub renders every
newline inside a comment as a line break, so one paragraph = one line;
let the editor soft-wrap.
Never include in a comment:
- The code restated in words, or anything the diff makes obvious.
- Background the author already has — they wrote the PR.
- How you found the problem.
- A second fix option. Pick the best one; if the choice genuinely belongs to
the author, name the options in one sentence.
- The same fact as both prose and bullets.
Other rules:
- Bullets over prose whenever they're easier to scan and end up shorter;
they count toward the budget.
- Fixes as ```diff blocks whenever concrete — GitHub renders them red/green.
- Other files referenced → markdown links with relative paths.
- Backtick every identifier, column, and path.
- Below the comment, a proof line for the user's triage (not pasted):
Verified: or Inferred: .
Severity
| Tier |
Alert |
Bar |
| Blocker |
[!CAUTION] |
breaks prod, loses data, security hole |
| Should-fix |
[!WARNING] |
real bug or trap; fix before or right after merge |
| Suggestion |
[!TIP] |
improves the change; author's call |
| Nitpick |
[!NOTE] |
style or taste; fine to ignore |
Tier + a few-word reason on the alert's first line. Torn between tiers →
pick the lower.
Output template
Write <repo-root>/pr-<N>-review-notes.md (no PR: review-notes-<branch>.md).
Keep the ##/### levels — they fold.
# PR #<N> — <TICKET-KEY>: review notes
Scratch file — not for committing. One ## per file, one ### per comment; paste the block under it.
## Overview
<Business-level description, 2-5 sentences. No code.>
_Verdict: <one italic line — does what the ticket asked / misses X / also does unrelated Y>_
**Ticket:** <one line — what it asks for>
## Quality points
<At most 3 bullets, each a fact the author can't already see: something you verified beyond what CI runs, or a non-obvious decision that's right. CI results, linter output, and praise adjectives never qualify. Nothing qualifies → delete this section.>
## `path/to/file.ext`
### Lines N-M — <plain-language title>
<alert block, paragraph, evidence — the pasteable comment>
_Verified/Inferred: …_
## Related findings (pre-existing, not this PR)
<Same format. Optional follow-ups — never review feedback on this PR.>
Don't
- Post anything to GitHub (
gh pr review, gh pr comment) unless asked
afterward.
- Invent findings. A clean PR gets no file-level
## sections and an honest
Quality points list (or none) — that's a valid, complete review.
- Leave traces: temp tests deleted, worktrees removed, the user's branch and
uncommitted work untouched.
1---2name: local-review3description: Use when reviewing a pull request or branch locally without posting to GitHub — the user says "review PR #N", "review this PR locally", "check this branch's changes", "review my diff", asks whether a PR matches its ticket or does what the task asked, or wants review comments written to a file to read, filter, and copy before publishing anything.4---56# Local PR review78Review a PR against what its ticket asked for, verify every finding by9running code, and write it all to a local scratchfile — never to GitHub.1011## Flow12131. **Target** — first that applies: given PR number (`gh pr view/diff <N>`);14 current branch's open PR (`gh pr view`); local diff vs base15 (`git diff <base>...HEAD`). Say which you used.162. **Spec** — find a ticket reference anywhere: branch name, PR title, PR17 description. Teams differ; there is no fixed pattern. Fetch the ticket via18 the Jira/Atlassian MCP tools. MCP missing or ticket unreachable → the PR19 description becomes the spec. Neither exists → infer intent from the code20 and say so in the overview. Beyond ticket-hunting, the PR description is21 not review input — judge the changes, not the pitch.223. **Big picture** — establish what the project does and what the touched23 area is for: README, CLAUDE.md, directory layout, the modules around the24 change. A diff can be locally correct and still wrong for the system.254. **What changed** — describe the change at business level: "fixes the26 duplicate image on the product page", never "renamed a to b, added an if".27 No code in the overview.285. **Scope check** — ticket vs changes: matches / misses pieces / does29 unrelated extras. Fundamental mismatch (solves a different problem) →30 stop and ask whether to review anyway. Anything less → record it in the31 overview's verdict line, keep going.326. **Find problems** — correctness (edge cases, wrong data, unhandled33 errors, races) and design (should this exist in this shape, consistency34 with sibling code, silent breaking changes). Ground every candidate in35 code you actually read: open the definitions the diff calls, check the36 data model, compare with siblings.377. **Verify** — every finding gets tested before it's written up, as you go38 or in one batch at the end, whichever is cheaper. Prefer a failing test39 that reproduces the bug — include it in the comment; it's the most useful40 artifact you can hand the author. When a test can't capture it, run the41 app and interact with it. Testing needs the PR's code: work in place if42 already on the branch with a clean tree, otherwise a temporary git43 worktree. Delete temp tests and worktrees after. Genuinely impractical to44 test (network, third parties)? High-confidence inference is acceptable —45 hedge honestly in the comment and mark the proof line. Discard whatever46 fails verification: a killed false positive is the system working.478. **Write** — fill the template below.489. **Humanize** — run the prose through the **`writing:humanize`** skill. No49 fake-personal voice in either direction ("I really like this PR…"):50 genuine strengths go under _Quality points_ as factual bullets; the user51 writes their own compliments from them.5253## Comment format5455Comments are grouped by file: one `##` per file, one `###` per comment under56it, so the user can fold each file and each handled comment while working57through the list. The `###` heading is `Lines N-M — plain-language title`.58Everything between the heading and the proof line is the pasteable comment.5960A comment is, in order:61621. The alert block: tier + the consequence in a few words.632. One paragraph, at most two sentences: what breaks and what it costs,64 consequence first, in terms a non-engineer could follow.653. At most one evidence block — a ```diff fix, a small table, or66 input → expected vs got. It shows what the paragraph claims; it never67 restates the paragraph.6869### Lines 41-48 — retried webhooks silently drop orders7071> [!WARNING]72> **Should-fix** — orders can disappear with no trace7374When the payment provider retries a webhook, the second save fails and the error is swallowed — the order is lost and nothing is logged.7576```diff77- } catch (e) {}78+ } catch (e) { logger.error(e); throw e; }79```8081_Verified: test double-firing the webhook — order row gone, no log line._8283Match that example's length and density. Hard limits:8485- **Budget: pasteable prose ≤ 500 characters per comment** (alert text +86 paragraph + any bullet text). Count it, don't eyeball it.87- **Named exception — incident risk:** a warning about data loss, a security88 hole, or breaking prod keeps whatever length it needs. Cut explanation,89 never warnings.90- **Mandatory cut pass:** draft the comment, then cut half of it; only the91 cut version lands in the file. First drafts calibrate to "thorough".92- **Never hard-wrap prose anywhere in the file.** GitHub renders every93 newline inside a comment as a line break, so one paragraph = one line;94 let the editor soft-wrap.9596Never include in a comment:9798- The code restated in words, or anything the diff makes obvious.99- Background the author already has — they wrote the PR.100- How you found the problem.101- A second fix option. Pick the best one; if the choice genuinely belongs to102 the author, name the options in one sentence.103- The same fact as both prose and bullets.104105Other rules:106107- Bullets over prose whenever they're easier to scan and end up shorter;108 they count toward the budget.109- Fixes as ```diff blocks whenever concrete — GitHub renders them red/green.110- Other files referenced → markdown links with relative paths.111- Backtick every identifier, column, and path.112- Below the comment, a proof line for the user's triage (not pasted):113 _Verified: <how>_ or _Inferred: <why still confident>_.114115## Severity116117| Tier | Alert | Bar |118| ---------- | ------------ | ------------------------------------------------- |119| Blocker | `[!CAUTION]` | breaks prod, loses data, security hole |120| Should-fix | `[!WARNING]` | real bug or trap; fix before or right after merge |121| Suggestion | `[!TIP]` | improves the change; author's call |122| Nitpick | `[!NOTE]` | style or taste; fine to ignore |123124Tier + a few-word reason on the alert's first line. Torn between tiers →125pick the lower.126127## Output template128129Write `<repo-root>/pr-<N>-review-notes.md` (no PR: `review-notes-<branch>.md`).130Keep the `##`/`###` levels — they fold.131132```markdown133# PR #<N> — <TICKET-KEY>: review notes134135Scratch file — not for committing. One ## per file, one ### per comment; paste the block under it.136137## Overview138139<Business-level description, 2-5 sentences. No code.>140141_Verdict: <one italic line — does what the ticket asked / misses X / also does unrelated Y>_142143**Ticket:** <one line — what it asks for>144145## Quality points146147<At most 3 bullets, each a fact the author can't already see: something you verified beyond what CI runs, or a non-obvious decision that's right. CI results, linter output, and praise adjectives never qualify. Nothing qualifies → delete this section.>148149## `path/to/file.ext`150151### Lines N-M — <plain-language title>152153<alert block, paragraph, evidence — the pasteable comment>154155_Verified/Inferred: …_156157## Related findings (pre-existing, not this PR)158159<Same format. Optional follow-ups — never review feedback on this PR.>160```161162## Don't163164- Post anything to GitHub (`gh pr review`, `gh pr comment`) unless asked165 afterward.166- Invent findings. A clean PR gets no file-level `##` sections and an honest167 _Quality points_ list (or none) — that's a valid, complete review.168- Leave traces: temp tests deleted, worktrees removed, the user's branch and169 uncommitted work untouched.