Skills DirectorySkills Directory
SkillsLearnSecurityCategoriesDocsCommunityBlog
Sign InSubmit Skill
Skills Directory

Security-tested agent skills for Claude, coding agents, and AI workflows.

Directory

  • Browse Skills
  • All Skills A–Z
  • Claude Skills
  • Claude Code Skills
  • Agent Skills
  • Categories
  • Submit a Skill

Learn

  • Learn Hub
  • Install Claude Skills
  • Write SKILL.md
  • Skills vs MCP
  • Directories Compared

Security

  • Security
  • Methodology
  • Secure Claude Skills
  • Security Badges

Company

  • About
  • Community
  • Blog
  • API Docs
  • Advertise

2026 Skills Directory. All rights reserved.

Back to skills

Pr Review

ASecurity

Review one or more GitHub pull requests as a progressive, understanding-first code review -- start at the highest altitude (what does it do, how, what to grasp before the details) and descend one abstraction layer at a time only when asked. Built for a senior engineer who wants to understand a PR before spending review time on it. Use when the user runs /pr-review with one or more PR links (often a frontend + backend pair), or asks to "review this PR" / "review these PRs". Treats the code dif...

3 stars
0 votes
0 copies
0 views
Added 9/20/2026
code-qualitygoreacttestinggitapifrontendbackend

Works with

terminalcliapi

Security Analysis

A100/100

Scanned 9/20/2026

Install to Claude Code

$npx -y skills add nvie/skills --skill pr-review --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Pr Review?

Add the live security badge to your README — it updates automatically with every re-scan.

