Context-engineering-kit git:attach-review-to-pr
Add line-specific review comments to pull requests using GitHub CLI API
git clone https://github.com/NeoLabHQ/context-engineering-kit
T=$(mktemp -d) && git clone --depth=1 https://github.com/NeoLabHQ/context-engineering-kit "$T" && mkdir -p ~/.claude/skills && cp -r "$T/plugins/git/skills/attach-review-to-pr" ~/.claude/skills/neolabhq-context-engineering-kit-git-attach-review-to-pr && rm -rf "$T"
plugins/git/skills/attach-review-to-pr/SKILL.mdHow to Attach Line-Specific Review Comments to Pull Requests
This guide explains how to add line-specific review comments to pull requests using the GitHub CLI (
gh) API or mcp__github_inline_comment__create_inline_comment if it not available, similar to how the GitHub UI allows commenting on specific lines of code.
Preferred Approach: Using MCP GitHub Tools
If available, use the
mcp__github_inline_comment__create_inline_comment MCP tool for posting line-specific inline comments on pull requests. This approach provides better integration with GitHub's UI and is the recommended method.
Fallback: If the MCP tool is not available, use the GitHub CLI (
gh) API methods described below:
- For single comments: Use the
endpoint (see Adding a Single Line-Specific Comment)/comments - For multiple comments: Use the
endpoint (see Adding Multiple Line-Specific Comments Together)/reviews
Overview
While
gh pr review provides basic review functionality (approve, request changes, general comments), it does not support line-specific comments directly. To add comments on specific lines of code, you must use the lower-level gh api command to call GitHub's REST API directly.
Prerequisites
-
GitHub CLI installed and authenticated:
gh auth status -
Access to the repository and pull request you want to review
Understanding GitHub's Review Comment System
GitHub has two types of PR comments:
- Issue Comments - General comments on the PR conversation
- Review Comments - Line-specific comments on code changes
Review comments can be added in two ways:
- Single comment - Using the
endpoint/pulls/{pr}/comments - Review with multiple comments - Using the
endpoint/pulls/{pr}/reviews
Adding a Single Line-Specific Comment
Basic Syntax
gh api repos/{owner}/{repo}/pulls/{pr_number}/comments \ -f body='Your comment text here' \ -f commit_id='<commit-sha>' \ -f path='path/to/file.js' \ -F line=42 \ -f side='RIGHT'
Parameters Explained
| Parameter | Type | Required | Description |
|---|---|---|---|
| string | Yes | The text of the review comment (supports Markdown) |
| string | Yes | The SHA of the commit to comment on |
| string | Yes | Relative path to the file being commented on |
| integer | Yes | The line number in the diff (use for integers) |
| string | Yes | for new/modified lines, for deleted lines |
| integer | No | For multi-line comments, the starting line |
| string | No | For multi-line comments, the starting side |
Parameter Flags
(--field) - For string values-f
(--field) - For integer values (note the capital F)-F
Complete Example
# First, get the latest commit SHA for the PR gh api repos/NeoLabHQ/learning-platform-app/pulls/4 --jq '.head.sha' # Then add your comment gh api repos/NeoLabHQ/learning-platform-app/pulls/4/comments \ -f body='Consider adding error handling here. Should we confirm the lesson was successfully marked as completed before navigating away?' \ -f commit_id='e152d0dd6cf498467eadbeb638bf05abe11c64d4' \ -f path='src/components/LessonNavigationButtons.tsx' \ -F line=26 \ -f side='RIGHT'
Understanding Line Numbers
The
line parameter refers to the position in the diff, not the absolute line number in the file:
- For new files: Line numbers match the file's line numbers
- For modified files: Use the line number as it appears in the "Files changed" tab
- For multi-line comments: Use
andstart_line
to specify the rangeline
Response
On success, returns a JSON object with comment details:
{ "id": 2532291222, "pull_request_review_id": 3470545909, "path": "src/components/LessonNavigationButtons.tsx", "line": 26, "body": "Consider adding error handling here...", "html_url": "https://github.com/NeoLabHQ/learning-platform-app/pull/4#discussion_r2532291222", "created_at": "2025-11-16T22:40:46Z" }
Adding Multiple Line-Specific Comments Together
To add multiple comments across different files in a single review, use the
/reviews endpoint with JSON input.
Why Use Reviews for Multiple Comments?
- Atomic operation - All comments are added together
- Single notification - Doesn't spam with multiple notifications
- Better UX - Appears as one cohesive review
- Same mechanism as GitHub UI - "Start a review" → "Finish review"
Basic Syntax
cat <<'EOF' | gh api repos/{owner}/{repo}/pulls/{pr_number}/reviews --input - { "event": "COMMENT", "body": "Overall review summary (optional)", "comments": [ { "path": "file1.tsx", "body": "Comment on file 1", "side": "RIGHT", "line": 15 }, { "path": "file2.tsx", "body": "Comment on file 2", "side": "RIGHT", "line": 30 } ] } EOF
Review Event Types
| Event | Description | When to Use |
|---|---|---|
| General review comment | Just leaving feedback without approval |
| Approve the PR | Changes look good, ready to merge |
| Request changes | Issues that must be fixed before merge |
Complete Example
cat <<'EOF' | gh api repos/NeoLabHQ/learning-platform-app/pulls/4/reviews --input - { "event": "COMMENT", "body": "Testing multiple line-specific comments via gh api", "comments": [ { "path": "src/components/CourseCard.tsx", "body": "Test comment generated by Claude", "side": "RIGHT", "line": 15 }, { "path": "src/components/CourseProgressWidget.tsx", "body": "Test comment generated by Claude", "side": "RIGHT", "line": 30 }, { "path": "src/components/LessonProgressTracker.tsx", "body": "Test comment generated by Claude", "side": "RIGHT", "line": 20 } ] } EOF
Response
{ "id": 3470546747, "state": "COMMENTED", "html_url": "https://github.com/NeoLabHQ/learning-platform-app/pull/4#pullrequestreview-3470546747", "submitted_at": "2025-11-16T22:42:43Z", "commit_id": "e152d0dd6cf498467eadbeb638bf05abe11c64d4" }
Common Issues and Solutions
Issue 1: "user_id can only have one pending review per pull request"
Error Message:
gh: Validation Failed (HTTP 422) {"message":"Validation Failed","errors":[{"resource":"PullRequestReview","code":"custom","field":"user_id","message":"user_id can only have one pending review per pull request"}]}
Cause: GitHub only allows one pending (unsubmitted) review per user per PR. If you previously started a review through the UI or API and didn't submit it, it blocks new review creation.
Solution 1: Submit the pending review
# Check for pending reviews gh api repos/{owner}/{repo}/pulls/{pr_number}/reviews | jq '.[] | select(.state=="PENDING")' # Submit it through the UI or ask the user to submit it
Solution 2: Use the single comment endpoint instead
# Add individual comments without creating a review gh api repos/{owner}/{repo}/pulls/{pr_number}/comments \ -f body='Comment text' \ -f commit_id='<sha>' \ -f path='file.tsx' \ -F line=26 \ -f side='RIGHT'
Issue 2: Array syntax not working with --raw-field
Failed Attempt:
# This does NOT work - GitHub API receives an object, not an array gh api repos/{owner}/{repo}/pulls/{pr}/reviews \ --raw-field 'comments[0][path]=file1.tsx' \ --raw-field 'comments[0][line]=15' \ --raw-field 'comments[1][path]=file2.tsx' \ --raw-field 'comments[1][line]=30'
Error:
Invalid request. For 'properties/comments', {"0" => {...}, "1" => {...}} is not an array.
Solution: Use JSON input via heredoc:
cat <<'EOF' | gh api repos/{owner}/{repo}/pulls/{pr}/reviews --input - { "comments": [...] } EOF
Issue 3: Invalid line number
Error Message:
Pull request review thread line must be part of the diff
Cause: The line number doesn't exist in the diff for this file.
Solutions:
- Verify the file was actually changed in this PR
- Check the "Files changed" tab to see actual line numbers in the diff
- Ensure you're using the correct
(the latest commit in the PR)commit_id
Issue 4: Wrong commit_id
Error Message:
commit_sha is not part of the pull request
Solution: Get the latest commit SHA:
gh api repos/{owner}/{repo}/pulls/{pr_number} --jq '.head.sha'
Best Practices
1. Get PR Information First
Before adding comments, gather necessary information:
# Get PR details gh pr view {pr_number} --json headRefOid,files # Or use the API gh api repos/{owner}/{repo}/pulls/{pr_number} --jq '{commit: .head.sha, files: [.changed_files]}' # List files changed gh api repos/{owner}/{repo}/pulls/{pr_number}/files --jq '.[] | {filename: .filename, additions: .additions, deletions: .deletions}'
2. Check for Pending Reviews
# Check if you have a pending review gh api repos/{owner}/{repo}/pulls/{pr_number}/reviews \ --jq '.[] | select(.state=="PENDING" and .user.login=="YOUR_USERNAME")'
3. Use Meaningful Comment Text
- Be specific and constructive
- Reference documentation or best practices
- Suggest alternatives when requesting changes
- Use code blocks for code suggestions:
Consider using async/await: \`\`\`typescript async function getData() { const result = await fetch(url); return result.json(); } \`\`\`
4. Batch Related Comments
Use the review endpoint to group related comments:
- All comments for a single file/area
- All comments for a specific concern (security, performance, etc.)
- Complete review session
5. Choose the Right Event Type
# For feedback during development "event": "COMMENT" # When approving "event": "APPROVE" # When blocking merge "event": "REQUEST_CHANGES"
Workflow Examples
Example 1: Quick Single Comment
#!/bin/bash OWNER="NeoLabHQ" REPO="learning-platform-app" PR=4 # Get latest commit COMMIT=$(gh api repos/$OWNER/$REPO/pulls/$PR --jq '.head.sha') # Add comment gh api repos/$OWNER/$REPO/pulls/$PR/comments \ -f body='Consider extracting this into a separate function for better testability' \ -f commit_id="$COMMIT" \ -f path='src/utils/validation.ts' \ -F line=45 \ -f side='RIGHT'
Example 2: Comprehensive Review
#!/bin/bash OWNER="NeoLabHQ" REPO="learning-platform-app" PR=4 # Create review with multiple comments cat <<EOF | gh api repos/$OWNER/$REPO/pulls/$PR/reviews --input - { "event": "COMMENT", "body": "Thanks for the PR! I've reviewed the changes and have a few suggestions.", "comments": [ { "path": "src/components/CourseCard.tsx", "body": "Consider memoizing this component to prevent unnecessary re-renders", "side": "RIGHT", "line": 25 }, { "path": "src/utils/courseProgress.ts", "body": "This function could benefit from error handling for invalid course IDs", "side": "RIGHT", "line": 12 }, { "path": "src/state/CourseProgressState.ts", "body": "Consider adding JSDoc comments to document the expected behavior", "side": "RIGHT", "line": 8 } ] } EOF
Example 3: Multi-line Comment
# Comment on a range of lines (e.g., lines 10-15) gh api repos/$OWNER/$REPO/pulls/$PR/comments \ -f body='This entire block could be simplified using array destructuring' \ -f commit_id="$COMMIT" \ -f path='src/utils/parser.ts' \ -F start_line=10 \ -f start_side='RIGHT' \ -F line=15 \ -f side='RIGHT'
Helpful Helper Scripts
Get PR Files and Lines
#!/bin/bash # pr-files.sh - List all files changed in a PR with line counts OWNER="$1" REPO="$2" PR="$3" gh api repos/$OWNER/$REPO/pulls/$PR/files --jq '.[] | "\(.filename): +\(.additions)/-\(.deletions)"'
Check Review Status
#!/bin/bash # check-reviews.sh - Check review status for a PR OWNER="$1" REPO="$2" PR="$3" echo "=== Reviews ===" gh api repos/$OWNER/$REPO/pulls/$PR/reviews --jq '.[] | "\(.user.login): \(.state) at \(.submitted_at)"' echo -e "\n=== Pending Reviews ===" gh api repos/$OWNER/$REPO/pulls/$PR/reviews --jq '.[] | select(.state=="PENDING") | "\(.user.login): \(.state)"'
Related Documentation
- GitHub API: Pull Request Review Comments
- GitHub API: Pull Request Reviews
- GitHub CLI Manual
- Create PR Command
- Commit Command
API Reference
POST /repos/{owner}/{repo}/pulls/{pull_number}/comments
Creates a review comment on a specific line.
Endpoint:
https://api.github.com/repos/{owner}/{repo}/pulls/{pull_number}/comments
Parameters:
(string, required): Comment textbody
(string, required): SHA of commitcommit_id
(string, required): Relative file pathpath
(integer, required): Line number in diffline
(string, required): "LEFT" or "RIGHT"side
(integer, optional): Start line for multi-linestart_line
(string, optional): Start side for multi-linestart_side
POST /repos/{owner}/{repo}/pulls/{pull_number}/reviews
Creates a review with optional line-specific comments.
Endpoint:
https://api.github.com/repos/{owner}/{repo}/pulls/{pull_number}/reviews
Parameters:
(string, required): "APPROVE", "REQUEST_CHANGES", or "COMMENT"event
(string, optional): Overall review commentbody
(array, optional): Array of comment objectscomments
(string, optional): SHA of commit to reviewcommit_id
Comment Object:
(string, required): Relative file pathpath
(string, required): Comment textbody
(integer, required): Line number in diffline
(string, required): "LEFT" or "RIGHT"side
(integer, optional): Start line for multi-linestart_line
(string, optional): Start side for multi-linestart_side