Claude Code in GitHub Actions: PR Review Workflows 2026

Last updated: April 15, 2026

Claude Code in GitHub Actions

TLDR verdict: install the official action, store your API key as a secret, wire up a PR review workflow in fifteen minutes, and expect about one dollar per medium PR on Sonnet 4.

The anthropics/claude-code-action action drops a headless Claude Code run into any GitHub workflow. You point it at a pull request or an issue, give it an API key, and it performs the task: review the diff, write the code, update the test suite, draft the changelog. The action handles the headless invocation, sets up Node, pulls the repo, and posts results back as comments or commits.

This page covers setup, two production-ready workflows, the required secrets, costs per run, and the practical trade-offs.

The official action

anthropics/claude-code-action is maintained by Anthropic. Install it by referencing the latest tagged release in any workflow file:

- uses: anthropics/claude-code-action@v1
  with:
    anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
    prompt: "Review this PR. Flag bugs and missing tests."

Under the hood the action installs Claude Code, authenticates with your key, runs a headless session against the checked-out repo, and captures both stdout and the final file diff. Comments go to the PR thread, and any file changes can be pushed as a follow-up commit.

Required secrets

Two options:

  • ANTHROPIC_API_KEY - a standard API key from console.anthropic.com. Direct-to-API billing.
  • CLAUDE_CODE_OAUTH_TOKEN - an OAuth token tied to a claude.ai Pro or Max account. Counts against that plan instead of API billing.

Pick one per repo. Store it in Settings to Secrets and variables to Actions. Never echo the value in a workflow step; set mask: true on any debug output that might include it.

For org-wide use, put the secret at the organization level and scope it to specific repos. That way key rotation happens in one place.

Permissions the job needs

For a review-only workflow that posts comments:

permissions:
  contents: read
  pull-requests: write

For a workflow that lets Claude commit changes:

permissions:
  contents: write
  pull-requests: write
  issues: write

Keep permissions as narrow as the job needs. A PR-comment job does not need contents: write, so do not grant it.

Workflow 1: automated PR review

This workflow runs on every pull request and posts a review comment with Claude findings. Drop it at .github/workflows/claude-review.yml:

name: Claude PR Review

on:
  pull_request:
    types: [opened, synchronize, reopened]

permissions:
  contents: read
  pull-requests: write

jobs:
  review:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - uses: anthropics/claude-code-action@v1
        with:
          anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
          prompt: |
            Review the pull request diff against the base branch.
            Flag bugs, missing tests, security issues, and style inconsistencies.
            Be terse. Use markdown bullet points. Post one review comment.
          model: sonnet
          max-turns: 10
          post-comment: true

The fetch-depth: 0 is important because Claude needs the full history to diff against the base branch. Without it the runner only has the PR head, and the review ends up commenting on the whole codebase instead of just the changes.

A single review on a 20-file PR costs roughly 50 cents to 2 dollars on Sonnet 4, depending on diff size. Budget accordingly; a repo that lands 20 PRs a day runs about 20 to 40 dollars a day in review cost.

Workflow 2: issue-to-commit with @claude

The second pattern lets a maintainer mention @claude in an issue comment and have the agent implement the fix. This one is riskier because Claude commits directly, so reserve it for trusted contributors.

name: Claude Implements Issue

on:
  issue_comment:
    types: [created]

permissions:
  contents: write
  pull-requests: write
  issues: write

jobs:
  implement:
    if: contains(github.event.comment.body, '@claude')
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: anthropics/claude-code-action@v1
        with:
          anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
          prompt: |
            Read the issue body and any comments.
            Implement the requested change on a new branch named fix/issue-${{ github.event.issue.number }}.
            Run the test suite. If tests pass, open a PR linked to the issue.
            If tests fail, comment on the issue with the failure log.
          model: opus
          max-turns: 30
          allowed-tools: Read,Write,Edit,Bash
          create-pr: true

Key safeguards:

  • The if: contains(...) gate limits triggers to comments that mention @claude. Without it every comment on every issue fires the workflow.
  • max-turns: 30 caps the agent at 30 tool rounds. A typical feature takes 10 to 20; this adds headroom without letting a stuck loop run forever.
  • The PR that Claude opens goes through the normal review process. No direct pushes to main.

Typical cost for a small-ticket implementation: 2 to 5 dollars on Opus 4. Reserve this pattern for tickets that are well specified and low stakes.

Combining with test runs

The real value comes from chaining Claude with your test runner. Add a second job that depends on the review job:

  test:
    needs: review
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: pnpm install
      - run: pnpm test
      - run: pnpm lint

