[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M71H2WR4HDPABDCRSQBC43CS":3,"skill-same:01M71H2WR4HDPABDCRSQBC43CS":96},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":30,"publishedAt":51,"linkOnly":52,"markdownContent":53,"markdownBody":54,"frontMatter":55,"refName":69,"commitSha":70,"skillDirectory":71,"forksCount":72,"repositoryHtmlUrl":73,"repositoryHomepageUrl":6,"ownerHtmlUrl":74,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":75,"install":76,"resources":89},"01M71H2WR4HDPABDCRSQBC43CS","github-code-review",null,"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.","0xzgbot\u002Fforge-nps-v01","0xzgbot","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F271900281?v=4","01M71GXWAFRXXJSJE3HBCVDKZY","01M71GXWBFQYRJK7M8RM6BDP0X",6,"MIT","https:\u002F\u002Fgithub.com\u002F0xzgbot\u002Fforge-nps-v01\u002Fblob\u002Fmaster\u002Fhermes_home\u002Fprofiles\u002Fcinesmith\u002Fskills\u002Fgithub\u002Fgithub-code-review\u002FSKILL.md",[17,22,25],{"categoryNo":18,"categoryName":19,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000007","代码审查","SCENARIO","使用场景",{"categoryNo":23,"categoryName":24,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000023","Skill与智能体开发",{"categoryNo":26,"categoryName":27,"taxonomyType":28,"taxonomyTypeDesc":29},"01JBSEEDCAT000000000000030","开发工程师","PROFESSION","适用职业",[31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50],"github code","github code review","code","review","github","code review","push","pull","gh cli","git","analyzing","cli","inline","api","code-review","pull-requests","workflow","diffs","auth","back","2026-11-10 10:12:30",false,"---\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`\u002F`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\n```bash\nif command -v gh &>\u002Fdev\u002Fnull && gh auth status &>\u002Fdev\u002Fnull; then\n  AUTH=\"gh\"\nelse\n  AUTH=\"git\"\n  if [ -z \"$GITHUB_TOKEN\" ]; then\n    if [ -f ~\u002F.hermes\u002F.env ] && grep -q \"^GITHUB_TOKEN=\" ~\u002F.hermes\u002F.env; then\n      GITHUB_TOKEN=$(grep \"^GITHUB_TOKEN=\" ~\u002F.hermes\u002F.env | head -1 | cut -d= -f2 | tr -d '\\n\\r')\n    elif grep -q \"github.com\" ~\u002F.git-credentials 2>\u002Fdev\u002Fnull; then\n      GITHUB_TOKEN=$(grep \"github.com\" ~\u002F.git-credentials 2>\u002Fdev\u002Fnull | head -1 | sed 's|https:\u002F\u002F[^:]*:\\([^@]*\\)@.*|\\1|')\n    fi\n  fi\nfi\n\nREMOTE_URL=$(git remote get-url origin)\nOWNER_REPO=$(echo \"$REMOTE_URL\" | sed -E 's|.*github\\.com[:\u002F]||; s|\\.git$||')\nOWNER=$(echo \"$OWNER_REPO\" | cut -d\u002F -f1)\nREPO=$(echo \"$OWNER_REPO\" | cut -d\u002F -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\n```bash\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\u002Fdeletions per file)\ngit diff main...HEAD --stat\n```\n\n### Review Strategy\n\n1. **Get the big picture first:**\n\n```bash\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\n```bash\ngit diff main...HEAD -- src\u002Fauth\u002Flogin.py\n```\n\n3. **Check for common issues:**\n\n```bash\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 \"\u003C\u003C\u003C\u003C\u003C\u003C\\|>>>>>>\\|=======\"\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\u002Fauth.py:45** — SQL injection: user input passed directly to query.\n  Suggestion: Use parameterized queries.\n\n### Warnings\n- **src\u002Fmodels\u002Fuser.py:23** — Password stored in plaintext. Use bcrypt or argon2.\n- **src\u002Fapi\u002Froutes.py:112** — No rate limiting on login endpoint.\n\n### Suggestions\n- **src\u002Futils\u002Fhelpers.py:8** — Duplicates logic in `src\u002Fcore\u002Futils.py:34`. Consolidate.\n- **tests\u002Ftest_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\n**With gh:**\n\n```bash\ngh pr view 123\ngh pr diff 123\ngh pr diff 123 --name-only\n```\n\n**With git + curl:**\n\n```bash\nPR_NUMBER=123\n\n# Get PR details\ncurl -s \\\n  -H \"Authorization: token $GITHUB_TOKEN\" \\\n  https:\u002F\u002Fapi.github.com\u002Frepos\u002F$OWNER\u002F$REPO\u002Fpulls\u002F$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:\u002F\u002Fapi.github.com\u002Frepos\u002F$OWNER\u002F$REPO\u002Fpulls\u002F$PR_NUMBER\u002Ffiles \\\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\n```bash\n# Fetch the PR branch and check it out\ngit fetch origin pull\u002F123\u002Fhead: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\n**With gh (shortcut):**\n\n```bash\ngh pr checkout 123\n```\n\n### Leave Comments on a PR\n\n**General PR comment — with gh:**\n\n```bash\ngh pr comment 123 --body \"Overall looks good, a few suggestions below.\"\n```\n\n**General PR comment — with curl:**\n\n```bash\ncurl -s -X POST \\\n  -H \"Authorization: token $GITHUB_TOKEN\" \\\n  https:\u002F\u002Fapi.github.com\u002Frepos\u002F$OWNER\u002F$REPO\u002Fissues\u002F$PR_NUMBER\u002Fcomments \\\n  -d '{\"body\": \"Overall looks good, a few suggestions below.\"}'\n```\n\n### Leave Inline Review Comments\n\n**Single inline comment — with gh (via API):**\n\n```bash\nHEAD_SHA=$(gh pr view 123 --json headRefOid --jq '.headRefOid')\n\ngh api repos\u002F$OWNER\u002F$REPO\u002Fpulls\u002F123\u002Fcomments \\\n  --method POST \\\n  -f body=\"This could be simplified with a list comprehension.\" \\\n  -f path=\"src\u002Fauth\u002Flogin.py\" \\\n  -f commit_id=\"$HEAD_SHA\" \\\n  -f line=45 \\\n  -f side=\"RIGHT\"\n```\n\n**Single inline comment — with curl:**\n\n```bash\n# Get the head commit SHA\nHEAD_SHA=$(curl -s \\\n  -H \"Authorization: token $GITHUB_TOKEN\" \\\n  https:\u002F\u002Fapi.github.com\u002Frepos\u002F$OWNER\u002F$REPO\u002Fpulls\u002F$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:\u002F\u002Fapi.github.com\u002Frepos\u002F$OWNER\u002F$REPO\u002Fpulls\u002F$PR_NUMBER\u002Fcomments \\\n  -d \"{\n    \\\"body\\\": \\\"This could be simplified with a list comprehension.\\\",\n    \\\"path\\\": \\\"src\u002Fauth\u002Flogin.py\\\",\n    \\\"commit_id\\\": \\\"$HEAD_SHA\\\",\n    \\\"line\\\": 45,\n    \\\"side\\\": \\\"RIGHT\\\"\n  }\"\n```\n\n### Submit a Formal Review (Approve \u002F Request Changes)\n\n**With gh:**\n\n```bash\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\n**With curl — multi-comment review submitted atomically:**\n\n```bash\nHEAD_SHA=$(curl -s \\\n  -H \"Authorization: token $GITHUB_TOKEN\" \\\n  https:\u002F\u002Fapi.github.com\u002Frepos\u002F$OWNER\u002F$REPO\u002Fpulls\u002F$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:\u002F\u002Fapi.github.com\u002Frepos\u002F$OWNER\u002F$REPO\u002Fpulls\u002F$PR_NUMBER\u002Freviews \\\n  -d \"{\n    \\\"commit_id\\\": \\\"$HEAD_SHA\\\",\n    \\\"event\\\": \\\"COMMENT\\\",\n    \\\"body\\\": \\\"Code review from Hermes Agent\\\",\n    \\\"comments\\\": [\n      {\\\"path\\\": \\\"src\u002Fauth.py\\\", \\\"line\\\": 45, \\\"body\\\": \\\"Use parameterized queries to prevent SQL injection.\\\"},\n      {\\\"path\\\": \\\"src\u002Fmodels\u002Fuser.py\\\", \\\"line\\\": 23, \\\"body\\\": \\\"Hash passwords with bcrypt before storing.\\\"},\n      {\\\"path\\\": \\\"tests\u002Ftest_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\u002Fauthz 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 \u002F Warnings \u002F Suggestions \u002F 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\n```bash\nsource \"${HERMES_HOME:-$HOME\u002F.hermes}\u002Fskills\u002Fgithub\u002Fgithub-auth\u002Fscripts\u002Fgh-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\n**With gh:**\n```bash\ngh pr view 123\ngh pr diff 123 --name-only\ngh pr checks 123\n```\n\n**With curl:**\n```bash\nPR_NUMBER=123\n\n# PR details (title, author, description, branch)\ncurl -s -H \"Authorization: token $GITHUB_TOKEN\" \\\n  https:\u002F\u002Fapi.github.com\u002Frepos\u002F$GH_OWNER\u002F$GH_REPO\u002Fpulls\u002F$PR_NUMBER\n\n# Changed files with line counts\ncurl -s -H \"Authorization: token $GITHUB_TOKEN\" \\\n  https:\u002F\u002Fapi.github.com\u002Frepos\u002F$GH_OWNER\u002F$GH_REPO\u002Fpulls\u002F$PR_NUMBER\u002Ffiles\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\n```bash\ngit fetch origin pull\u002F$PR_NUMBER\u002Fhead:pr-$PR_NUMBER\ngit checkout pr-$PR_NUMBER\n```\n\n### Step 4: Read the diff and understand changes\n\n```bash\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\u002Fto\u002Ffile.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\n```bash\n# Run tests if there's a test suite\npython -m pytest 2>&1 | tail -20\n# or: npm test, cargo test, go test .\u002F..., 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\n**With gh:**\n```bash\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\n**With curl — atomic review with multiple inline comments:**\n```bash\nHEAD_SHA=$(curl -s -H \"Authorization: token $GITHUB_TOKEN\" \\\n  https:\u002F\u002Fapi.github.com\u002Frepos\u002F$GH_OWNER\u002F$GH_REPO\u002Fpulls\u002F$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:\u002F\u002Fapi.github.com\u002Frepos\u002F$GH_OWNER\u002F$GH_REPO\u002Fpulls\u002F$PR_NUMBER\u002Freviews \\\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\u002Fauth.py\\\", \\\"line\\\": 45, \\\"body\\\": \\\"🔴 **Critical:** User input passed directly to SQL query — use parameterized queries.\\\"},\n      {\\\"path\\\": \\\"src\u002Fmodels.py\\\", \\\"line\\\": 23, \\\"body\\\": \\\"⚠️ **Warning:** Password stored without hashing.\\\"},\n      {\\\"path\\\": \\\"src\u002Futils.py\\\", \\\"line\\\": 8, \\\"body\\\": \\\"💡 **Suggestion:** This duplicates logic in core\u002Futils.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\u002Freview-output-template.md`.\n\n**With gh:**\n```bash\ngh pr comment $PR_NUMBER --body \"$(cat \u003C\u003C'EOF'\n## Code Review Summary\n\n**Verdict: Changes Requested** (2 issues, 1 suggestion)\n\n### 🔴 Critical\n- **src\u002Fauth.py:45** — SQL injection vulnerability\n\n### ⚠️ Warnings\n- **src\u002Fmodels.py:23** — Plaintext password storage\n\n### 💡 Suggestions\n- **src\u002Futils.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\n```bash\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","# 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`\u002F`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\n```bash\nif command -v gh &>\u002Fdev\u002Fnull && gh auth status &>\u002Fdev\u002Fnull; then\n  AUTH=\"gh\"\nelse\n  AUTH=\"git\"\n  if [ -z \"$GITHUB_TOKEN\" ]; then\n    if [ -f ~\u002F.hermes\u002F.env ] && grep -q \"^GITHUB_TOKEN=\" ~\u002F.hermes\u002F.env; then\n      GITHUB_TOKEN=$(grep \"^GITHUB_TOKEN=\" ~\u002F.hermes\u002F.env | head -1 | cut -d= -f2 | tr -d '\\n\\r')\n    elif grep -q \"github.com\" ~\u002F.git-credentials 2>\u002Fdev\u002Fnull; then\n      GITHUB_TOKEN=$(grep \"github.com\" ~\u002F.git-credentials 2>\u002Fdev\u002Fnull | head -1 | sed 's|https:\u002F\u002F[^:]*:\\([^@]*\\)@.*|\\1|')\n    fi\n  fi\nfi\n\nREMOTE_URL=$(git remote get-url origin)\nOWNER_REPO=$(echo \"$REMOTE_URL\" | sed -E 's|.*github\\.com[:\u002F]||; s|\\.git$||')\nOWNER=$(echo \"$OWNER_REPO\" | cut -d\u002F -f1)\nREPO=$(echo \"$OWNER_REPO\" | cut -d\u002F -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\n```bash\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\u002Fdeletions per file)\ngit diff main...HEAD --stat\n```\n\n### Review Strategy\n\n1. **Get the big picture first:**\n\n```bash\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\n```bash\ngit diff main...HEAD -- src\u002Fauth\u002Flogin.py\n```\n\n3. **Check for common issues:**\n\n```bash\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 \"\u003C\u003C\u003C\u003C\u003C\u003C\\|>>>>>>\\|=======\"\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\u002Fauth.py:45** — SQL injection: user input passed directly to query.\n  Suggestion: Use parameterized queries.\n\n### Warnings\n- **src\u002Fmodels\u002Fuser.py:23** — Password stored in plaintext. Use bcrypt or argon2.\n- **src\u002Fapi\u002Froutes.py:112** — No rate limiting on login endpoint.\n\n### Suggestions\n- **src\u002Futils\u002Fhelpers.py:8** — Duplicates logic in `src\u002Fcore\u002Futils.py:34`. Consolidate.\n- **tests\u002Ftest_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\n**With gh:**\n\n```bash\ngh pr view 123\ngh pr diff 123\ngh pr diff 123 --name-only\n```\n\n**With git + curl:**\n\n```bash\nPR_NUMBER=123\n\n# Get PR details\ncurl -s \\\n  -H \"Authorization: token $GITHUB_TOKEN\" \\\n  https:\u002F\u002Fapi.github.com\u002Frepos\u002F$OWNER\u002F$REPO\u002Fpulls\u002F$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:\u002F\u002Fapi.github.com\u002Frepos\u002F$OWNER\u002F$REPO\u002Fpulls\u002F$PR_NUMBER\u002Ffiles \\\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\n```bash\n# Fetch the PR branch and check it out\ngit fetch origin pull\u002F123\u002Fhead: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\n**With gh (shortcut):**\n\n```bash\ngh pr checkout 123\n```\n\n### Leave Comments on a PR\n\n**General PR comment — with gh:**\n\n```bash\ngh pr comment 123 --body \"Overall looks good, a few suggestions below.\"\n```\n\n**General PR comment — with curl:**\n\n```bash\ncurl -s -X POST \\\n  -H \"Authorization: token $GITHUB_TOKEN\" \\\n  https:\u002F\u002Fapi.github.com\u002Frepos\u002F$OWNER\u002F$REPO\u002Fissues\u002F$PR_NUMBER\u002Fcomments \\\n  -d '{\"body\": \"Overall looks good, a few suggestions below.\"}'\n```\n\n### Leave Inline Review Comments\n\n**Single inline comment — with gh (via API):**\n\n```bash\nHEAD_SHA=$(gh pr view 123 --json headRefOid --jq '.headRefOid')\n\ngh api repos\u002F$OWNER\u002F$REPO\u002Fpulls\u002F123\u002Fcomments \\\n  --method POST \\\n  -f body=\"This could be simplified with a list comprehension.\" \\\n  -f path=\"src\u002Fauth\u002Flogin.py\" \\\n  -f commit_id=\"$HEAD_SHA\" \\\n  -f line=45 \\\n  -f side=\"RIGHT\"\n```\n\n**Single inline comment — with curl:**\n\n```bash\n# Get the head commit SHA\nHEAD_SHA=$(curl -s \\\n  -H \"Authorization: token $GITHUB_TOKEN\" \\\n  https:\u002F\u002Fapi.github.com\u002Frepos\u002F$OWNER\u002F$REPO\u002Fpulls\u002F$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:\u002F\u002Fapi.github.com\u002Frepos\u002F$OWNER\u002F$REPO\u002Fpulls\u002F$PR_NUMBER\u002Fcomments \\\n  -d \"{\n    \\\"body\\\": \\\"This could be simplified with a list comprehension.\\\",\n    \\\"path\\\": \\\"src\u002Fauth\u002Flogin.py\\\",\n    \\\"commit_id\\\": \\\"$HEAD_SHA\\\",\n    \\\"line\\\": 45,\n    \\\"side\\\": \\\"RIGHT\\\"\n  }\"\n```\n\n### Submit a Formal Review (Approve \u002F Request Changes)\n\n**With gh:**\n\n```bash\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\n**With curl — multi-comment review submitted atomically:**\n\n```bash\nHEAD_SHA=$(curl -s \\\n  -H \"Authorization: token $GITHUB_TOKEN\" \\\n  https:\u002F\u002Fapi.github.com\u002Frepos\u002F$OWNER\u002F$REPO\u002Fpulls\u002F$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:\u002F\u002Fapi.github.com\u002Frepos\u002F$OWNER\u002F$REPO\u002Fpulls\u002F$PR_NUMBER\u002Freviews \\\n  -d \"{\n    \\\"commit_id\\\": \\\"$HEAD_SHA\\\",\n    \\\"event\\\": \\\"COMMENT\\\",\n    \\\"body\\\": \\\"Code review from Hermes Agent\\\",\n    \\\"comments\\\": [\n      {\\\"path\\\": \\\"src\u002Fauth.py\\\", \\\"line\\\": 45, \\\"body\\\": \\\"Use parameterized queries to prevent SQL injection.\\\"},\n      {\\\"path\\\": \\\"src\u002Fmodels\u002Fuser.py\\\", \\\"line\\\": 23, \\\"body\\\": \\\"Hash passwords with bcrypt before storing.\\\"},\n      {\\\"path\\\": \\\"tests\u002Ftest_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\u002Fauthz 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 \u002F Warnings \u002F Suggestions \u002F 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\n```bash\nsource \"${HERMES_HOME:-$HOME\u002F.hermes}\u002Fskills\u002Fgithub\u002Fgithub-auth\u002Fscripts\u002Fgh-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\n**With gh:**\n```bash\ngh pr view 123\ngh pr diff 123 --name-only\ngh pr checks 123\n```\n\n**With curl:**\n```bash\nPR_NUMBER=123\n\n# PR details (title, author, description, branch)\ncurl -s -H \"Authorization: token $GITHUB_TOKEN\" \\\n  https:\u002F\u002Fapi.github.com\u002Frepos\u002F$GH_OWNER\u002F$GH_REPO\u002Fpulls\u002F$PR_NUMBER\n\n# Changed files with line counts\ncurl -s -H \"Authorization: token $GITHUB_TOKEN\" \\\n  https:\u002F\u002Fapi.github.com\u002Frepos\u002F$GH_OWNER\u002F$GH_REPO\u002Fpulls\u002F$PR_NUMBER\u002Ffiles\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\n```bash\ngit fetch origin pull\u002F$PR_NUMBER\u002Fhead:pr-$PR_NUMBER\ngit checkout pr-$PR_NUMBER\n```\n\n### Step 4: Read the diff and understand changes\n\n```bash\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\u002Fto\u002Ffile.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\n```bash\n# Run tests if there's a test suite\npython -m pytest 2>&1 | tail -20\n# or: npm test, cargo test, go test .\u002F..., 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\n**With gh:**\n```bash\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\n**With curl — atomic review with multiple inline comments:**\n```bash\nHEAD_SHA=$(curl -s -H \"Authorization: token $GITHUB_TOKEN\" \\\n  https:\u002F\u002Fapi.github.com\u002Frepos\u002F$GH_OWNER\u002F$GH_REPO\u002Fpulls\u002F$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:\u002F\u002Fapi.github.com\u002Frepos\u002F$GH_OWNER\u002F$GH_REPO\u002Fpulls\u002F$PR_NUMBER\u002Freviews \\\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\u002Fauth.py\\\", \\\"line\\\": 45, \\\"body\\\": \\\"🔴 **Critical:** User input passed directly to SQL query — use parameterized queries.\\\"},\n      {\\\"path\\\": \\\"src\u002Fmodels.py\\\", \\\"line\\\": 23, \\\"body\\\": \\\"⚠️ **Warning:** Password stored without hashing.\\\"},\n      {\\\"path\\\": \\\"src\u002Futils.py\\\", \\\"line\\\": 8, \\\"body\\\": \\\"💡 **Suggestion:** This duplicates logic in core\u002Futils.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\u002Freview-output-template.md`.\n\n**With gh:**\n```bash\ngh pr comment $PR_NUMBER --body \"$(cat \u003C\u003C'EOF'\n## Code Review Summary\n\n**Verdict: Changes Requested** (2 issues, 1 suggestion)\n\n### 🔴 Critical\n- **src\u002Fauth.py:45** — SQL injection vulnerability\n\n### ⚠️ Warnings\n- **src\u002Fmodels.py:23** — Plaintext password storage\n\n### 💡 Suggestions\n- **src\u002Futils.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\n```bash\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",{"name":5,"author":56,"license":14,"version":57,"metadata":58,"description":7},"Hermes Agent","1.1.0",{"hermes":59},{"tags":60,"related_skills":66},[61,62,63,64,65],"GitHub","Code-Review","Pull-Requests","Git","Quality",[67,68],"github-auth","github-pr-workflow","master","a76a61826887171cb38ce217ae85643d5d7685d1","hermes_home\u002Fprofiles\u002Fcinesmith\u002Fskills\u002Fgithub\u002Fgithub-code-review",2,"https:\u002F\u002Fgithub.com\u002F0xzgbot\u002Fforge-nps-v01","https:\u002F\u002Fgithub.com\u002F0xzgbot","2026-08-31 09:13:28",{"source":8,"skillName":5,"commands":77,"prompt":87,"zipAvailable":88},[78,81,84],{"tool":79,"command":80},"npx","npx skills add 0xzgbot\u002Fforge-nps-v01 --skill github-code-review",{"tool":82,"command":83},"bunx","bunx skills add 0xzgbot\u002Fforge-nps-v01 --skill github-code-review",{"tool":85,"command":86},"pnpm","pnpm dlx skills add 0xzgbot\u002Fforge-nps-v01 --skill github-code-review","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002F0xzgbot\u002Fforge-nps-v01\u002Fblob\u002Fmaster\u002Fhermes_home\u002Fprofiles\u002Fcinesmith\u002Fskills\u002Fgithub\u002Fgithub-code-review\u002FSKILL.md",true,[90],{"path":91,"resourceType":92,"resourceTypeDesc":93,"sizeBytes":94,"sourceHtmlUrl":95},"references\u002Freview-output-template.md","REFERENCE","参考文档",2465,"https:\u002F\u002Fgithub.com\u002F0xzgbot\u002Fforge-nps-v01\u002Fblob\u002Fmaster\u002Fhermes_home\u002Fprofiles\u002Fcinesmith\u002Fskills\u002Fgithub\u002Fgithub-code-review\u002Freferences\u002Freview-output-template.md",[97,110,127,141,152,164],{"skillNo":98,"name":99,"nameZh":6,"description":100,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":101,"categories":102,"keywords":103,"publishedAt":51},"01M71J5TFCV7K97773JYZE7ET8","yuanbao","Yuanbao (元宝) groups: @mention users, query info\u002Fmembers.","https:\u002F\u002Fgithub.com\u002F0xzgbot\u002Fforge-nps-v01\u002Fblob\u002Fmaster\u002Fhermes_home\u002Fskills\u002Fyuanbao\u002FSKILL.md",[],[99,104,105,106,107,108,109],"groups","at","info","users","query","group",{"skillNo":111,"name":112,"nameZh":6,"description":113,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":114,"categories":115,"keywords":120,"publishedAt":51},"01M71J5QR69MCT5J8P3B4Y9ZHA","workflow-ltx-i2v","Use when the task involves workflow ltx i2v. DESCRIPTION.","https:\u002F\u002Fgithub.com\u002F0xzgbot\u002Fforge-nps-v01\u002Fblob\u002Fmaster\u002Fhermes_home\u002Fskills\u002Fworkflow_ltx_i2v\u002FSKILL.md",[116,119],{"categoryNo":117,"categoryName":118,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000016","图像与多媒体",{"categoryNo":23,"categoryName":24,"taxonomyType":20,"taxonomyTypeDesc":21},[121,122,47,123,124,125,126],"ltx","workflow ltx i2v","Production","task","when","use",{"skillNo":128,"name":129,"nameZh":6,"description":130,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":131,"categories":132,"keywords":135,"publishedAt":51},"01M71J5NYW853AAPB17VR0F7ZX","workflow-flux2-text-to-image","Flux2 Text-to-Image Workflow Reference.","https:\u002F\u002Fgithub.com\u002F0xzgbot\u002Fforge-nps-v01\u002Fblob\u002Fmaster\u002Fhermes_home\u002Fskills\u002Fworkflow_flux2_text_to_image\u002FSKILL.md",[133,134],{"categoryNo":117,"categoryName":118,"taxonomyType":20,"taxonomyTypeDesc":21},{"categoryNo":23,"categoryName":24,"taxonomyType":20,"taxonomyTypeDesc":21},[136,137,47,138,139,123,140],"workflow flux2 text to image","image","text","reference","Text-to-Image",{"skillNo":142,"name":143,"nameZh":6,"description":144,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":145,"categories":146,"keywords":148,"publishedAt":51},"01M71J5KWY96MD6B6YC2XP6NXB","wide-angle-environmental","Use when the task involves wide angle environmental. DESCRIPTION.","https:\u002F\u002Fgithub.com\u002F0xzgbot\u002Fforge-nps-v01\u002Fblob\u002Fmaster\u002Fhermes_home\u002Fskills\u002Fwide_angle_environmental\u002FSKILL.md",[147],{"categoryNo":23,"categoryName":24,"taxonomyType":20,"taxonomyTypeDesc":21},[149,150,151,123,124,125,126],"environmental","wide","wide angle environmental",{"skillNo":153,"name":154,"nameZh":6,"description":155,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":156,"categories":157,"keywords":159,"publishedAt":51},"01M71J5DXHECTDVDF8HRP81YFY","wes-anderson-specialist","Use when the task involves wes anderson specialist. 1. EXECUTIVE SUMMARY.","https:\u002F\u002Fgithub.com\u002F0xzgbot\u002Fforge-nps-v01\u002Fblob\u002Fmaster\u002Fhermes_home\u002Fskills\u002Fwes_anderson_specialist\u002FSKILL.md",[158],{"categoryNo":23,"categoryName":24,"taxonomyType":20,"taxonomyTypeDesc":21},[160,161,162,163,125,126,124,123],"specialist","wes anderson specialist","summary","executive summary",{"skillNo":165,"name":166,"nameZh":6,"description":167,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":168,"categories":169,"keywords":171,"publishedAt":51},"01M71J5BRHX2N4BRG2VQMWJK3E","volumetric-god-rays-lighting","Use when the task involves volumetric god rays lighting. DESCRIPTION.","https:\u002F\u002Fgithub.com\u002F0xzgbot\u002Fforge-nps-v01\u002Fblob\u002Fmaster\u002Fhermes_home\u002Fskills\u002Fvolumetric_god_rays_lighting\u002FSKILL.md",[170],{"categoryNo":23,"categoryName":24,"taxonomyType":20,"taxonomyTypeDesc":21},[172,173,126,125,124,123],"volumetric god rays lighting","lighting"]