Security grade badge for Pr Review
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/nvie-pr-review/badge)](https://www.skillsdirectory.com/skills/nvie-pr-review)

More formats (shields.io, HTML) on the badges page.

Download Zip
Files
SKILL.md
---
name: pr-review
description: >
  Review one or more GitHub pull requests as a progressive, understanding-first
  code review -- start at the highest altitude (what does it do, how, what to
  grasp before the details) and descend one abstraction layer at a time only when
  asked. Built for a senior engineer who wants to understand a PR before spending
  review time on it. Use when the user runs /pr-review with one or more PR links
  (often a frontend + backend pair), or asks to "review this PR" / "review these
  PRs". Treats the code diff as the source of truth and the PR description as
  context, reads the PR's existing discussion so it doesn't repeat points already
  raised, and keeps every finding at the current altitude of the review. Surfaces
  only interesting findings and good questions to ask the author -- never a
  checklist dump.
---

# PR Review (progressive, understanding-first)

Help a senior engineer understand and review one or more GitHub PRs without
wasting their time. The reviewer is smart and busy. They want to build an
accurate mental model of the change *first*, then decide where to spend their
focus. Your job is to be the fast, honest guide through that -- not to spray
every nit you can find.

The change being reviewed is often **split across repos** -- a backend PR and a
frontend PR that land together. Treat such a set as **one logical change**. The
contract between the parts (a protocol bump, a shared type, an API the other side
consumes) is frequently the most interesting thing to review.

## The two rules that override everything

1. **Code is the source of truth, the PR description is context.** Read the
   description for intent and motivation, but verify every claim against the
   diff. When they disagree, the code wins -- and that disagreement is itself an
   interesting finding worth reporting.

2. **Only report interesting findings.** If there's nothing notable about
   backward compatibility, don't mention backward compatibility. A review that
   says "naming looks fine, tests look fine, no concerns" is a *good* outcome --
   say that in one line and move on. Never pad. Never invent concerns to look
   thorough. Genuine compliments ("this is a clean way to model X") are valid
   findings too.

## Inputs

Invoked as `/pr-review <pr-url> [<pr-url> ...]`. Each argument is a GitHub PR
link. Zero arguments + a checked-out branch means "review the current branch's
PR" -- find it with `gh pr view`.

## Getting the code

Prefer **local code** over the GitHub API whenever it's available -- the user
usually runs this from a worktree group with the PR branches already checked out,
so you can read full files for context, run scripts, execute tests, and try out
theories instead of squinting at an isolated diff.

For each PR URL, parse `owner/repo/number`, then:

1. **Try local first.** Look for a checkout of that repo with the PR's branch.
   `gh pr view <number> --repo <owner>/<repo> --json headRefName,title,body,state`
   gives you the branch name and description; `git worktree list` (and sibling
   directories) tells you what's checked out nearby. If you find it, read and run
   code there. The diff to review is `git diff <base>...HEAD` on that branch.
2. **Fall back to `gh`.** If there's no local checkout, use
   `gh pr diff <url>` for the changes and `gh pr view <url>` for the description.
   You lose the ability to run things, but you can still review.

Read the description(s) and the full diff(s) of **all** PRs before saying
anything. Build the model first.

**Also read the existing comments and discussions** on each PR
(`gh pr view <url> --comments`, plus review threads). Know what's already been
raised so you don't repeat points that are under active discussion -- skip those.
Following up on an existing thread is fine *when it matches the current altitude
of the review*: don't drag a deep implementation nit into the high-level Layer 1
pass just because someone already commented on it.

## How the review flows

This is a **conversation in layers, not a report**. Go one layer deep, then
**stop and let the user steer**. They may want to drill into one finding, skip a
layer, take a question to a coworker, or jump straight to the deep dive. Never
dump all layers at once.

Throughout, write for a human reading on a couch, not a robot parsing an IDE:
**avoid file paths, line numbers, and function names unless they're truly the
clearest way to say something.** Talk in concepts. (Contrast: the final
thermo-nuclear layer is where precise locations finally matter.)

**At every layer, watch for what's *missing*, not just what's there** -- and
raise each gap as a question for the author. What's missing differs by altitude:
conceptually at the top (an unhandled case in the design, a scenario the approach
doesn't account for, a stated goal the PR doesn't actually reach), and
functionally or tactically lower down (a missing test for a risky path, an
unhandled error, an edge case the code skips). A gap is often the most valuable
finding in a review -- the diff can't show you what isn't there.

### Layer 1 -- What is this, really? (start here, always)

The goal: give the user the mental model they need *before* looking at details.

- **What does it do, and how does it achieve that?** Start from the very top.
  What's the most important change? What's the shape of the approach?
- **What should they understand conceptually before the details?** The one or
  two ideas that, once they click, make the rest of the diff obvious.
- **A before/after example when it helps.** A tiny, concrete "here's how this
  worked before, here's how it works after this lands." A code/`diff` block or a
  one-line scenario beats a paragraph of prose.
- **Rollout -- but only the interesting parts.** Mention these *only* when there
  is something worth knowing: backward-incompatible changes, what's user-visible
  vs purely internal, whether it needs multiple deployments or a migration to
  roll out safely, and what's in this PR vs deferred to later. If a dimension is
  unremarkable, stay silent on it.

Then offer **~5-10 initial observations**: a mix of the sharpest *questions you'd
ask the author* and genuine *compliments*. Favor questions that probe intent,
risk, and design choices over surface nits. If a change looks controversial or
early-stage, suggest asking those questions on the PR *now*, before either of you
sinks time into a deep review.

**Then stop.** Let the user react before going deeper.

### Layer 2 -- Concepts, naming, and data design

Only on request. One level below the summary, still above implementation:

- Are the **new concepts** clear and unambiguous -- both on their own and
  against the *existing* vocabulary in the codebase? A name that's fine in
  isolation but collides with an established concept is a real problem.
- Confusing names, leaky abstractions, data structures that don't fit the
  problem.
- **Public vs private API.** This distinction is critical. Naming and shape of
  **public, user-facing APIs** matters enormously -- it's hard to change later
  and users live with it. Internal APIs can be renamed freely, so hold them to a
  lower bar and say so. Spend your scrutiny where it counts.

**If anything here is a real flag, stop and surface it.** Some concerns are
worth raising before going deeper -- the user may want to resolve a naming or
data-model objection with the author before either of you reviews implementation
that might change anyway.

### Layer 3 -- Implementation

Only on request. Now look at the code itself: is it modular, clear, elegant? Are
the abstractions pulling their weight? Is there adequate test coverage for the
risky parts? Are there edge cases the diff misses? This is where running the
tests or trying a theory locally earns its keep.

Concrete checks worth running here:

- **No non-test constants in test inputs.** Tests should show *raw literal
  inputs and expected outputs*, not values pulled from the code under test. When
  a test feeds in something like `Permission.RoomWrite` instead of the literal
  `"room:write"`, the reader can't see what's actually being exercised at
  runtime, and the test stops independently pinning down the constant's value --
  if the enum's value silently changes, the test moves with it instead of
  catching it. Prefer inlining the literal, and flag cases where a test imports
  enums/constants/config from the module it's testing. (See
  https://dev.to/scottshipp/don-t-use-non-test-constants-in-unit-tests-3ej0.)

- **Look for properties worth a `fast-check` property test.** Beyond
  example-based tests, ask: does any new API have an *invariant* that should hold
  across *all* inputs? Property tests over a generated input space buy far more
  confidence in correctness than a handful of hand-picked cases. When you spot a
  good candidate, point it out and sketch the property. Common shapes to look
  for:
  - **Invariants** -- something always true regardless of input. E.g. "no matter
    what combination of scope strings you pass, the `personal` capability is
    always `write`", or "no matter what capability matrix you give the resolver,
    `personal` is always `write`".
  - **Idempotence** -- resolving/normalizing once equals resolving twice. E.g.
    "for any capability matrix, resolving it and then resolving that result
    again yields the same value, equal to the first result."
  - Other classics: round-trips (`decode(encode(x)) === x`), commutativity,
    monotonicity, and "output always satisfies invariant Y." Surface whichever
    fit the new APIs.

### Layer 4 -- Deep code-quality audit

When the user wants the harshest pass, hand off to the
**`thermo-nuclear-code-quality-review`** skill. That's the right tool for
strict maintainability and abstraction-quality scrutiny; don't reimplement it
here.

## Anchoring a finding to an inline PR comment

When a finding is concrete enough that the user might leave it as an **inline
comment** on the PR, give them a precise place to put it: which PR, which file,
and the single best line number (the one line the comment should attach to, not a
range). Whenever possible, hand them a ready-to-click GitHub deep link straight to
that line in the diff.

GitHub's per-line diff anchor looks like:

```
https://github.com/<owner>/<repo>/pull/<number>/files#diff-<hash><side><line>
```

- `<hash>` is the lowercase **SHA-256 of the file's path** relative to the repo
  root. Compute it with `printf '%s' '<path>' | shasum -a 256`.
- `<side>` is `R` for the new/right side of the diff (the added or current line --
  what you almost always want) or `L` for the old/left side.
- `<line>` is the line number on that side.

So a comment on line 86 (new side) of a file hashing to `008ee2…628d` becomes
`…/pull/1769/files#diff-008ee2…628dR86`. (`/files` and `/changes` both work as
the path segment.)

**Prefer selecting a whole block when the comment is about one.** If the finding
concerns a small self-contained unit -- a single test case, a helper function, a
method, a short block -- that spans no more than ~20 lines, link to the entire
range instead of one line. GitHub anchors a range by appending the end line:

```
…#diff-<hash><side><start>-<side><end>
```

e.g. `…#diff-008ee2…628dR86-R98` selects lines 86-98 on the new side. Keep ranges
tight and meaningful: only span a block that genuinely reads as one unit, and
fall back to a single line for anything larger or more diffuse.

For a finding that's about the **file as a whole** -- or that sits at/just past
the end of the file where a line anchor is awkward -- don't anchor to a line at
all. Link to the file's diff with the bare `#diff-<hash>` anchor (no `<side>` or
`<line>`):

