Create a self-review pending GitHub pull request review with inline comments on specific lines of code.
-
Get PR details and diff
gh pr view <pr-number>
gh pr diff <pr-number>
If you need to inspect a single changed file or a narrower hunk, prefer local git diffing against the PR base/head refs instead of passing extra path args to gh pr diff:
gh pr view <pr-number> --json baseRefName,headRefName
git diff --unified=20 origin/<base-ref>...origin/<head-ref> -- path/to/file.js
-
Analyze the changes - Review the diff for:
- Code correctness and potential bugs
- Style and convention issues (run ESLint if applicable)
- Performance implications
- Security considerations
- Test coverage
-
Identify specific lines to comment on independently - For each issue found before reading any existing current-user pending review, note:
- File path (relative to repo root)
- Line number in the new version of the file
- The issue/suggestion to raise
When a finding is proven with a focused failing test, inline the important
setup and failing assertion in the comment. Prefer a compact snippet the PR
author can copy into the suite over process labels or proof jargon. Keep
only the lines needed to show the scenario and the failing expectation, and
note the received value inline when useful.
-
Reconcile with any existing current-user pending review
GitHub allows only one pending review per user per PR. After independent findings are complete, fetch the current-user pending review, if any, and compare it with the new findings.
ME=$(gh api user --jq .login)
gh api repos/{owner}/{repo}/pulls/<pr-number>/reviews --paginate \
| jq --arg me "$ME" '.[] | select(.state=="PENDING" and .user.login==$me) | {id,node_id,user:.user.login,body,commit_id}'
- Keep or merge existing pending comments only when they are independently confirmed, still relevant, and useful.
- Dismiss existing pending comments that are invalid, stale, duplicate, superseded, or unsupported by the independent review evidence; note the reason in the final summary instead of carrying them forward.
- Rewrite partially right comments so the final draft states only the verified concern and avoids over-claiming.
- Do not submit, delete, or replace the pending review until the complete reconciled comment set is ready.
-
Create or replace the pending review with inline comments using GitHub API:
This is the default action. Unless the user explicitly asks to submit the review, omit event and leave the review pending. If replacing an existing pending review, use the complete reconciled comment set.
For normal pending inline comments, create the pending review with a comments array:
cat <<'EOF' | gh api repos/{owner}/{repo}/pulls/<pr-number>/reviews --method POST --input -
{
"body": "Summary of the review",
"comments": [
{
"path": "path/to/file.js",
"line": 42,
"body": "Comment about line 42"
},
{
"path": "path/to/another/file.js",
"line": 10,
"body": "Comment about line 10"
}
]
}
EOF
If comments contain GitHub ````suggestionblocks and must render as Suggested change widgets, create the pending review shell first, then add line-anchored threads with GraphQLaddPullRequestReviewThreadusing the pending review'snode_id. The REST review commentsarray can store comments as legacyposition` comments, which may not render as applyable suggestions. Do not fall back to the REST pull request comments endpoint; it publishes immediately.
review_json=$(cat <<'EOF' | gh api repos/{owner}/{repo}/pulls/<pr-number>/reviews --method POST --input -
{
"body": "Summary of the pending review"
}
EOF
)
review_node=$(echo "$review_json" | jq -r .node_id)
body=$(cat <<'EOF'
**Functional regression:** concise explanation.
```suggestion
replacement code for the commented line
EOF
)
gh api graphql
-f query='mutation($review: ID!, $path: String!, $line: Int!, $body: String!) { addPullRequestReviewThread(input: { pullRequestReviewId: $review, path: $path, line: $line, side: RIGHT, body: $body }) { thread { comments(first: 1) { nodes { databaseId pullRequestReview { databaseId state } } } } } }'
-f review="$review_node"
-f path="path/to/file.js"
-F line=42
-f body="$body"
-
Manage pending reviews carefully
- If no draft review exists yet, create one by omitting
event.
- If you need to revise the draft before submission, recreate it with the full reconciled comment set.
- Do not assume you can append more inline comments later to the same draft review.
Recommended workflow when reconciliation changes the pending review:
ME=$(gh api user --jq .login)
gh api repos/{owner}/{repo}/pulls/<pr-number>/reviews --paginate \
| jq --arg me "$ME" '.[] | select(.state=="PENDING" and .user.login==$me) | {id,node_id,user:.user.login}'
gh api repos/{owner}/{repo}/pulls/<pr-number>/reviews/<numeric-review-id> --method DELETE
cat <<'EOF' | gh api repos/{owner}/{repo}/pulls/<pr-number>/reviews --method POST --input -
{
"body": "Updated review summary",
"comments": [
{ "path": "path/to/file.js", "line": 42, "body": "First comment" },
{ "path": "path/to/file.js", "line": 57, "body": "Newly added comment" }
]
}
EOF
-
Submit the pending review only on explicit user instruction
Once the inline comments look correct, keep the draft review pending unless the user explicitly tells you to submit it.
When the user does explicitly instruct submission, submit the existing draft review:
cat <<'EOF' | gh api repos/{owner}/{repo}/pulls/<pr-number>/reviews/<review-id>/events --method POST --input -
{
"event": "REQUEST_CHANGES",
"body": "Requesting changes because ..."
}
EOF
Please hydrate the selected view without applying the interactive pagination reset.