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. gh-review --help prints every command with its
full signature in one pass; use gh-review <command> --help only for option semantics. This skill
covers workflow and semantics only.
The repository is a positional owner/repo argument, NOT a --repo flag, and it is inferred from
the current directory when omitted. Pass it only when working outside the checkout.
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 the same rule except for the bot-reply case below.
- 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.
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
gh-review reply adds a threaded reply to an existing review thread as part of a pending review, so
it stays invisible until the user submits. It finds the pending review itself; pass --review-id
only when more than one exists. With no pending review it errors instead of posting: start one
first, and treat replies as part of the same review pass as your inline comments.
--publish skips the pending review and posts the reply immediately. Use it in exactly one case:
the PR is the user's own and the comment you are answering came from a bot (CodeRabbit, Copilot,
Qodana, any [bot] author). Batching those into a review the user then has to submit on their own
PR buys nothing, so do NOT start a review for bot replies. Every other reply, on someone else's
PR or to a human on the user's, MUST go through the pending review.
GitHub rejects a published reply while you hold a pending review on that PR. If reply --publish
fails, inspect and preserve that review. Ask before discarding it; a failed reply is not deletion
authorization. Delete only the explicitly authorized review, then retry.
The COMMENT_ID argument is 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.
Conversation comments (the PR's main timeline) have no thread and cannot be replied to this way.
Editing and Removing Comments
gh-review edit modifies an existing review comment. Two paths depending on what changed:
- Body only (no positioning args): patches the comment in place. One API call.
- Repositioning (any of
--path,--line,--start-line,--side,--start-side): deletes the old comment and creates a new one on the same pending review. Requires both--review-idand--line, even when only--pathchanges (the underlying comment node does not expose its line, so it cannot be inferred).--pathand--bodyare merged from the current comment when omitted;--sidedefaults toRIGHTrather than being read from the existing comment.
edit and remove both take the PRRC_... node ID for pending comments. For published comments
and replies, pass OWNER/REPO followed by the numeric comment ID; those 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, publishededitandremove, andresolve