If the review job posts a comment but the tests fail, the PR is blocked by branch protection until both checks go green. You get the review benefit without letting Claude merge unchecked code.

For the issue-to-commit workflow, move the test run inside the agent prompt instead:

prompt: |
  Implement the issue.
  Run `pnpm test` and `pnpm lint`.
  Only open a PR if both pass. Otherwise comment with the failure output.

Claude can read the test output and fix issues iteratively, which is the point of an agent in the first place.

Branch protection and merge strategy

Enable branch protection on main before wiring up any auto-commit workflow. At minimum:

  • Require PRs to pass status checks before merging
  • Require at least one human review for PRs that touch protected paths
  • Disable direct pushes to main

For the review-only workflow this is already the default for most teams. For the issue-to-commit workflow, branch protection is the guardrail that keeps Claude from quietly shipping a bug. Treat Claude commits like any other contributor: they go through review.

Cost implications

A few reference numbers from real workflows at the time of writing:

  • Small PR review (5 files, 200 lines): 0.30 to 0.80 dollars on Sonnet 4
  • Medium PR review (20 files, 800 lines): 0.80 to 2.00 dollars on Sonnet 4
  • Large PR review (50+ files): 2 to 5 dollars
  • Issue-to-commit on a well-scoped ticket: 2 to 8 dollars on Opus 4
  • Issue-to-commit on a vague ticket that the agent fumbles: 10 to 30 dollars before the max-turns cap hits

A repo with 30 PRs a day and a review workflow pays roughly 20 to 50 dollars a day. Compare that against the hours of human review time it replaces; for most teams the math works out.

To keep costs predictable, set max-turns low on review jobs and only enable the Opus issue-to-commit flow on select repos.

Input filtering and prompt safety

Workflows triggered by issue_comment or pull_request accept input that an untrusted user can influence. Never paste github.event.comment.body verbatim into a prompt without sanitization. A hostile comment can redirect the agent into unwanted behavior.

Safer pattern:

prompt: |
  Issue number: ${{ github.event.issue.number }}
  (The agent will fetch the issue body via the gh CLI and reason about it inside tool output, which is less susceptible to prompt injection than inlining the raw body.)

For public repos, gate the issue-to-commit workflow on contributor role:

if: github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'OWNER'

This rejects comments from drive-by users and limits exposure.

Debugging a failing job

When a Claude Code action fails, the workflow log shows the stderr from the headless run. Three common issues:

  1. Missing secret - the job logs ANTHROPIC_API_KEY is not set. Fix by adding the secret at repo or org level.
  2. Shallow clone - Claude reviews the wrong files because the diff is incomplete. Add fetch-depth: 0 to the checkout step.
  3. Max-turns hit - the agent ran out of rounds before finishing. Either raise the cap or tighten the prompt. Check the JSON output to see where it got stuck.

Enable ACTIONS_RUNNER_DEBUG: true on the job to see verbose output. It adds noise but catches edge cases quickly.

Where this fits in the broader toolkit

GitHub Actions is one of three ways to automate Claude Code. Headless mode from a shell script handles cron jobs and local CI. Remote triggers over webhooks handle callbacks from external services. GitHub Actions specifically handles repo-centric automation: PR review, commit generation, release notes, issue triage.

Pick the tool that matches the trigger. Repo events go through Actions. Scheduled jobs on a VPS go through cron. External webhooks go through a dedicated endpoint.

Frequently asked questions

Do I need Claude Max or will the API key work?

Either works. The API key bills per token, the OAuth token counts against a claude.ai Pro or Max plan. Teams running heavy CI traffic usually prefer the API key because quotas are predictable.

Can Claude commit directly to main?

Only if you disable branch protection, which you should not. The issue-to-commit workflow opens a PR instead. Review and merge it through your normal process.

How do I stop a runaway agent from burning credit?

Set `max-turns` to a realistic cap (10 for review, 30 for implementation). Add a `timeout-minutes` on the job. Monitor spend weekly via the Anthropic usage dashboard.

Does the action work on self-hosted runners?

Yes. The action only needs Node and outbound HTTPS to api.anthropic.com. Self-hosted runners give you more control over secrets and network egress, which matters for regulated teams.

What if Claude posts a wrong review?

Treat it as a junior reviewer. Human review still happens. When Claude flags something that is not a real issue, the human ignores the comment. Over time, refine the prompt to reduce false positives.

Can I run multiple Claude jobs in parallel on one PR?

Yes, each job is a separate headless invocation. Use matrix builds to split reviews by file type (security, perf, style) if the single-prompt approach gets too noisy.