Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Review PRs: diffs, inline comments via gh or REST.
.claude/skills/hezaohezao-github-code-review/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-07 | ✗→✓ | ▲ Improved | 189% | 0% |
| case-13 | ✗→✓ | ▲ Improved | 36% | 0% |
| case-15 | ✗→✓ | ▲ Improved | 63% | 0% |
| case-05 | ✓→✗ | ▼ Worse | 35% | 0% |
| case-06 | ✓→✗ | ▼ Worse | 62% | 0% |
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.
GITHUB_TOKEN env var or gh auth login)bashif command -v gh &>/dev/null && gh auth status &>/dev/null; then AUTH="gh" else AUTH="git" fi 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)
This is pure git — works everywhere, no API needed.
bash# Staged changes (what would be committed) git diff --staged # All changes vs main (what a PR would contain) git diff main...HEAD # File names only git diff main...HEAD --name-only # Stat summary (insertions/deletions per file) git diff main...HEAD --stat
bashgit diff main...HEAD --stat git log main..HEAD --oneline
read_file on changed files for full context:bashgit diff main...HEAD -- src/auth/login.py
bash# Debug statements, TODOs, console.logs left behind git diff main...HEAD | grep -n "print(\|console\.log\|TODO\|FIXME\|HACK\|XXX\|debugger" # Large files accidentally staged git diff main...HEAD --stat | sort -t'|' -k2 -rn | head -10 # Secrets or credential patterns git diff main...HEAD | grep -in "password\|secret\|api_key\|token.*=\|private_key" # Merge conflict markers git diff main...HEAD | grep -n "<<<<<<\|>>>>>>\|======="
## 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 pathWith gh:
bashgh pr view 123 gh pr diff 123 gh pr diff 123 --name-only
With git + curl:
bashPR_NUMBER=123 # Get PR details curl -s \ -H "Authorization: token $GITHUB_TOKEN" \ https://api.github.com/repos/$OWNER/$REPO/pulls/$PR_NUMBER \ | python3 -c " import sys, json pr = 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']}\")" # List changed files curl -s \ -H "Authorization: token $GITHUB_TOKEN" \ https://api.github.com/repos/$OWNER/$REPO/pulls/$PR_NUMBER/files \ | python3 -c " import sys, json for f in json.load(sys.stdin): print(f\"{f['status']:10} +{f['additions']:-4} -{f['deletions']:-4} {f['filename']}\")"
This works with plain git — no gh needed:
bash# Fetch the PR branch and check it out git fetch origin pull/123/head:pr-123 git checkout pr-123 # Now you can use read_file, bash grep, run tests, etc. git diff main...pr-123
General PR comment — with gh:
bashgh pr comment 123 --body "Overall looks good, a few suggestions below."
General PR comment — with curl:
bashcurl -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."}'
Single inline comment — with gh (via API):
bashHEAD_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"
With gh:
bashgh 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:
bashHEAD_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\", \"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.\"} ] }"
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".
When performing a code review (local or PR), systematically check:
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 diffread_file if you need more context| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→fail | 4,244 | 7,119 | +68% | 1 | 1 | 0% | 604 | 2,460 | +307% | 0 | 0 | — |
case-02 | fail→fail | 10,789 | 54,819 | +408% | 1 | 1 | 0% | 1,032 | 4,052 | +293% | 0 | 0 | — |
case-03 | fail→fail | 11,253 | 25,279 | +125% | 1 | 1 | 0% | 687 | 2,499 | +264% | 0 | 0 | — |
case-04 | pass→pass | 10,501 | 6,071 | -42% | 1 | 1 | 0% | 1,660 | 2,993 | +80% | 0 | 0 | — |
case-05 | pass→fail | 13,994 | 5,536 | -60% | 1 | 1 | 0% | 1,843 | 2,480 | +35% | 0 | 0 | — |
case-06 | pass→fail | 8,492 | 9,479 | +12% | 1 | 1 | 0% | 1,547 | 2,504 | +62% | 0 | 0 | — |
case-07 | fail→pass | 6,372 | 4,409 | -31% | 1 | 1 | 0% | 1,004 | 2,903 | +189% | 0 | 0 | — |
case-08 | pass→pass | 11,236 | 7,373 | -34% | 1 | 1 | 0% | 1,764 | 3,261 | +85% | 0 | 0 | — |
case-09 | pass→pass | 9,022 | 7,354 | -18% | 1 | 1 | 0% | 1,309 | 3,239 | +147% | 0 | 0 | — |
case-10 | pass→pass | 7,842 | 5,512 | -30% | 1 | 1 | 0% | 1,028 | 3,029 | +195% | 0 | 0 | — |
case-11 | pass→pass | 18,509 | 8,004 | -57% | 1 | 1 | 0% | 2,863 | 3,474 | +21% | 0 | 0 | — |
case-12 | pass→pass | 20,531 | 6,436 | -69% | 1 | 1 | 0% | 3,221 | 3,224 | +0% | 0 | 0 | — |
case-13 | fail→pass | 37,089 | 10,501 | -72% | 1 | 1 | 0% | 2,773 | 3,780 | +36% | 0 | 0 | — |
case-14 | pass→pass | 4,574 | 7,680 | +68% | 1 | 1 | 0% | 809 | 2,935 | +263% | 0 | 0 | — |
case-15 | fail→pass | 12,460 | 9,837 | -21% | 1 | 1 | 0% | 2,345 | 3,812 | +63% | 0 | 0 | — |
case-16 | pass→pass | 13,149 | 4,749 | -64% | 1 | 1 | 0% | 2,209 | 3,165 | +43% | 0 | 0 | — |
case-17 | pass→pass | 20,136 | 3,440 | -83% | 1 | 1 | 0% | 1,433 | 2,651 | +85% | 0 | 0 | — |
case-18 | pass→pass | 8,640 | 6,089 | -30% | 1 | 1 | 0% | 1,620 | 3,314 | +105% | 0 | 0 | — |
case-19 | pass→pass | 11,553 | 5,280 | -54% | 1 | 1 | 0% | 2,013 | 3,177 | +58% | 0 | 0 | — |
case-20 | pass→pass | 5,862 | 3,751 | -36% | 1 | 1 | 0% | 843 | 2,752 | +226% | 0 | 0 | — |
case-21 | pass→pass | 11,298 | 5,942 | -47% | 1 | 1 | 0% | 1,566 | 2,915 | +86% | 0 | 0 | — |
case-22 | pass→pass | 4,484 | 8,888 | +98% | 1 | 1 | 0% | 570 | 2,546 | +347% | 0 | 0 | — |
case-23 | pass→fail | 8,530 | 13,486 | +58% | 1 | 1 | 0% | 1,192 | 2,598 | +118% | 0 | 0 | — |
case-24 | pass→pass | 21,441 | 16,578 | -23% | 1 | 1 | 0% | 3,266 | 4,679 | +43% | 0 | 0 | — |
case-25 | pass→pass | 7,411 | 3,299 | -55% | 1 | 1 | 0% | 1,269 | 2,820 | +122% | 0 | 0 | — |
case-26 | pass→pass | 5,434 | 5,035 | -7% | 1 | 1 | 0% | 620 | 2,858 | +361% | 0 | 0 | — |
case-27 | pass→pass | 5,665 | 5,085 | -10% | 1 | 1 | 0% | 791 | 2,998 | +279% | 0 | 0 | — |
case-28 | pass→pass | 6,543 | 3,287 | -50% | 1 | 1 | 0% | 839 | 2,585 | +208% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 28 cases were attempted, and 24 counted toward the lift figure. The other 4 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of 0 percentage points is the difference between those two pass rates over the 24 comparable cases. 3 cases got worse with the skill loaded, and they are included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.