```
https://github.com/<owner>/<repo>/pull/<number>/files#diff-<hash>
```

The user leaves a top-level, file-level comment there instead.

If you can't reliably build the link (e.g. you're working from `gh pr diff`
without the path settled), fall back to stating PR + file + line in plain text so
the user can navigate there themselves.

### Emitting the link so it stays clickable

The link is only useful if the user can Cmd+click it in the terminal, so emit it
in the one form that survives both the Markdown renderer and Ghostty's OSC 8
hyperlink detection:

- **Print the complete URL as a bare URL on its own line.** Full SHA-256 hash, no
  `…` ellipsis (the truncations above are for readability in *this* doc -- a
  shortened hash resolves to nothing). The whole thing must be literal so the
  terminal autolinks it.
- **Never wrap it in backticks.** Inline code renders as non-clickable text, not
  a link. No `[label](url)` Markdown link either -- emit the raw URL; that's what
  both the renderer and OSC 8 reliably turn into a clickable target.
- **Put nothing adjacent to it.** No trailing `.`, `,`, `)`, or `>` touching the
  URL, and no opening `(`/`<` right before it -- terminals greedily swallow such
  characters into the link target and break it. Surround the URL with whitespace
  or line breaks on both sides.
- These anchors only ever contain `[A-Za-z0-9#-]`, so there's nothing to
  percent-encode; the rules above are the whole job. If a future link ever does
  carry a space or other special character, leave it raw on its own line rather
  than escaping it -- escaping is what breaks OSC 8.
