How to Automate PR Code Reviews with Claude Code CLI + GitHub Actions
If you want Claude Code to automatically review every pull request before a human sees it — catching bugs, security issues, and performance problems — this tutorial gives you a complete CI pipeline in 35 minutes: prompt template, GitHub Actions workflow, and a Python script that posts line-level comments back to your PR.
进阶 · 35 分钟 · 2026年6月18日
TL;DR
If you're searching for "how to automate code reviews with Claude Code," this tutorial walks you through setting up an AI-powered PR review pipeline that catches bugs, enforces style guides, and writes review comments — all triggered automatically by GitHub Actions. In 35 minutes, you'll have a working CI pipeline that reviews every pull request before a human even looks at it.
What You'll Learn
- Set up Claude Code CLI in a CI environment (GitHub Actions)
- Write a review prompt template that catches real bugs, not just style nits
- Configure GitHub Actions workflow to trigger on PR events
- Post review comments back to the PR via GitHub API
- Handle common failures: token limits, large diffs, and irrelevant feedback
Prerequisites
- A GitHub repository you can push to (public or private)
- Claude Code CLI installed locally (for testing — we'll install it in CI too)
- An Anthropic API key with credits (free tier works for testing, ~$5/mo for production use with ~50 PRs)
- Basic familiarity with GitHub Actions YAML syntax (but we'll explain every line)
Step 1: Install Claude Code CLI and Test Locally
Before we automate, let's make sure Claude Code works on your machine. We'll test it on a real codebase so you know what to expect.
# Install Claude Code via npm (Node.js 18+ required)
npm install -g @anthropic-ai/claude-code
# Verify installation
claude --version
# Expected: claude-code/1.x.x
# Authenticate with your Anthropic API key
export ANTHROPIC_API_KEY="sk-ant-..."
# Test on your repository
cd /path/to/your-project
claude "Review the file src/main.py for bugs, security issues, and code style problems. Output findings as a bullet list."
What you should see: Claude Code reads the file, analyzes it, and returns a structured list of findings. If it returns nothing useful, your prompt is too vague — jump to Step 2 for the template.
Pitfall alert: If you get Error: API key not found, make sure the environment variable is exported (not just set in .env — Claude Code reads ANTHROPIC_API_KEY from the environment, not from .env files).
Step 2: Write the Review Prompt Template
The quality of your automated review depends entirely on your prompt. A vague "review this code" prompt will produce vague (and sometimes wrong) feedback. Here's a battle-tested template that produces actionable, specific reviews.
Create a file at .github/claude-code-review-prompt.md:
You are a senior software engineer conducting a code review. Review the following pull request diff.
## Review Rules
1. **Bugs & Logic Errors (CRITICAL):** Look for off-by-one errors, null pointer risks, race conditions, incorrect API usage. If you find a bug, explain WHY it's wrong and suggest the fix with code.
2. **Security Issues (HIGH):** SQL injection, XSS, hardcoded secrets, missing input validation, unsafe deserialization.
3. **Performance (MEDIUM):** N+1 queries, unnecessary allocations, missing indexes, synchronous calls where async is available.
4. **Code Style (LOW):** Naming conventions, inconsistent patterns, missing type hints. Only flag these if they genuinely hurt readability — do NOT nitpick formatting.
## Output Format
For each finding, use this exact format so our CI can parse it:
FILE: path/to/file.py LINE: 42 SEVERITY: critical|high|medium|low ISSUE: One-line summary of the problem SUGGESTION: How to fix it, with code if applicable
## Important
- Skip findings about import order, whitespace, or formatting — our linter handles those.
- If a PR is entirely documentation changes, say "No code changes to review — documentation PR, skipping."
- Limit to the 10 most important findings. Do not list every minor style issue.
- If you're unsure about a finding, mark it SEVERITY: low and add "CONFIDENCE: uncertain."
Here is the PR diff to review:
Why this prompt works:
- Severity tiers prevent the reviewer from spamming 50 "add a type hint" comments while missing the SQL injection on line 200.
- Structured output (
FILE:LINE:) lets our GitHub Actions script parse findings and post them as PR review comments at the exact line. - Explicit exclusions (import order, whitespace) stop Claude Code from wasting tokens on things your linter already checks.
- Uncertainty flag prevents false-confidence bugs — an AI that admits "I'm not sure" is more trustworthy than one that confidently hallucinates.
Step 3: Create the GitHub Actions Workflow
Now we'll create the CI pipeline. This workflow triggers on every PR (opened, updated, or reopened), runs Claude Code against the diff, and posts findings as review comments.
Create .github/workflows/claude-code-review.yml:
name: Claude Code PR Review
on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
permissions:
contents: read
pull-requests: write
issues: write
jobs:
ai-review:
runs-on: ubuntu-latest
if: github.event.pull_request.draft == false
timeout-minutes: 15
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0 # Full history for accurate diff
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install Claude Code CLI
run: npm install -g @anthropic-ai/claude-code
- name: Generate PR diff
id: diff
run: |
git diff origin/${{ github.base_ref }}...HEAD > /tmp/pr.diff
echo "diff_lines=$(wc -l < /tmp/pr.diff)" >> $GITHUB_OUTPUT
echo "diff_size=$(stat -c%s /tmp/pr.diff)" >> $GITHUB_OUTPUT
- name: Skip if diff too large
if: steps.diff.outputs.diff_lines > 5000
run: |
echo "⚠️ Diff exceeds 5000 lines (${{ steps.diff.outputs.diff_lines }}). Skipping AI review to avoid token overflow."
echo "LARGE_DIFF=true" >> $GITHUB_ENV
- name: Run Claude Code Review
if: env.LARGE_DIFF != 'true'
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
run: |
# Combine prompt template + diff
cat .github/claude-code-review-prompt.md /tmp/pr.diff > /tmp/full_prompt.md
# Run Claude Code in non-interactive mode
claude --print --max-turns 1 \
-p "$(cat /tmp/full_prompt.md)" \
> /tmp/review_output.txt 2>/tmp/review_error.txt
echo "Review output lines: $(wc -l < /tmp/review_output.txt)"
- name: Post Review Comments
if: env.LARGE_DIFF != 'true'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ github.event.pull_request.number }}
run: |
python3 .github/scripts/post_review_comments.py \
/tmp/review_output.txt \
$PR_NUMBER
Key decisions explained:
| Setting | Why |
|---|---|
fetch-depth: 0 | We need full git history to compute git diff against the base branch accurately |
if: draft == false | Don't waste API credits reviewing draft PRs — wait until they're marked ready |
timeout-minutes: 15 | Claude Code with large diffs can take 5-10 minutes; 15 is a safe ceiling |
--max-turns 1 | Prevent Claude Code from going into agent loop — we want a single review pass, not tool calls |
--print | Output to stdout instead of interactive mode, required for CI |
| 5000-line diff limit | Claude's context window handles ~200K tokens; 5000 lines of diff ≈ ~80K tokens with the prompt, leaving room for the response |
Step 4: Write the Comment-Posting Script
Claude Code outputs structured review findings. We need a Python script that parses FILE:LINE:SEVERITY: blocks and posts them as GitHub PR review comments at the correct line.
Create .github/scripts/post_review_comments.py:
# !/usr/bin/env python3
"""Parse Claude Code review output and post comments to GitHub PR."""
import os, re, sys, json, urllib.request
GITHUB_TOKEN = os.environ["GITHUB_TOKEN"]
REPO = os.environ["GITHUB_REPOSITORY"]
PR_NUMBER = sys.argv[2] if len(sys.argv) > 2 else os.environ.get("PR_NUMBER")
REVIEW_FILE = sys.argv[1]
if not PR_NUMBER:
print("ERROR: PR_NUMBER not set")
sys.exit(1)
# Parse Claude Code output
with open(REVIEW_FILE) as f:
text = f.read()
# Regex to match FILE/LINE/SEVERITY/ISSUE/SUGGESTION blocks
pattern = re.compile(
r"FILE:\s*(.+?)\n"
r"LINE:\s*(\d+)\n"
r"SEVERITY:\s*(critical|high|medium|low)\n"
r"ISSUE:\s*(.+?)\n"
r"SUGGESTION:\s*(.+?)(?:\n---|\n$|\Z)",
re.DOTALL
)
findings = []
for m in pattern.finditer(text):
findings.append({
"path": m.group(1).strip(),
"line": int(m.group(2)),
"severity": m.group(3).strip(),
"issue": m.group(4).strip(),
"suggestion": m.group(5).strip(),
})
print(f"Parsed {len(findings)} findings from review output")
if not findings:
# Post a summary comment saying no issues found
print("No issues found — posting positive review summary")
findings = [{
"path": "GENERAL",
"line": 1,
"severity": "low",
"issue": "✅ Claude Code automated review found no critical issues",
"suggestion": "Great job! Proceed with human review for logic and architecture decisions.",
}]
# Post each finding as a PR review comment
api_base = f"https://api.github.com/repos/{REPO}/pulls/{PR_NUMBER}"
severity_emoji = {
"critical": "🔴", "high": "🟠", "medium": "🟡", "low": "🟢"
}
for f in findings:
body = f"**{severity_emoji.get(f['severity'], '')} [{f['severity'].upper()}] {f['issue']}**\n\n{f['suggestion']}\n\n---\n*🤖 Automated review by Claude Code*"
payload = json.dumps({
"body": body,
"path": f["path"] if f["path"] != "GENERAL" else None,
"line": f["line"] if f["path"] != "GENERAL" else None,
"side": "RIGHT",
}).encode()
url = f"{api_base}/comments"
req = urllib.request.Request(url, data=payload, method="POST")
req.add_header("Authorization", f"token {GITHUB_TOKEN}")
req.add_header("Accept", "application/vnd.github+json")
req.add_header("Content-Type", "application/json")
try:
with urllib.request.urlopen(req) as resp:
result = json.loads(resp.read())
print(f" ✅ Posted: {f['path']}:{f['line']} [{f['severity']}] — comment ID {result.get('id')}")
except urllib.error.HTTPError as e:
err_body = e.read().decode()
print(f" ❌ Failed to post {f['path']}:{f['line']}: {e.code} — {err_body[:200]}")
print(f"\nDone. {len(findings)} comments posted to PR #{PR_NUMBER}")Make the script executable:
chmod +x .github/scripts/post_review_comments.pyStep 5: Set Up Secrets and Test
-
Add your Anthropic API key to GitHub Secrets:
- Go to your repo → Settings → Secrets and variables → Actions
- Click "New repository secret"
- Name:
ANTHROPIC_API_KEY - Value: your
sk-ant-...key
-
Push everything and create a test PR:
git add .github/
git commit -m "Add Claude Code automated PR review workflow"
git push
# Create a branch with some intentional issues to test
git checkout -b test-ai-review
echo "def divide(a, b): return a / b # What if b=0?" > src/buggy.py
git add src/buggy.py
git commit -m "Add division function (intentionally missing zero check)"
git push origin test-ai-review
# Create PR via GitHub CLI
gh pr create --title "Test: AI review of buggy code" --body "Testing Claude Code automated review"- Check the Actions tab — the workflow should trigger automatically. Within 2-5 minutes, you should see Claude Code's review comments appear on your PR.

