WayToClawEarn
进阶阅读约 35 分钟2026年6月18日

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.

terminal

# 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."

Claude Code terminal output showing review results

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:

markdown
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

code

## 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:

yaml
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

GitHub Actions workflow diagram: PR opened → Claude Code review → comment on PR

Key decisions explained:

SettingWhy
fetch-depth: 0We need full git history to compute git diff against the base branch accurately
if: draft == falseDon't waste API credits reviewing draft PRs — wait until they're marked ready
timeout-minutes: 15Claude Code with large diffs can take 5-10 minutes; 15 is a safe ceiling
--max-turns 1Prevent Claude Code from going into agent loop — we want a single review pass, not tool calls
--printOutput to stdout instead of interactive mode, required for CI
5000-line diff limitClaude'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:

python

# !/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:

terminal
chmod +x .github/scripts/post_review_comments.py

Step 5: Set Up Secrets and Test

  1. 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
  2. Push everything and create a test PR:

terminal
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"
  1. 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.

GitHub PR showing Claude Code review comments at specific lines

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_KEYanthropic_api_key.
  • Claude Code gets stuck in a loop: The --max-turns 1 flag 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.synchronize to 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.md to 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-permissions with 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 critical or high severity — use GitHub CODEOWNERS or a custom routing script
  • Try other AI tools: The same pattern works with OpenAI Codex CLI — swap claude for codex exec and 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

免责声明:本站案例均为知识分享内容,仅供灵感与参考,不构成收益承诺;由此进行的外部执行与结果请自行判断并承担相应责任。

相关推荐