- **Always print the human-readable location underneath the link** -- the file
  path and the line number(s), e.g. `path/to/file.test.ts:86` or
  `path/to/file.test.ts:86-98`. GitHub sometimes refuses to auto-expand and
  highlight the anchored range (it caps how far it'll unfold a collapsed diff),
  leaving the user staring at a link that lands nowhere useful. The file + lines
  let them jump straight to the spot by hand. This is a plain-text caption, so
  backticks are fine here.

## Turning a numbered suggestion into a comment

Number your findings/suggestions whenever you present a batch of them, so the user
can refer back to one. When the user replies with just a number (e.g. `4`) -- or
"comment on 4", "do 2 and 5" -- they want that suggestion turned into a
ready-to-leave PR comment. For each referenced number:

1. **Print the GitHub deep link** to that finding's location, following all the
   rules in "Emitting the link so it stays clickable" above (bare, complete URL,
   on its own line, range anchor when it's a block). This is the line the user
   clicks to open the comment box at the right spot.
2. **Then write the comment body** in GitHub-flavored Markdown, ready to `/copy`
   and paste into that box. The user edits it online before submitting. Follow
   the comment voice below. Use backticks around identifiers and a fenced
   ` ```suggestion ` block when you're proposing a concrete code change GitHub
   can apply:

   ````markdown
   When I read tests I like seeing the raw inputs. I think `Permission.RoomWrite`
   is an implementation detail here, and it hides what's actually being tested at
   runtime. Maybe inline the literal?

   ```suggestion
       expect(permissionCapabilitiesFromScopes(["room:write"])).toEqual({
   ```
   ````

   Put the comment body in its own fenced block in your reply so the user can
   `/copy` it cleanly. Match the comment to the review's current altitude, and if
   one comment covers several spots (e.g. "same applies below"), say so in the
   body rather than emitting a near-duplicate per line.

### Comment voice

The reviewer is a colleague, not a judge. Keep comments simple, friendly, and
curious. The goal is always to improve the end product, but the tone is "let's
figure this out together," not "here's what's wrong."

- **Keep it simple.** Short sentences, plain words. Don't write academically or
  pad with jargon.
- **No em dashes.** And go easy on bolded bullet lists -- a comment is usually
  just a sentence or two of prose.
- **Don't state opinions as facts.** Take a curious stance: ask a question, or
  open with "I think", "I believe", "if I recall correctly", "maybe", "a bit"
  ("this reads a bit confusingly to me"), "I'd lean toward...", "would it make
  sense to...". Leave room for the author to disagree or know better.
- **Show, don't lecture.** A tiny example or a `suggestion` block makes the point
  faster than a paragraph explaining it.
- **Stay friendly and constructive.** Even when pushing for a change, you're on
  the author's side trying to make the thing better.

## Output style

- **Concise. Sacrifice grammar for concision** where it helps.
- Concepts over coordinates -- minimal file/line/function references (until
  Layer 4, or when anchoring a comment as above).
- Honest. Don't hedge, don't pad, don't manufacture findings. "Nothing
  interesting here" is a complete and welcome answer.
- One layer at a time, then pause.

Attribution

nvienvie
View sourceMore from nvie →
SSkills DirectorySkills Directory

Your tool, in front of Claude Code builders.

3 founder slots · $299/mo · GSC-verified traffic · sponsors can never buy grades.

See placements

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments (0)

No comments yet. Be the first to comment!

SSkills DirectorySkills Directory

Your tool, in front of Claude Code builders.

3 founder slots · $299/mo · GSC-verified traffic · sponsors can never buy grades.

See placements

Related Skills

Caveman Review

Ultra-compressed code review comments. Cuts noise from PR feedback while preserving the actionable signal. Each comment is one line: location, problem, fix. Use when user says "review this PR", "code review", "review the diff", "/review", or invokes /caveman-review. Auto-triggers when reviewing pull requests.

1023331 votes

Caveman Commit

Ultra-compressed commit message generator. Cuts noise from commit messages while preserving intent and reasoning. Conventional Commits format. Subject ≤50 chars, body only when "why" isn't obvious. Use when user says "write a commit", "commit message", "generate commit", "/commit", or invokes /caveman-commit. Auto-triggers when staging changes.

1023331 votes

Verification Loop

一个全面的 Claude Code 会话验证系统。

2456590 votes

Springboot Verification

Verification loop for Spring Boot projects: build, static analysis, tests with coverage, security scans, and diff review before release or PR.

2456590 votes

Django Verification

Verification loop for Django projects: migrations, linting, tests with coverage, security scans, and deployment readiness checks before release or PR.

2456590 votes
View all in code-quality →