PR Review
All PR comment operations (reading, writing, replying) MUST go through gh-review. Do NOT use raw
gh api or gh pr for any review-related task.
MUST run gh-review --help before the first invocation in a session and read the target command's
signature from that output. It lists every command with its full signature in one pass. Never infer
arguments from this skill, from another command, or from a previous session; optional positionals in
one command are required in another. Use gh-review <command> --help only for option semantics.
This skill covers workflow and semantics only.
Critical Rules
- NEVER submit reviews. The user manually submits pending reviews via GitHub UI.
- Inline comments MUST go through a pending review; never post them directly. Replies follow Replying to Comments.
- Pass Markdown bodies as
--body -with a single-quoted heredoc. Double-quoted bodies execute backticks as shell commands beforegh-reviewreceives them. - When a line target is outside diff hunks,
commentautomatically retries as a file-level comment on the same file. The output includes anote:line indicating the fallback. No manual retry or relocation needed.
Review Etiquette
Tone
- Bugs/defects: Direct language ("I think this is a bug...", "This will cause...")
- Style/architecture: Questions ("What do you think about...", "Would it make sense to...")
- Use contractions, be conversational, comment on code not developer
- Skip comments that just repeat what other reviewers already said
- Bot comments (infer from context:
[bot]suffix, known CI/analysis tools, automated comment patterns): use neutral, factual statements. Explain what was done and why, or why something will not be done. Do not address the bot conversationally or phrase replies as if speaking to a person.
Verification
Use ctx7 to verify unfamiliar patterns, best practices, and security implications before writing
comments. Use web search when Context7 lacks coverage. Every technical claim must be verified.
Reading a PR
gh-review view hides resolved threads unless you pass --all. Pass it whenever the question is
what already happened on the PR: whether a finding was raised before, or whether your own review
landed. A published review whose threads were all resolved is invisible without it, which reads as
"never posted." --author LOGIN narrows output to one participant.
The default view hides threads whose last comment is yours, so a reviewer's rebuttal is invisible
there. After publishing replies, re-run with --unanswered before calling the cycle done.
Inline comments belonging to an unsubmitted review are tagged [pending, unsubmitted], and the
PENDING REVIEWS section prints the draft body and each inline comment. Nothing there is visible to
anyone else yet.
Pending Review Workflow
gh-review viewthe PR. If the output includes aPENDING REVIEWSsection, reuse thatPRR_...ID. Otherwise,gh-review startto create one.gh-review commentfor each inline comment, passing the review ID.- Stop. The user submits the review manually via the GitHub UI.
gh-review delete discards a pending review, by its PRR_... ID or by the PR it belongs to.
Replying to Comments
- Reviewing someone else's PR:
gh-review replystages the reply in the same pending review as your inline comments, invisible until the user submits. It finds the pending review itself; pass--review-idonly when more than one exists. With none it errors instead of posting;startone first. - Otherwise, post with
gh-review reply --publish; neverstarta review for these replies:- Bot author (CodeRabbit, Copilot, Qodana, any
[bot]login) on the user's own PR: publish directly. - Every other reply: draft it in chat first. For each thread, quote the comment being answered, then the draft body. Publish only the drafts the user approves, with their edits applied verbatim. Approval covers the shown text only; a revised body needs a new approval.
- Bot author (CodeRabbit, Copilot, Qodana, any
GitHub rejects a published reply while you hold a pending review on that PR. If reply --publish
fails, inspect and preserve that review. Ask the user to submit it or authorize discarding it; a
failed reply is not deletion authorization. Delete only the explicitly authorized review, then
retry.
A reply targets the numeric database ID shown as #ID in view output headers (e.g.
@reviewer (2026-05-14) #98765 PRRC_kwDO...:). Extract the number after #, not the node ID.
Only thread comments carry #ID. Review bodies (tagged [review body, no reply thread]) and
conversation comments have no thread and cannot be replied to, even when a review body lists file
and line findings (e.g. CodeRabbit's collapsed "Other comments").
Editing and Removing Comments
gh-review edit changes a body in place, but any positioning change deletes the comment and
recreates it on the same pending review. Repositioning therefore needs the full target position
restated, not just the part that changed: the comment node does not expose its own line, and omitted
values fall back to defaults rather than the old comment. Published comments and replies support
body edits only.
Line Targeting
GitHub's API only supports line-level comments on lines within diff hunks (changed lines plus surrounding context). Lines in the gap between hunks cannot be targeted as line comments.
When comment targets a non-diff line, it automatically falls back to a file-level comment on the
same file (using subjectType: FILE). The output includes a note: field explaining the fallback.
The comment still lands on the correct file; it just appears at the top of the file's diff rather
than on a specific line.
Omitting --line posts a file-level comment directly, skipping the line attempt.
Suggestion blocks: Suggestions only work on line-level comments. The --start-line to --line
range defines what GitHub replaces when a suggestion is applied. The range MUST exactly match the
lines being replaced. Do NOT include surrounding context lines in the range; they will be deleted.
ID Formats
PRR_...: Review node ID (fromstartorview)PRRT_...: Thread node ID (emitted bycommentandresolve; not surfaced byview)PRRC_...: Comment node ID (fromviewreview-thread headers orcommentoutput'scomment-node-idfield); used byeditandremove#NNN: Numeric database ID (fromviewoutput orcommentoutput'scomment-idfield); used byreply,resolve, and publishededitandremove