github-pr-review-comments
npx skills add https://github.com/straub/agent-skills --skill github-pr-review-comments
Agent 安装分布
Skill 文档
GitHub PR Review Comments
This skill provides a comprehensive workflow for managing PR review comments using the gh CLI and GitHub’s GraphQL API.
When to Use This Skill
Use this skill when:
- Asked to address PR review comments
- Finding unreplied or unresolved review threads
- Replying to review comments
- Resolving or unresolving review threads
- Working with review threads programmatically (coding agents, automation)
Finding All Review Comments (Reliable Method)
CRITICAL: PR review comments are paginated and span multiple review rounds. Simple queries will miss comments. Use this comparison approach:
Step 1: Get ALL Original Comment IDs
gh api repos/{owner}/{repo}/pulls/{pr}/comments --paginate \
--jq '[.[] | select(.in_reply_to_id == null)] | .[].id' \
| sort -n > /tmp/all_original_comments.txt
This finds all “top-level” review comments (not replies).
Step 2: Check Your Username
gh api user -q .login
Step 3: Get ALL Comment IDs That Have Your Replies
gh api repos/{owner}/{repo}/pulls/{pr}/comments --paginate \
--jq '[.[] | select(.user.login == "{your_username}" and .in_reply_to_id != null)] | .[].in_reply_to_id' \
| sort -n > /tmp/replied_comments.txt
Step 4: Find Unreplied Comments (Set Difference)
comm -23 /tmp/all_original_comments.txt /tmp/replied_comments.txt
This shows comment IDs that don’t have your reply yet.
Why Simple Approaches Fail
- Time-based filtering misses comments from earlier review rounds added to the same PR
- Non-paginated queries miss comments beyond the first page (typically 30-100 per page)
- Counting reviews vs comments is misleading – a single review can have many comments
- The PR “comments” field only shows issue-style comments, not review comments
Getting Comment Details
Once you have unreplied comment IDs, get full details:
gh api repos/{owner}/{repo}/pulls/{pr}/comments --paginate \
--jq '[.[] | select(.id == {id1} or .id == {id2})] | .[] | {id, path, line, body}'
Replace {id1}, {id2} with actual comment IDs.
Replying to Review Comments
Basic Reply to a Comment
gh api repos/{owner}/{repo}/pulls/{pr}/comments/{comment_id}/replies \
-X POST -f body='Your response here'
Response Format Best Practices
- Start with status emoji:
- â for addressed/fixed
- ð for acknowledged/will fix
- ð for discussion/clarification needed
- Reference specific commits when fixes are made:
**FIXED** in commit abc1234 - Be concise but clear about what action was taken
- Group related fixes into single commits with descriptive messages
Example Responses
# Fixed issue
gh api repos/owner/repo/pulls/123/comments/456/replies \
-X POST -f body='â
**FIXED** in commit abc1234 - Refactored to use async/await pattern'
# Acknowledged
gh api repos/owner/repo/pulls/123/comments/789/replies \
-X POST -f body='ð Good catch! Will fix in next commit'
Working with Review Threads (GraphQL API)
The GitHub GraphQL API provides powerful capabilities for managing review threads.
Fetch Unresolved Review Threads
gh api graphql -f query='
{
repository(owner: "OWNER", name: "REPO") {
pullRequest(number: PR_NUMBER) {
reviewThreads(first: 100) {
nodes {
id
isResolved
comments(first: 100) {
nodes {
id
body
author { login }
path
line
}
}
}
}
}
}
}'
Reply to a Review Thread
Use the thread ID from reviewThreads.nodes[].id (format: PRRT_kwDO...), NOT the comment ID:
gh api graphql -f query='
mutation {
addPullRequestReviewThreadReply(input: {
pullRequestReviewThreadId: "PRRT_kwDO..."
body: "Your reply here"
}) {
comment { id }
}
}'
Resolve a Review Thread
gh api graphql -f query='
mutation {
resolveReviewThread(input: {threadId: "PRRT_kwDO..."}) {
thread { id isResolved }
}
}'
Thread IDs are in the id field of each thread node (format: PRRT_kwDO...).
Unresolve a Review Thread
gh api graphql -f query='
mutation {
unresolveReviewThread(input: {threadId: "PRRT_kwDO..."}) {
thread { id isResolved }
}
}'
Workflow: Addressing All Review Comments
- Find unreplied comments using the comparison method above
- Get comment details for each unreplied comment
- Make necessary code changes to address the feedback
- Commit changes with descriptive messages
- Reply to each comment with status and commit reference
- Resolve threads when appropriate (only after fix is confirmed and pushed)
Examples
Example 1: Find and List All Unreplied Comments for PR #42
# Set variables
OWNER="myorg"
REPO="myrepo"
PR="42"
# Step 1: Get all original comment IDs
gh api repos/$OWNER/$REPO/pulls/$PR/comments --paginate \
--jq '[.[] | select(.in_reply_to_id == null)] | .[].id' \
| sort -n > /tmp/all_original_comments.txt
# Step 2: Get your username
USERNAME=$(gh api user -q .login)
# Step 3: Get comment IDs you've replied to
gh api repos/$OWNER/$REPO/pulls/$PR/comments --paginate \
--jq "[.[] | select(.user.login == \"$USERNAME\" and .in_reply_to_id != null)] | .[].in_reply_to_id" \
| sort -n > /tmp/replied_comments.txt
# Step 4: Find unreplied comment IDs
UNREPLIED=$(comm -23 /tmp/all_original_comments.txt /tmp/replied_comments.txt)
# Step 5: Get details for unreplied comments
for id in $UNREPLIED; do
gh api repos/$OWNER/$REPO/pulls/$PR/comments --paginate \
--jq "[.[] | select(.id == $id)] | .[] | {id, path, line, body, author: .user.login}"
done
Example 2: Reply to Multiple Comments After Fix
OWNER="myorg"
REPO="myrepo"
PR="42"
COMMIT="abc1234"
# Reply to comment about async refactoring
gh api repos/$OWNER/$REPO/pulls/$PR/comments/111/replies \
-X POST -f body="â
**FIXED** in commit $COMMIT - Refactored to use async/await"
# Reply to comment about error handling
gh api repos/$OWNER/$REPO/pulls/$PR/comments/222/replies \
-X POST -f body="â
**FIXED** in commit $COMMIT - Added try/catch with proper error logging"
Example 3: Get All Unresolved Threads and Reply
OWNER="myorg"
REPO="myrepo"
PR="42"
# Fetch unresolved threads
THREADS=$(gh api graphql -f query="
{
repository(owner: \"$OWNER\", name: \"$REPO\") {
pullRequest(number: $PR) {
reviewThreads(first: 100) {
nodes {
id
isResolved
comments(first: 1) {
nodes { body path }
}
}
}
}
}
}")
echo "$THREADS" | jq '.data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved == false)'
# Reply to a specific thread and resolve it
THREAD_ID="PRRT_kwDOAbc123"
gh api graphql -f query="
mutation {
addPullRequestReviewThreadReply(input: {
pullRequestReviewThreadId: \"$THREAD_ID\"
body: \"â
Fixed in latest commit\"
}) {
comment { id }
}
}"
gh api graphql -f query="
mutation {
resolveReviewThread(input: {threadId: \"$THREAD_ID\"}) {
thread { id isResolved }
}
}"
Guidelines
- Always paginate when fetching PR comments – use
--paginateflag - Use set comparison (comm command) to reliably find unreplied comments
- Reply before resolving – add a comment explaining the fix before marking as resolved
- Reference commits in replies so reviewers can verify the fix
- Group related changes into single commits with clear messages
- Test your fixes before replying to ensure the issue is actually addressed
- Be specific in replies about what changed and why
- Keep replies concise but informative
- Use emojis consistently for status (â fixed, ð in progress, ð discussion)
Notes
REST API vs GraphQL API
-
REST API (
gh api repos/.../pulls/.../comments):- Better for listing and filtering comments
- Simpler for replies
- Requires pagination for complete results
-
GraphQL API (
gh api graphql):- Better for fetching threads with nested structure
- Required for resolving/unresolving threads
- More efficient for complex queries (fewer API calls)
- Thread IDs have format
PRRT_kwDO...
Comment ID vs Thread ID
- Comment IDs are numeric (e.g.,
123456789) - Thread IDs are GraphQL node IDs (e.g.,
PRRT_kwDOAbc123...) - Use comment IDs for REST API replies
- Use thread IDs for GraphQL thread operations
Automation Considerations
For coding agents and automation:
- Store comment IDs and thread IDs for tracking
- Batch operations where possible to reduce API calls
- Add delays between API calls to respect rate limits
- Log all API responses for debugging
- Handle errors gracefully (comment might be deleted, PR might be closed)
Future Enhancement
When gh pr review-thread command becomes available (gh cli #12419), it will provide:
gh pr review-thread resolve <thread-id>gh pr review-thread unresolve <thread-id>gh pr review-thread list --unresolved
Until then, use the GraphQL mutations shown above.