Common Pitfalls
- "API key not found" in CI: Double-check the secret name is exactly
ANTHROPIC_API_KEY(case-sensitive). GitHub Actions${{ secrets.XXX }}is case-sensitive —ANTHROPIC_API_KEY≠anthropic_api_key. - Claude Code gets stuck in a loop: The
--max-turns 1flag is critical. Without it, Claude Code may try to run bash commands, edit files, and enter an agentic loop that burns API credits and times out the job. - Review finds "issues" that aren't real: If Claude Code hallucinates bugs (e.g., claiming there's an SQL injection in a file with no SQL), your prompt needs more context. Add a note: "This is a Python project using SQLAlchemy ORM — raw SQL queries are not present." Be specific about your tech stack.
- Large PRs time out or exceed token limits: The 5000-line diff guard handles most cases, but if you have frequent large PRs, consider reviewing only changed functions (use
git diff --function-context) or splitting the review into multiple chunks. - Comments posted at wrong lines: GitHub's PR review API uses the right-side (new) line numbers. If the diff context shifts (e.g., someone pushes more commits while review is running), line numbers may be stale. To mitigate, use
pull_request.synchronizeto re-trigger on every push — the event already handles this. - Cost control: Each PR review costs approximately $0.05-0.30 in Anthropic API credits (depending on diff size and claude-sonnet-4-20250514 pricing). For a team with 20 PRs/day, that's ~$3-6/day. Set up Anthropic usage alerts to catch cost spikes early.
Next Steps
- Customize for your tech stack: Edit the review rules in
.github/claude-code-review-prompt.mdto match your language (Rust borrow checker issues, React hook dependencies, SQL query patterns, etc.) - Add auto-fix: Extend the workflow so Claude Code can directly commit suggested fixes to the PR branch (use
gh pr checkout+claude --dangerously-skip-permissionswith caution) - Review summary comment: Instead of individual line comments, post one summary comment with all findings using the GitHub Reviews API
- Pair with human review: Tag specific team members when the AI flags
criticalorhighseverity — use GitHub CODEOWNERS or a custom routing script - Try other AI tools: The same pattern works with OpenAI Codex CLI — swap
claudeforcodex execand adjust the prompt format
Related tutorials: How to Build a Custom MCP Server for Claude Code · How to Use OpenAI Codex CLI · AI Coding Agent Security Configuration
相关推荐
How to Automate Daily AI Research with n8n and DeepSeek: Zero-Code Guide
If you want an automated daily AI research digest without writing code, this tutorial walks you through a complete n8n workflow in 30 minutes. Use the Schedule Trigger to fetch headlines from NewsAPI, pipe them through DeepSeek for intelligent summarization, and deliver the finished digest to Slack, email, or Notion — all drag-and-drop.
How to Build a Custom MCP Server for Claude Code: Step-by-Step Guide
If you want to build a custom MCP server so Claude Code can call your own tools — weather lookup, file summary, todo manager — this tutorial gives you a complete step-by-step guide with working Python code, JSON Schema tool definitions, and real API integration in under 45 minutes.
主题中心
2026 AI 编程工具全景指南
从 Copilot 改版到 Claude Code / DeepSeek 低成本方案——把分散资讯收成可搜索、可对比的工具矩阵。
进入「2026 AI 编程工具全景指南」 →赚钱视角
这个趋势怎么赚钱?
WayToClawEarn 的差异在可验证的赚钱案例,而不只是资讯。从这些复盘开始:
浏览全部案例 →相关教程
相关资讯
- How Do You Track Codex CLI Token Usage? Codex v0.140 Adds /usage, Claude Code Import, and Session Deletion
- Can Claude Design Replace Your Design Tool? Anthropic Adds Code Round-Trips, Figma Imports, and 2x Tokens
- Will Claude Require ID Verification? Anthropic's New Privacy Policy Explained
- Did Anthropic Cancel the Claude Agent SDK Credit Split? June 15 Pause Explained