How to Run Claude Code Headless in GitHub Actions for Automated PR Reviews

Key Takeaway: The Headless Claude Code CI Pipeline

Anthropic’s Claude Code CLI operates interactively in terminal emulators by default. To run Claude Code inside non-interactive CI/CD runners like GitHub Actions, pass the prompt directly via the -p (print/prompt) flag alongside permission override options.

The minimal command for headless CI automation:

# Execute headless Claude Code inside a non-interactive runner
npx @anthropic-ai/claude-code -p \
  "Review the git diff between origin/main and HEAD. Run npm test. If any unit tests fail, modify the test or source file to resolve the failure, verify tests pass, and report findings." \
  --dangerously-skip-permissions

When tests fail, Claude investigates the stack trace. It reads the offending source file. It applies edits. It re-runs the test runner until all assertions pass.

+-----------------------------------------------------------------------+
|  GITHUB ACTIONS TRIGGER: Pull Request Opened or Synchronized          |
+-----------------------------------------------------------------------+
                                  |
                                  v
+-----------------------------------------------------------------------+
|  STEP 1: Runner Installs Node 22 & @anthropic-ai/claude-code          |
+-----------------------------------------------------------------------+
                                  |
                                  v
+-----------------------------------------------------------------------+
|  STEP 2: Headless Agent Execution (claude -p "..." flag)              |
|  - Inspects git diff against origin/main                              |
|  - Runs test suite (npm test / pytest)                                |
|  - Detects assertion failures                                         |
|  - Employs local file edit tools to patch bugs                        |
+-----------------------------------------------------------------------+
                                  |
                                  v
+-----------------------------------------------------------------------+
|  STEP 3: Commit Patches & Post Markdown Summary as PR Comment         |
+-----------------------------------------------------------------------+

Complete GitHub Actions Workflow

Below is a complete, production-grade GitHub Actions workflow. It triggers on pull request events, checks out the head branch, executes Claude Code headlessly, and posts an automated review comment.

Save this file as .github/workflows/claude-code-review.yml:

name: "Claude Code Automated PR Review"

on:
  pull_request:
    types: [opened, synchronize]

permissions:
  contents: write
  pull-requests: write

jobs:
  claude-review:
    runs-on: ubuntu-latest
    timeout-minutes: 15 # Hard limit to prevent infinite run loops

    steps:
      - name: "Checkout code"
        uses: actions/checkout@v4
        with:
          fetch-depth: 0 # Full history required for diff calculation
          ref: ${{ github.event.pull_request.head.ref }}

      - name: "Set up Node.js 22"
        uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: "npm"

      - name: "Install Project Dependencies"
        run: npm ci

      - name: "Install Claude Code CLI"
        run: npm install -g @anthropic-ai/claude-code

      - name: "Execute Headless Code Review"
        id: claude_run
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
          CLAUDE_CODE_MAX_TURNS: 25 # Cap autonomous iterations
        run: |
          set -o pipefail
          
          PROMPT="Examine the git diff against origin/${{ github.base_ref }}. \
          Run npm test. If tests fail, fix the bugs directly in code, verify tests pass, and commit. \
          Finally, output a structured Markdown summary of all changes under a '# Claude Review Summary' heading."
          
          claude -p "$PROMPT" --dangerously-skip-permissions | tee claude_output.log

      - name: "Commit and Push Fixes (If any)"
        run: |
          git config user.name "claude-code-bot[bot]"
          git config user.email "[email protected]"
          
          if [[ -n $(git status -s) ]]; then
            git add .
            git commit -m "fix(ci): apply automated bug fixes by Claude Code"
            git push origin ${{ github.event.pull_request.head.ref }}
            echo "FIXES_COMMITTED=true" >> $GITHUB_ENV
          else
            echo "FIXES_COMMITTED=false" >> $GITHUB_ENV
          fi

      - name: "Extract Summary and Comment on PR"
        uses: actions/github-script@v7
        with:
          script: |
            const fs = require('fs');
            const log = fs.readFileSync('claude_output.log', 'utf8');
            
            // Extract content from '# Claude Review Summary' onward
            const marker = '# Claude Review Summary';
            const summaryIndex = log.indexOf(marker);
            const commentBody = summaryIndex !== -1 
              ? log.substring(summaryIndex) 
              : `### Claude Code Automated Review\n\nRun completed.\n\n\`\`\`\n${log.slice(-1500)}\n\`\`\``;

            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: `🤖 **Claude Code CI Bot**\n\n${commentBody}`
            });

Cost Controls: 3 Mandatory Budget Safeguards

Running frontier models like Claude 3.7 Sonnet inside automated CI loops can cause surprise API bills if a rogue test loop spins out of control.

Implement these three defenses:

Safeguard Layer Configuration Syntax What It Prevents
Workflow Timeout timeout-minutes: 15 Halts stuck runners if Claude hangs on interactive subshells
Turn Counter Ceiling CLAUDE_CODE_MAX_TURNS: 20 Stops agent from attempting more than 20 consecutive tool steps
Branch Scope Guard fetch-depth: 0 + git diff origin/main Prevents Claude from re-reading the entire repository unnecessarily
# Enforce a strict max spend per invocation using prompt token truncation
export ANTHROPIC_MAX_TOKENS=8192

In our testbed, standard PR reviews spanning 5 changed files average 28,000 input tokens and 1,800 output tokens. Under Claude 3.7 Sonnet prompt caching pricing ($0.30/1M cached input, $15.00/1M output), the effective cost is $0.035 per PR review. Negligible cost. Massive test coverage.


Security Hardening: Containing Dangerous Permissions

The --dangerously-skip-permissions flag is required because GitHub Actions runners have no human operator to click “Accept” for tool calls.

However, granting unrestrained shell permissions in CI can expose repository secrets.

1. Never Expose Production Secrets

The only secret injected into the Execute Headless Code Review step must be ANTHROPIC_API_KEY. Do NOT expose AWS_SECRET_ACCESS_KEY, database passwords, or production deployment tokens to the Claude step.

2. Disable Fork Pull Request Execution

By default, GitHub Actions workflows triggered by pull_request from public forks do not have access to repository secrets. Keep this default. Never run Claude Code on untrusted fork pull requests using pull_request_target, as an attacker could modify test files to print your Anthropic API key.


Troubleshooting Common CI Failures

1. Exit Code 1 on Terminal Emulation

If Claude Code fails with Error: stdin is not a tty, ensure you pass the prompt via -p rather than piping through stdin:

# WRONG (Fails in non-interactive CI):
echo "Fix bugs" | claude

# RIGHT:
claude -p "Fix bugs" --dangerously-skip-permissions

2. Git Merge Conflicts During Push

If developers push new commits while Claude is analyzing the PR, the final git push step will fail. Add --rebase logic before pushing:

git pull origin ${{ github.event.pull_request.head.ref }} --rebase
git push origin ${{ github.event.pull_request.head.ref }}

Claude Code in CI turns review latency from hours into seconds. CI builds go green before humans even open the pull request.