/pr-review — one-shot read-only PR review
This is the thin entry point the pr-reviewer agent's own
documentation already promises (Trigger with /pr-review <PR-URL|#n>), and it does exactly one
thing: dispatch that agent at a PR and report what came back.
It never applies a finding, never pushes, and never resolves a thread. That is the whole distinction from its neighbours, and it is the reason to reach for this command rather than one of them: you get a review, and your working tree is exactly where you left it.
Contents
- Operations
- Step 0: Parse the argument
- Step 1: Resolve the PR
- Step 2: Dispatch the agent
- Step 3: Report
remember— write a maintainer relevance rule- Which review command do I want?
- Hard rules
Operations
Parse the first token of $ARGUMENTS.
| First token | Operation | Runs |
|---|---|---|
remember |
memory write | one mcp__lorekit__memory_write, no review |
| anything else (or empty) | review | one pr-reviewer dispatch, read-only |
There is no third operation, and no mode flag that turns this command into an apply pass.
A request to fix what the review found is /review-changes, below.
Step 0: Parse the argument
Everything after the PR reference is a pass-through flag: forward it verbatim and interpret none of it. The agent owns its own flag grammar, so a flag this skill has never heard of must still reach it.
# Known agent flags, listed for the argument-hint only — NOT a validation allowlist.
# --critical --full --effort high --with a,b,c --no-holistic --no-escalate
# --no-optimize --no-standards --skip-gates --fix-links
Never validate the flag list. A skill that rejects an unrecognised flag has to be edited every time the agent gains one, and the failure mode is silent: the user's flag is dropped and the review runs without it. Forward the tail unchanged and let the agent reject what it does not know.
Step 1: Resolve the PR
case "$ARGUMENTS" in
*github.com/*/pull/*|*\#[0-9]*) PR_REF="<the reference as given>" ;;
*) PR_REF=$(gh pr view --json url -q .url 2>/dev/null) ;; # current branch's open PR
esac
If no reference was given and the current branch has no open PR, stop with one line:
/pr-review: no PR reference given and no open PR on this branch. Pass a URL or #<n>, or open a draft PR first (/create-pr).
pr-reviewer has no PR-less mode — it reads threads, gates, and its own prior state from the PR
object — so there is nothing to degrade to here.
Where gh is unavailable (a sandbox with only the GitHub MCP server, for instance), resolve the
reference with mcp__github__pull_request_read instead of failing.
The agent itself is MCP-capable, so a missing gh is a resolution problem in this step and never a
reason to skip the review.
Step 2: Dispatch the agent
pr-reviewer is an agent, not a skill.
✅ RIGHT — through the harness's sub-agent dispatch tool
Task(subagent_type="pr-reviewer", prompt="<PR_REF> <pass-through flags>")
❌ WRONG — there is no skill by that name; this errors with `Unknown skill: pr-reviewer`
Skill("pr-reviewer", …)
That tool's NAME varies by harness — Task in the Claude Code CLI, Agent in
the Claude Agent SDK harness behind Claude Code on the web. Use whichever one
this session exposes; the call shape is identical. A tool taking a
subagent_type (or equivalent agent-name) parameter is the dispatch tool
whatever it is spelled.
Dispatch once. This command does not loop: a second pass over an unchanged head re-reads the
same code and re-posts the same report, and iterating a review against fixes is what
review-loop exists for.
When sub-agent dispatch is unavailable
Some harnesses expose no sub-agent dispatch tool at all. Establish that by
capability — no available tool dispatches a sub-agent under any name —
never from the absence of the single name Task, which would skip the review on
every harness that spells it Agent. When the capability is genuinely absent,
report the skip and stop:
/pr-review — skipped (sub-agent dispatch unavailable; pr-reviewer requires it).
Do not play the reviewer role in this context, and do not retry the dispatch. The agent's review independence comes from running in a fresh, isolated context; performing it inline produces a self-review wearing a reviewer's label, which is worse than no review because it is reported as one. One absent-dispatch return is conclusive — the capability's absence is a property of the dispatch topology, settled before any code is read, so a retry costs a round trip and returns the same answer.
Where another process reviews the PR instead (a review bot, a CI-triggered agent), the supported
path is Skill("review-loop", "<PR> --external-review"), which waits on that reviewer rather than
dispatching one.
Step 3: Report
The agent posts its own sticky report comment and its inline findings. This skill adds a terminal summary and nothing else — never a second GitHub write.
/pr-review on PR #<n> (<owner>/<repo>)
Verdict: <PASS | WARN | FAIL>
Run mode: <full | incremental | incremental-quick | zero-delta> · <deep | standard | quick> · <checkout | tarball | diff-only>
Findings: <N inline (<K> blocking)>, <D deferred (low-confidence, advisory)>
Gates: <one line naming any non-passing gate, or "all passing">
<one line per blocking finding: path:line — the ask>
Report: <URL of the sticky comment>
Apply these: /review-changes <PR> (or /implement-suggestion <PR>)
Surface blocking findings and non-passing gates prominently. This command applies nothing, so an unsurfaced blocker is a blocker the user never sees — the terminal summary is the only place the result reaches them in this flow.
Report the verdict as returned. Do not soften a FAIL because the findings look minor to you,
and do not upgrade a PASS because the diff looks risky: the gates and the verifier already made
that call with evidence, and re-adjudicating it here would make two disagreeing verdicts for one
run.
remember — write a maintainer relevance rule
/pr-review remember <fact> is the maintainer's direct write into the relevance memory the reviewer
reads on every run — the local equivalent of leaving the same comment on a PR, and the one write
path that needs no corroboration.
memory.md
owns the semantics; this section owns only the invocation.
Classify the direction from the wording:
| Wording | direction |
|---|---|
| "don't flag …", "stop flagging …", "we don't care about …" | suppress |
| "always check …", "watch for …", "this repo cares about …" | amplify |
The key must be an fp, or there is no rule to write
The reviewer matches rules by fingerprint at read time, so a rule stored under any other key is never read again.
node agents/pr-reviewer/scripts/fingerprint.mjs build \
--finder <finder> --defect-class <class> --symbol <symbol|-> --path <repo-relative path>
That needs three things the prose may not carry: a finder, a defect-class, and a path
(--symbol - covers a whole-file rule).
Infer what the fact determines, then:
- All three resolved → build the
fpand write the rule. - Any one missing → ask for it in one question, naming the candidates from the enums the script
validates against (
FINDERSandDEFECT_CLASSESinfingerprint.mjs).
Never invent a key to make the write succeed. A prose-slug key writes a record the read path
cannot see, which is indistinguishable from having stored nothing while looking like success — the
exact failure the structural fp_v: 2 space replaced.
✅ RIGHT
/pr-review remember don't flag maintainability in scripts/eval/golden/
→ fp = quality:maintainability:-@scripts/eval/golden/ → write suppress
❌ WRONG
/pr-review remember stop being so picky
→ no finder, no class, no path. Ask which finder and where; never write `rule::stop-being-so-picky`.
The write
mcp__lorekit__memory_write
tag: loop::reviewer-comment-relevance
key: rule::<fp>
scope: repo::{owner}/{repo}
ttl: 60d
body: { direction, status: "active",
source: { type: "human", agent: "other", explicit: true },
reason: "<the fact, verbatim>", scope_globs: [<glob>] }
status: active immediately, with no corroboration threshold: a maintainer saying "don't flag this"
is the evidence, and requiring three PRs' worth of it would be requiring them to say it three
times.
explicit: true is required. The agent filters every relevance-rule read on
source.agent == "pr-reviewer" ∨ source.explicit == true
(memory.md), and
without the flag this record is byte-identical to the incidental human comment that filter exists to
reject. Omitting it writes a rule the reviewer will never read — the same
looks-like-success-stores-nothing failure as inventing a prose key, arriving through the body
instead of the key.
Two rules remember cannot write
A suppress rule can never silence a standards finding or a (blocking) one.
Refuse those two and say which:
/pr-review: `standards` findings are not suppressible — they come from this repo's own governing
docs, so the fix is to change the doc (CLAUDE.md, AGENTS.md, .claude/rules/*.md), not to stop
enforcing it. Nothing was written.
The repo's written rule outranks its reviewers' fatigue, and a blocking finding is the one class
where a silent drop is most costly.
Both exemptions are the agent's, not this command's, so this refusal is a restatement of
memory.md and must not diverge from it.
Which review command do I want?
| Command | Reviews | Applies findings | Pushes | Loops |
|---|---|---|---|---|
/pr-review <PR> |
yes | no | no | no — one dispatch |
/review-changes <PR> |
yes | yes | yes | yes, via review-loop |
/review-changes <PR> --report |
yes | no | no | no |
review-loop |
yes | yes | yes | yes, cap 5, converges on threads + CI |
/polish |
yes | mechanical only | no | no — one pass each |
/pr-review <PR> and /review-changes <PR> --report reach the same place by design.
This command is the direct name for it, and it is what the agent's own description, depth-routing.md,
and memory.md all already tell the user to type; --report stays a flag on the convergence
command for people already there.
Hard rules
- Read-only, always. This command never edits a file, never commits, never pushes, and never resolves a thread. Applying is
/implement-suggestion; applying-and-converging isreview-loop. - Never write to GitHub. The agent posts its own sticky report and inline findings. This skill adds a terminal summary only — a second comment would duplicate a report that is rewritten in place precisely so a PR does not accumulate copies.
- Dispatch via the sub-agent dispatch tool, never
Skill().pr-revieweris an agent;Skill("pr-reviewer", …)errors withUnknown skill. The tool is namedTaskin some harnesses andAgentin others — use the one this session has. - One dispatch per invocation. Do not loop. Re-reviewing an unchanged head produces the same report at full cost.
- Absent sub-agent dispatch is a skip, not a fallback — and it is a CAPABILITY test, not a name test. Conclude it only when no available tool dispatches a sub-agent under any name; the absence of
Taskalone is not evidence. Then never review in this context and label it apr-reviewerreview, and never retry the dispatch. - Never validate the pass-through flags. Forward the tail verbatim; the agent owns that grammar and rejects what it does not know.
- Never re-adjudicate the verdict. Report
PASS/WARN/FAILas returned, with the blocking findings named. rememberwrites anfp-keyed rule or asks. A prose-slug key is unreadable by the read path and must never be invented to make a write appear to succeed.remembercannot suppress astandardsor(blocking)finding. Refuse and name the reason; those exemptions belong tomemory.mdand this command only restates them.