Github Code Review — Review PRs: diffs, inline comments via gh or REST
Github Code Review
Section titled “Github Code Review”Review PRs: diffs, inline comments via gh or REST.
Skill metadata
Section titled “Skill metadata”| Source | Bundled (installed by default) |
| Path | skills/github/github-code-review |
| Version | 1.1.0 |
| Author | Hermes Agent |
| License | MIT |
| Tags | GitHub, Code-Review, Pull-Requests, Git, Quality |
| Related skills | github-auth, github-pr-workflow |
Reference: full SKILL.md
Section titled “Reference: full SKILL.md”The following is the complete skill definition that Hermes loads when this skill is triggered. This is what the agent sees as instructions when the skill is active.
GitHub Code Review
Section titled “GitHub Code Review”Perform code reviews on local changes before pushing, or review open PRs on GitHub. Most of this skill uses plain git — the gh/curl split only matters for PR-level interactions.
Prerequisites
Section titled “Prerequisites”- Authenticated with GitHub (see
github-authskill) - Inside a git repository
Setup (for PR interactions)
Section titled “Setup (for PR interactions)”if command -v gh &>/dev/null && gh auth status &>/dev/null; then AUTH="gh"else AUTH="git" if [ -z "$GITHUB_TOKEN" ]; then if [ -f ~/.hermes/.env ] && grep -q "^GITHUB_TOKEN=" ~/.hermes/.env; then GITHUB_TOKEN=$(grep "^GITHUB_TOKEN=" ~/.hermes/.env | head -1 | cut -d= -f2 | tr -d '\n\r') elif grep -q "github.com" ~/.git-credentials 2>/dev/null; then GITHUB_TOKEN=$(grep "github.com" ~/.git-credentials 2>/dev/null | head -1 | sed 's|https://[^:]*:\([^@]*\)@.*|\1|') fi fifi
REMOTE_URL=$(git remote get-url origin)OWNER_REPO=$(echo "$REMOTE_URL" | sed -E 's|.*github\.com[:/]||; s|\.git$||')OWNER=$(echo "$OWNER_REPO" | cut -d/ -f1)REPO=$(echo "$OWNER_REPO" | cut -d/ -f2)1. Reviewing Local Changes (Pre-Push)
Section titled “1. Reviewing Local Changes (Pre-Push)”This is pure git — works everywhere, no API needed.
Get the Diff
Section titled “Get the Diff”# Staged changes (what would be committed)git diff --staged
# All changes vs main (what a PR would contain)git diff main...HEAD
# File names onlygit diff main...HEAD --name-only
# Stat summary (insertions/deletions per file)git diff main...HEAD --statReview Strategy
Section titled “Review Strategy”- Get the big picture first:
git diff main...HEAD --statgit log main..HEAD --oneline- Review file by file — use
read_fileon changed files for full context, and the diff to see what changed:
git diff main...HEAD -- src/auth/login.py- Check for common issues:
# Debug statements, TODOs, console.logs left behindgit diff main...HEAD | grep -n "print(\|console\.log\|TODO\|FIXME\|HACK\|XXX\|debugger"
# Large files accidentally stagedgit diff main...HEAD --stat | sort -t'|' -k2 -rn | head -10
# Secrets or credential patternsgit diff main...HEAD | grep -in "password\|secret\|api_key\|token.*=\|private_key"
# Merge conflict markersgit diff main...HEAD | grep -n "<<<<<<\|>>>>>>\|======="- Present structured feedback to the user.
Review Output Format
Section titled “Review Output Format”When reviewing local changes, present findings in this structure:
## Code Review Summary
### Critical- **src/auth.py:45** — SQL injection: user input passed directly to query. Suggestion: Use parameterized queries.
### Warnings- **src/models/user.py:23** — Password stored in plaintext. Use bcrypt or argon2.- **src/api/routes.py:112** — No rate limiting on login endpoint.
### Suggestions- **src/utils/helpers.py:8** — Duplicates logic in `src/core/utils.py:34`. Consolidate.- **tests/test_auth.py** — Missing edge case: expired token test.
### Looks Good- Clean separation of concerns in the middleware layer- Good test coverage for the happy path2. Reviewing a Pull Request on GitHub
Section titled “2. Reviewing a Pull Request on GitHub”View PR Details
Section titled “View PR Details”With gh:
gh pr view 123gh pr diff 123gh pr diff 123 --name-onlyWith git + curl:
PR_NUMBER=123
# Get PR detailscurl -s \ -H "Authorization: token $GITHUB_TOKEN" \ https://api.github.com/repos/$OWNER/$REPO/pulls/$PR_NUMBER \ | python3 -c "import sys, jsonpr = json.load(sys.stdin)print(f\"Title: {pr['title']}\")print(f\"Author: {pr['user']['login']}\")print(f\"Branch: {pr['head']['ref']} -> {pr['base']['ref']}\")print(f\"State: {pr['state']}\")print(f\"Body:\n{pr['body']}\")"
# List changed filescurl -s \ -H "Authorization: token $GITHUB_TOKEN" \ https://api.github.com/repos/$OWNER/$REPO/pulls/$PR_NUMBER/files \ | python3 -c "import sys, jsonfor f in json.load(sys.stdin): print(f\"{f['status']:10} +{f['additions']:-4} -{f['deletions']:-4} {f['filename']}\")"Check Out PR Locally for Full Review
Section titled “Check Out PR Locally for Full Review”This works with plain git — no gh needed:
# Fetch the PR branch and check it outgit fetch origin pull/123/head:pr-123git checkout pr-123
# Now you can use read_file, search_files, run tests, etc.
# View diff against the base branchgit diff main...pr-123With gh (shortcut):
gh pr checkout 123Leave Comments on a PR
Section titled “Leave Comments on a PR”General PR comment — with gh:
gh pr comment 123 --body "Overall looks good, a few suggestions below."General PR comment — with curl:
curl -s -X POST \ -H "Authorization: token $GITHUB_TOKEN" \ https://api.github.com/repos/$OWNER/$REPO/issues/$PR_NUMBER/comments \ -d '{"body": "Overall looks good, a few suggestions below."}'Leave Inline Review Comments
Section titled “Leave Inline Review Comments”Single inline comment — with gh (via API):
HEAD_SHA=$(gh pr view 123 --json headRefOid --jq '.headRefOid')
gh api repos/$OWNER/$REPO/pulls/123/comments \ --method POST \ -f body="This could be simplified with a list comprehension." \ -f path="src/auth/login.py" \ -f commit_id="$HEAD_SHA" \ -f line=45 \ -f side="RIGHT"Single inline comment — with curl:
# Get the head commit SHAHEAD_SHA=$(curl -s \ -H "Authorization: token $GITHUB_TOKEN" \ https://api.github.com/repos/$OWNER/$REPO/pulls/$PR_NUMBER \ | python3 -c "import sys,json; print(json.load(sys.stdin)['head']['sha'])")
curl -s -X POST \ -H "Authorization: token $GITHUB_TOKEN" \ https://api.github.com/repos/$OWNER/$REPO/pulls/$PR_NUMBER/comments \ -d "{ \"body\": \"This could be simplified with a list comprehension.\", \"path\": \"src/auth/login.py\", \"commit_id\": \"$HEAD_SHA\", \"line\": 45, \"side\": \"RIGHT\" }"Submit a Formal Review (Approve / Request Changes)
Section titled “Submit a Formal Review (Approve / Request Changes)”With gh:
gh pr review 123 --approve --body "LGTM!"gh pr review 123 --request-changes --body "See inline comments."gh pr review 123 --comment --body "Some suggestions, nothing blocking."With curl — multi-comment review submitted atomically:
HEAD_SHA=$(curl -s \ -H "Authorization: token $GITHUB_TOKEN" \ https://api.github.com/repos/$OWNER/$REPO/pulls/$PR_NUMBER \ | python3 -c "import sys,json; print(json.load(sys.stdin)['head']['sha'])")
curl -s -X POST \ -H "Authorization: token $GITHUB_TOKEN" \ https://api.github.com/repos/$OWNER/$REPO/pulls/$PR_NUMBER/reviews \ -d "{ \"commit_id\": \"$HEAD_SHA\", \"event\": \"COMMENT\", \"body\": \"Code review from Hermes Agent\", \"comments\": [ {\"path\": \"src/auth.py\", \"line\": 45, \"body\": \"Use parameterized queries to prevent SQL injection.\"}, {\"path\": \"src/models/user.py\", \"line\": 23, \"body\": \"Hash passwords with bcrypt before storing.\"}, {\"path\": \"tests/test_auth.py\", \"line\": 1, \"body\": \"Add test for expired token edge case.\"} ] }"Event values: "APPROVE", "REQUEST_CHANGES", "COMMENT"
The line field refers to the line number in the new version of the file. For deleted lines, use "side": "LEFT".
3. Review Checklist
Section titled “3. Review Checklist”When performing a code review (local or PR), systematically check:
Correctness
Section titled “Correctness”- Does the code do what it claims?
- Edge cases handled (empty inputs, nulls, large data, concurrent access)?
- Error paths handled gracefully?
Security
Section titled “Security”- No hardcoded secrets, credentials, or API keys
- Input validation on user-facing inputs
- No SQL injection, XSS, or path traversal
- Auth/authz checks where needed
Code Quality
Section titled “Code Quality”- Clear naming (variables, functions, classes)
- No unnecessary complexity or premature abstraction
- DRY — no duplicated logic that should be extracted
- Functions are focused (single responsibility)
Testing
Section titled “Testing”- New code paths tested?
- Happy path and error cases covered?
- Tests readable and maintainable?
Performance
Section titled “Performance”- No N+1 queries or unnecessary loops
- Appropriate caching where beneficial
- No blocking operations in async code paths
Documentation
Section titled “Documentation”- Public APIs documented
- Non-obvious logic has comments explaining “why”
- README updated if behavior changed
4. Pre-Push Review Workflow
Section titled “4. Pre-Push Review Workflow”When the user asks you to “review the code” or “check before pushing”:
git diff main...HEAD --stat— see scope of changesgit diff main...HEAD— read the full diff- For each changed file, use
read_fileif you need more context - Apply the checklist above
- Present findings in the structured format (Critical / Warnings / Suggestions / Looks Good)
- If critical issues found, offer to fix them before the user pushes
5. PR Review Workflow (End-to-End)
Section titled “5. PR Review Workflow (End-to-End)”When the user asks you to “review PR #N”, “look at this PR”, or gives you a PR URL, follow this recipe:
Step 1: Set up environment
Section titled “Step 1: Set up environment”source "${HERMES_HOME:-$HOME/.hermes}/skills/github/github-auth/scripts/gh-env.sh"# Or run the inline setup block from the top of this skillStep 2: Gather PR context
Section titled “Step 2: Gather PR context”Get the PR metadata, description, and list of changed files to understand scope before diving into code.
With gh:
gh pr view 123gh pr diff 123 --name-onlygh pr checks 123With curl:
PR_NUMBER=123
# PR details (title, author, description, branch)curl -s -H "Authorization: token $GITHUB_TOKEN" \ https://api.github.com/repos/$GH_OWNER/$GH_REPO/pulls/$PR_NUMBER
# Changed files with line countscurl -s -H "Authorization: token $GITHUB_TOKEN" \ https://api.github.com/repos/$GH_OWNER/$GH_REPO/pulls/$PR_NUMBER/filesStep 3: Check out the PR locally
Section titled “Step 3: Check out the PR locally”This gives you full access to read_file, search_files, and the ability to run tests.
git fetch origin pull/$PR_NUMBER/head:pr-$PR_NUMBERgit checkout pr-$PR_NUMBERStep 4: Read the diff and understand changes
Section titled “Step 4: Read the diff and understand changes”# Full diff against the base branchgit diff main...HEAD
# Or file-by-file for large PRsgit diff main...HEAD --name-only# Then for each file:git diff main...HEAD -- path/to/file.pyFor each changed file, use read_file to see full context around the changes — diffs alone can miss issues visible only with surrounding code.
Step 5: Run automated checks locally (if applicable)
Section titled “Step 5: Run automated checks locally (if applicable)”# Run tests if there's a test suitepython -m pytest 2>&1 | tail -20# or: npm test, cargo test, go test ./..., etc.
# Run linter if configuredruff check . 2>&1 | head -30# or: eslint, clippy, etc.Step 6: Apply the review checklist (Section 3)
Section titled “Step 6: Apply the review checklist (Section 3)”Go through each category: Correctness, Security, Code Quality, Testing, Performance, Documentation.
Step 7: Post the review to GitHub
Section titled “Step 7: Post the review to GitHub”Collect your findings and submit them as a formal review with inline comments.
With gh:
# If no issues — approvegh pr review $PR_NUMBER --approve --body "Reviewed by Hermes Agent. Code looks clean — good test coverage, no security concerns."
# If issues found — request changes with inline commentsgh pr review $PR_NUMBER --request-changes --body "Found a few issues — see inline comments."With curl — atomic review with multiple inline comments:
HEAD_SHA=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \ https://api.github.com/repos/$GH_OWNER/$GH_REPO/pulls/$PR_NUMBER \ | python3 -c "import sys,json; print(json.load(sys.stdin)['head']['sha'])")
# Build the review JSON — event is APPROVE, REQUEST_CHANGES, or COMMENTcurl -s -X POST \ -H "Authorization: token $GITHUB_TOKEN" \ https://api.github.com/repos/$GH_OWNER/$GH_REPO/pulls/$PR_NUMBER/reviews \ -d "{ \"commit_id\": \"$HEAD_SHA\", \"event\": \"REQUEST_CHANGES\", \"body\": \"## Hermes Agent Review\n\nFound 2 issues, 1 suggestion. See inline comments.\", \"comments\": [ {\"path\": \"src/auth.py\", \"line\": 45, \"body\": \"🔴 **Critical:** User input passed directly to SQL query — use parameterized queries.\"}, {\"path\": \"src/models.py\", \"line\": 23, \"body\": \"⚠️ **Warning:** Password stored without hashing.\"}, {\"path\": \"src/utils.py\", \"line\": 8, \"body\": \"💡 **Suggestion:** This duplicates logic in core/utils.py:34.\"} ] }"Step 8: Also post a summary comment
Section titled “Step 8: Also post a summary comment”In addition to inline comments, leave a top-level summary so the PR author gets the full picture at a glance. Use the review output format from references/review-output-template.md.
With gh:
gh pr comment $PR_NUMBER --body "$(cat <<'EOF'## Code Review Summary
**Verdict: Changes Requested** (2 issues, 1 suggestion)
### 🔴 Critical- **src/auth.py:45** — SQL injection vulnerability
### ⚠️ Warnings- **src/models.py:23** — Plaintext password storage
### 💡 Suggestions- **src/utils.py:8** — Duplicated logic, consider consolidating
### ✅ Looks Good- Clean API design- Good error handling in the middleware layer
---*Reviewed by Hermes Agent*EOF)"Step 9: Clean up
Section titled “Step 9: Clean up”git checkout maingit branch -D pr-$PR_NUMBERDecision: Approve vs Request Changes vs Comment
Section titled “Decision: Approve vs Request Changes vs Comment”- Approve — no critical or warning-level issues, only minor suggestions or all clear
- Request Changes — any critical or warning-level issue that should be fixed before merge
- Comment — observations and suggestions, but nothing blocking (use when you’re unsure or the PR is a draft)