{“content”:”---\nname: github-code-review\ndescription: Review code changes by analyzing git diffs, leaving inline comments on PRs, and performing thorough pre-push review. Works with gh CLI or falls back to git + GitHub REST API via curl.\nversion: 1.1.0\nauthor: Hermes Agent\nlicense: MIT\nmetadata:\n hermes:\n tags: [GitHub, Code-Review, Pull-Requests, Git, Quality]\n related_skills: [github-auth, github-pr-workflow]\n---\n\n# GitHub Code Review\n\nPerform 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.\n\n## Prerequisites\n\n- Authenticated with GitHub (see github-auth skill)\n- Inside a git repository\n\n### Setup (for PR interactions)\n\nbash\nif command -v gh &>/dev/null && gh auth status &>/dev/null; then\n AUTH=\"gh\"\nelse\n AUTH=\"git\"\n if [ -z \"$GITHUB_TOKEN\" ]; then\n if [ -f ~/.hermes/.env ] && grep -q \"^GITHUB_TOKEN=\" ~/.hermes/.env; then\n GITHUB_TOKEN=$(grep \"^GITHUB_TOKEN=\" ~/.hermes/.env | head -1 | cut -d= -f2 | tr -d '\\n\\r')\n elif grep -q \"github.com\" ~/.git-credentials 2>/dev/null; then\n GITHUB_TOKEN=$(grep \"github.com\" ~/.git-credentials 2>/dev/null | head -1 | sed 's|https://[^:]*:\\([^@]*\\)@.*|\\1|')\n fi\n fi\nfi\n\nREMOTE_URL=$(git remote get-url origin)\nOWNER_REPO=$(echo \"$REMOTE_URL\" | sed -E 's|.*github\\.com[:/]||; s|\\.git$||')\nOWNER=$(echo \"$OWNER_REPO\" | cut -d/ -f1)\nREPO=$(echo \"$OWNER_REPO\" | cut -d/ -f2)\n\n\n---\n\n## 1. Reviewing Local Changes (Pre-Push)\n\nThis is pure git — works everywhere, no API needed.\n\n### Get the Diff\n\nbash\n# Staged changes (what would be committed)\ngit diff --staged\n\n# All changes vs main (what a PR would contain)\ngit diff main...HEAD\n\n# File names only\ngit diff main...HEAD --name-only\n\n# Stat summary (insertions/deletions per file)\ngit diff main...HEAD --stat\n\n\n### Review Strategy\n\n1. Get the big picture first:\n\nbash\ngit diff main...HEAD --stat\ngit log main..HEAD --oneline\n\n\n2. Review file by file — use read_file on changed files for full context, and the diff to see what changed:\n\nbash\ngit diff main...HEAD -- src/auth/login.py\n\n\n3. Check for common issues:\n\nbash\n# Debug statements, TODOs, console.logs left behind\ngit diff main...HEAD | grep -n \"print(\\|console\\.log\\|TODO\\|FIXME\\|HACK\\|XXX\\|debugger\"\n\n# Large files accidentally staged\ngit diff main...HEAD --stat | sort -t'|' -k2 -rn | head -10\n\n# Secrets or credential patterns\ngit diff main...HEAD | grep -in \"password\\|secret\\|api_key\\|token.*=\\|private_key\"\n\n# Merge conflict markers\ngit diff main...HEAD | grep -n \"<<<<<<\\|>>>>>>\\|=======\"\n\n\n4. Present structured feedback to the user.\n\n### Review Output Format\n\nWhen reviewing local changes, present findings in this structure:\n\n\n## Code Review Summary\n\n### Critical\n- **src/auth.py:45** — SQL injection: user input passed directly to query.\n Suggestion: Use parameterized queries.\n\n### Warnings\n- **src/models/user.py:23** — Password stored in plaintext. Use bcrypt or argon2.\n- **src/api/routes.py:112** — No rate limiting on login endpoint.\n\n### Suggestions\n- **src/utils/helpers.py:8** — Duplicates logic in `src/core/utils.py:34`. Consolidate.\n- **tests/test_auth.py** — Missing edge case: expired token test.\n\n### Looks Good\n- Clean separation of concerns in the middleware layer\n- Good test coverage for the happy path\n\n\n---\n\n## 2. Reviewing a Pull Request on GitHub\n\n### View PR Details\n\nWith gh:\n\nbash\ngh pr view 123\ngh pr diff 123\ngh pr diff 123 --name-only\n\n\nWith git + curl:\n\nbash\nPR_NUMBER=123\n\n# Get PR details\ncurl -s \\\n -H \"Authorization: token $GITHUB_TOKEN\" \\\n https://api.github.com/repos/$OWNER/$REPO/pulls/$PR_NUMBER \\\n | python3 -c \"\nimport sys, json\npr = json.load(sys.stdin)\nprint(f\\\"Title: {pr['title']}\\\")\nprint(f\\\"Author: {pr['user']['login']}\\\")\nprint(f\\\"Branch: {pr['head']['ref']} -> {pr['base']['ref']}\\\")\nprint(f\\\"State: {pr['state']}\\\")\nprint(f\\\"Body:\\n{pr['body']}\\\")\"\n\n# List changed files\ncurl -s \\\n -H \"Authorization: token $GITHUB_TOKEN\" \\\n https://api.github.com/repos/$OWNER/$REPO/pulls/$PR_NUMBER/files \\\n | python3 -c \"\nimport sys, json\nfor f in json.load(sys.stdin):\n print(f\\\"{f['status']:10} +{f['additions']:-4} -{f['deletions']:-4} {f['filename']}\\\")\"\n\n\n### Check Out PR Locally for Full Review\n\nThis works with plain git — no gh needed:\n\nbash\n# Fetch the PR branch and check it out\ngit fetch origin pull/123/head:pr-123\ngit checkout pr-123\n\n# Now you can use read_file, search_files, run tests, etc.\n\n# View diff against the base branch\ngit diff main...pr-123\n\n\nWith gh (shortcut):\n\nbash\ngh pr checkout 123\n\n\n### Leave Comments on a PR\n\nGeneral PR comment — with gh:\n\nbash\ngh pr comment 123 --body \"Overall looks good, a few suggestions below.\"\n\n\nGeneral PR comment — with curl:\n\nbash\ncurl -s -X POST \\\n -H \"Authorization: token $GITHUB_TOKEN\" \\\n https://api.github.com/repos/$OWNER/$REPO/issues/$PR_NUMBER/comments \\\n -d '{\"body\": \"Overall looks good, a few suggestions below.\"}'\n\n\n### Leave Inline Review Comments\n\nSingle inline comment — with gh (via API):\n\nbash\nHEAD_SHA=$(gh pr view 123 --json headRefOid --jq '.headRefOid')\n\ngh api repos/$OWNER/$REPO/pulls/123/comments \\\n --method POST \\\n -f body=\"This could be simplified with a list comprehension.\" \\\n -f path=\"src/auth/login.py\" \\\n -f commit_id=\"$HEAD_SHA\" \\\n -f line=45 \\\n -f side=\"RIGHT\"\n\n\nSingle inline comment — with curl:\n\nbash\n# Get the head commit SHA\nHEAD_SHA=$(curl -s \\\n -H \"Authorization: token $GITHUB_TOKEN\" \\\n https://api.github.com/repos/$OWNER/$REPO/pulls/$PR_NUMBER \\\n | python3 -c \"import sys,json; print(json.load(sys.stdin)['head']['sha'])\")\n\ncurl -s -X POST \\\n -H \"Authorization: token $GITHUB_TOKEN\" \\\n https://api.github.com/repos/$OWNER/$REPO/pulls/$PR_NUMBER/comments \\\n -d \"{\n \\\"body\\\": \\\"This could be simplified with a list comprehension.\\\",\n \\\"path\\\": \\\"src/auth/login.py\\\",\n \\\"commit_id\\\": \\\"$HEAD_SHA\\\",\n \\\"line\\\": 45,\n \\\"side\\\": \\\"RIGHT\\\"\n }\"\n\n\n### Submit a Formal Review (Approve / Request Changes)\n\nWith gh:\n\nbash\ngh pr review 123 --approve --body \"LGTM!\"\ngh pr review 123 --request-changes --body \"See inline comments.\"\ngh pr review 123 --comment --body \"Some suggestions, nothing blocking.\"\n\n\nWith curl — multi-comment review submitted atomically:\n\nbash\nHEAD_SHA=$(curl -s \\\n -H \"Authorization: token $GITHUB_TOKEN\" \\\n https://api.github.com/repos/$OWNER/$REPO/pulls/$PR_NUMBER \\\n | python3 -c \"import sys,json; print(json.load(sys.stdin)['head']['sha'])\")\n\ncurl -s -X POST \\\n -H \"Authorization: token $GITHUB_TOKEN\" \\\n https://api.github.com/repos/$OWNER/$REPO/pulls/$PR_NUMBER/reviews \\\n -d \"{\n \\\"commit_id\\\": \\\"$HEAD_SHA\\\",\n \\\"event\\\": \\\"COMMENT\\\",\n \\\"body\\\": \\\"Code review from Hermes Agent\\\",\n \\\"comments\\\": [\n {\\\"path\\\": \\\"src/auth.py\\\", \\\"line\\\": 45, \\\"body\\\": \\\"Use parameterized queries to prevent SQL injection.\\\"},\n {\\\"path\\\": \\\"src/models/user.py\\\", \\\"line\\\": 23, \\\"body\\\": \\\"Hash passwords with bcrypt before storing.\\\"},\n {\\\"path\\\": \\\"tests/test_auth.py\\\", \\\"line\\\": 1, \\\"body\\\": \\\"Add test for expired token edge case.\\\"}\n ]\n }\"\n\n\nEvent values: \"APPROVE\", \"REQUEST_CHANGES\", \"COMMENT\"\n\nThe line field refers to the line number in the new version of the file. For deleted lines, use \"side\": \"LEFT\".\n\n---\n\n## 3. Review Checklist\n\nWhen performing a code review (local or PR), systematically check:\n\n### Correctness\n- Does the code do what it claims?\n- Edge cases handled (empty inputs, nulls, large data, concurrent access)?\n- Error paths handled gracefully?\n\n### Security\n- No hardcoded secrets, credentials, or API keys\n- Input validation on user-facing inputs\n- No SQL injection, XSS, or path traversal\n- Auth/authz checks where needed\n\n### Code Quality\n- Clear naming (variables, functions, classes)\n- No unnecessary complexity or premature abstraction\n- DRY — no duplicated logic that should be extracted\n- Functions are focused (single responsibility)\n\n### Testing\n- New code paths tested?\n- Happy path and error cases covered?\n- Tests readable and maintainable?\n\n### Performance\n- No N+1 queries or unnecessary loops\n- Appropriate caching where beneficial\n- No blocking operations in async code paths\n\n### Documentation\n- Public APIs documented\n- Non-obvious logic has comments explaining “why”\n- README updated if behavior changed\n\n---\n\n## 4. Pre-Push Review Workflow\n\nWhen the user asks you to “review the code” or “check before pushing”:\n\n1. git diff main...HEAD --stat — see scope of changes\n2. git diff main...HEAD — read the full diff\n3. For each changed file, use read_file if you need more context\n4. Apply the checklist above\n5. Present findings in the structured format (Critical / Warnings / Suggestions / Looks Good)\n6. If critical issues found, offer to fix them before the user pushes\n\n---\n\n## 5. PR Review Workflow (End-to-End)\n\nWhen the user asks you to “review PR N”, “look at this PR”, or gives you a PR URL, follow this recipe:\n\n### Step 1: Set up environment\n\nbash\nsource \"${HERMES_HOME:-$HOME/.hermes}/skills/github/github-auth/scripts/gh-env.sh\"\n# Or run the inline setup block from the top of this skill\n\n\n### Step 2: Gather PR context\n\nGet the PR metadata, description, and list of changed files to understand scope before diving into code.\n\nWith gh:\nbash\ngh pr view 123\ngh pr diff 123 --name-only\ngh pr checks 123\n\n\nWith curl:\nbash\nPR_NUMBER=123\n\n# PR details (title, author, description, branch)\ncurl -s -H \"Authorization: token $GITHUB_TOKEN\" \\\n https://api.github.com/repos/$GH_OWNER/$GH_REPO/pulls/$PR_NUMBER\n\n# Changed files with line counts\ncurl -s -H \"Authorization: token $GITHUB_TOKEN\" \\\n https://api.github.com/repos/$GH_OWNER/$GH_REPO/pulls/$PR_NUMBER/files\n\n\n### Step 3: Check out the PR locally\n\nThis gives you full access to read_file, search_files, and the ability to run tests.\n\nbash\ngit fetch origin pull/$PR_NUMBER/head:pr-$PR_NUMBER\ngit checkout pr-$PR_NUMBER\n\n\n### Step 4: Read the diff and understand changes\n\nbash\n# Full diff against the base branch\ngit diff main...HEAD\n\n# Or file-by-file for large PRs\ngit diff main...HEAD --name-only\n# Then for each file:\ngit diff main...HEAD -- path/to/file.py\n\n\nFor each changed file, use read_file to see full context around the changes — diffs alone can miss issues visible only with surrounding code.\n\n### Step 5: Run automated checks locally (if applicable)\n\nbash\n# Run tests if there's a test suite\npython -m pytest 2>&1 | tail -20\n# or: npm test, cargo test, go test ./..., etc.\n\n# Run linter if configured\nruff check . 2>&1 | head -30\n# or: eslint, clippy, etc.\n\n\n### Step 6: Apply the review checklist (Section 3)\n\nGo through each category: Correctness, Security, Code Quality, Testing, Performance, Documentation.\n\n### Step 7: Post the review to GitHub\n\nCollect your findings and submit them as a formal review with inline comments.\n\nWith gh:\nbash\n# If no issues — approve\ngh pr review $PR_NUMBER --approve --body \"Reviewed by Hermes Agent. Code looks clean — good test coverage, no security concerns.\"\n\n# If issues found — request changes with inline comments\ngh pr review $PR_NUMBER --request-changes --body \"Found a few issues — see inline comments.\"\n\n\nWith curl — atomic review with multiple inline comments:\nbash\nHEAD_SHA=$(curl -s -H \"Authorization: token $GITHUB_TOKEN\" \\\n https://api.github.com/repos/$GH_OWNER/$GH_REPO/pulls/$PR_NUMBER \\\n | python3 -c \"import sys,json; print(json.load(sys.stdin)['head']['sha'])\")\n\n# Build the review JSON — event is APPROVE, REQUEST_CHANGES, or COMMENT\ncurl -s -X POST \\\n -H \"Authorization: token $GITHUB_TOKEN\" \\\n https://api.github.com/repos/$GH_OWNER/$GH_REPO/pulls/$PR_NUMBER/reviews \\\n -d \"{\n \\\"commit_id\\\": \\\"$HEAD_SHA\\\",\n \\\"event\\\": \\\"REQUEST_CHANGES\\\",\n \\\"body\\\": \\\"## Hermes Agent Review\\n\\nFound 2 issues, 1 suggestion. See inline comments.\\\",\n \\\"comments\\\": [\n {\\\"path\\\": \\\"src/auth.py\\\", \\\"line\\\": 45, \\\"body\\\": \\\"🔴 **Critical:** User input passed directly to SQL query — use parameterized queries.\\\"},\n {\\\"path\\\": \\\"src/models.py\\\", \\\"line\\\": 23, \\\"body\\\": \\\"⚠️ **Warning:** Password stored without hashing.\\\"},\n {\\\"path\\\": \\\"src/utils.py\\\", \\\"line\\\": 8, \\\"body\\\": \\\"💡 **Suggestion:** This duplicates logic in core/utils.py:34.\\\"}\n ]\n }\"\n\n\n### Step 8: Also post a summary comment\n\nIn 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.\n\nWith gh:\nbash\ngh pr comment $PR_NUMBER --body \"$(cat <<'EOF'\n## Code Review Summary\n\n**Verdict: Changes Requested** (2 issues, 1 suggestion)\n\n### 🔴 Critical\n- **src/auth.py:45** — SQL injection vulnerability\n\n### ⚠️ Warnings\n- **src/models.py:23** — Plaintext password storage\n\n### 💡 Suggestions\n- **src/utils.py:8** — Duplicated logic, consider consolidating\n\n### ✅ Looks Good\n- Clean API design\n- Good error handling in the middleware layer\n\n---\n*Reviewed by Hermes Agent*\nEOF\n)\"\n\n\n### Step 9: Clean up\n\nbash\ngit checkout main\ngit branch -D pr-$PR_NUMBER\n\n\n### Decision: Approve vs Request Changes vs Comment\n\n- Approve — no critical or warning-level issues, only minor suggestions or all clear\n- Request Changes — any critical or warning-level issue that should be fixed before merge\n- Comment — observations and suggestions, but nothing blocking (use when you’re unsure or the PR is a draft)\n”}