Skip to main content
Back to Blog
Claude CodeGitHub ActionsCI/CDCode Review AutomationDevOpsAI Agents

How to Automate Multi-Axis PR Code Reviews using Claude Code and GitHub Actions CI/CD

Learn how to integrate Claude Code into your GitHub Actions pipeline to automatically review pull requests across security, performance, and testability axes, posting line-by-line feedback before a human ever opens the diff.

September 13, 202616 min readNiraj Kumar

Introduction

If you've ever watched a pull request sit in a queue for two days waiting for a senior engineer to "get around to it," you already know the real cost of code review isn't the review itself — it's the wait. Bugs compound while a PR sits idle. Context evaporates from the author's head. And senior engineers, the people best equipped to catch subtle security or performance issues, end up spending their mornings reading diffs instead of writing code.

This is where an agentic reviewer earns its keep. Instead of waiting for a human to have five free minutes, you can have Claude Code run automatically the moment a pull request opens, read the diff with full repository context, evaluate it across multiple axes — security, performance, testability, and whatever else your team cares about — and leave targeted, line-by-line comments directly on GitHub. By the time a human reviewer opens the PR, the obvious issues are already flagged, and the human can spend their limited attention on architecture and intent instead of typos and off-by-one errors.

In this tutorial, we'll build exactly that: a production-ready GitHub Actions workflow that runs Claude Code on every pull request, performs a structured multi-axis review, and posts inline comments automatically. We'll cover the GitHub App setup, the workflow YAML, prompt engineering for multi-axis evaluation, and the operational guardrails you need before you let an AI agent comment on every PR in your organization.

By the end, you'll have a pipeline that turns "please review my PR" into "here's what's already been reviewed — go look at the three things that matter."

Why Multi-Axis Review Matters More Than a Single Linter Pass

Most teams already run static analysis: ESLint, RuboCop, Bandit, SonarQube, whatever fits the stack. These tools are excellent at catching syntax-level problems and known anti-patterns, but they share a common limitation — they evaluate code in isolation, one rule at a time, with no understanding of why the change was made or how it fits into the broader system.

A multi-axis review means evaluating the same diff through several different lenses simultaneously, the way a thoughtful senior engineer would:

  • Security: Does this change introduce an injection vector, a broken auth check, an exposed secret, or an unsafe deserialization path?
  • Performance: Does this introduce an N+1 query, an unbounded loop, a blocking call on a hot path, or unnecessary re-renders?
  • Testability: Is the new logic covered by tests? Are the tests actually asserting behavior, or just checking that the function doesn't throw? Is the code structured in a way that's even testable?

A static linter can't reason across these axes because it doesn't understand intent — it just pattern-matches. An LLM-based agent like Claude Code can. It can read the full diff, pull in surrounding files for context, understand what the PR is trying to accomplish from its title and description, and then reason about each axis independently before writing up its findings. That's a fundamentally different (and more useful) kind of review.

How Claude Code Fits Into a GitHub Actions Pipeline

Claude Code is Anthropic's agentic coding tool, normally used from your terminal, IDE, or desktop app. The part that makes this tutorial possible is the Claude Code GitHub Action — a GitHub Action that runs the same underlying agent inside a GitHub Actions job. It's built on the Claude Agent SDK, so it has the same core capabilities you'd get locally: it can read files, run shell commands, use the GitHub API through bundled MCP tools, and follow instructions from a CLAUDE.md file in your repository.

Two things make this different from a simple "call an LLM API and paste in a diff" script:

  1. Full repository context. Since the action checks out your repository before running, Claude Code isn't reviewing a blind diff — it can open the surrounding files, check how a function is used elsewhere, look at the existing test suite, and reason with the same context a human reviewer would have.
  2. Native GitHub integration. Through the GitHub App and bundled MCP tools, Claude Code can post structured, line-anchored comments directly on the PR diff — not just a wall of text in a workflow log.

It's worth being precise about naming here, because Anthropic ships a few related products that get confused with each other:

  • Claude Code GitHub Action (anthropics/claude-code-action) — the workflow-file-based integration this tutorial covers. You control the trigger, the prompt, and the model.
  • Claude Code Review — a separate, managed product that reviews every PR automatically without you writing a workflow file at all.
  • Claude Code on the web — browser and mobile sessions, unrelated to CI.

This tutorial focuses on the GitHub Action because building your own workflow is what gives you control over the multi-axis prompt, the model, the triggers, and exactly where feedback gets posted.

Prerequisites

Before you start, make sure you have:

  • Admin access to the GitHub repository (required to install a GitHub App and add secrets)
  • A Claude API key from the Claude Console, or a Claude subscription (Pro, Max, Team, or Enterprise) if you'd rather authenticate with an OAuth token
  • The GitHub CLI installed locally, if you want to use the guided quick-setup path
  • A repository that already has a CI pipeline you don't mind extending

Step 1: Install the Claude GitHub App

You have two ways to wire this up: a guided quick setup from your terminal, or a fully manual setup. Both end in the same place — a workflow file, a secret, and an installed GitHub App — so pick whichever fits your comfort level.

If you already run Claude Code locally, this is the fastest path. Open claude inside your repository and run:

/install-github-app

This command:

  • Installs the Claude GitHub App on your repository
  • Creates an authentication secret (ANTHROPIC_API_KEY if you use an API key, or CLAUDE_CODE_OAUTH_TOKEN if you authenticate with your Claude subscription)
  • Pushes a branch containing the workflow file(s) you select and opens a pull request for you to review and merge

You need admin access to the repo for this to work, and the CLI checks for gh auth login before proceeding.

Option B: Manual setup

If you'd rather not run Claude Code locally, or you want full control over the workflow file from the start, do it by hand:

  1. Install the Claude GitHub App on your repository or organization.
  2. Add an authentication secret in Settings → Secrets and variables → Actions:
    • ANTHROPIC_API_KEY for API key authentication, or
    • CLAUDE_CODE_OAUTH_TOKEN for subscription-based authentication (generate one locally with claude setup-token)
  3. Copy the example workflow file into .github/workflows/ and adapt it — which is exactly what we'll do in Step 4.

The GitHub App itself is shared across several Claude features (the GitHub Action, Code Review, and web auto-fix), so it requests a fairly broad permission set — Contents, Issues, Pull requests, Checks, Actions, Discussions, Repository hooks, and a couple of read-only scopes for Members and Metadata. If your organization's security policy requires a narrower footprint, you can register a custom GitHub App scoped to just Contents, Issues, and Pull requests — but that custom app only supports the GitHub Action, not the managed Code Review product.

Step 2: Define Your Review Standards in CLAUDE.md

Before touching the workflow YAML, give Claude something to review against. Drop a CLAUDE.md file in your repository root — Claude Code reads it automatically on every run, whether that run happens locally or inside CI.

# CLAUDE.md

## Project context
This is a Node.js/TypeScript service handling payment processing.
Correctness and security take priority over stylistic preferences.

## Code review priorities
When reviewing pull requests, evaluate changes against these axes,
in this order of severity:

1. **Security**
   - Flag any raw SQL string concatenation — we use parameterized
     queries exclusively via our `db` client.
   - Flag any use of `eval`, `Function()`, or dynamic `require()`.
   - Flag secrets, tokens, or credentials committed in plaintext.
   - Flag missing authorization checks on any route under `/api/admin`.

2. **Performance**
   - Flag database calls inside loops (N+1 query patterns).
   - Flag synchronous file or network I/O on request-handling paths.
   - Flag unbounded array operations on data that can grow without limit.

3. **Testability**
   - New business logic in `/src/services` must have a corresponding
     test file in `/test/services`.
   - Tests must assert on behavior/output, not just "does not throw."
   - Flag functions with more than two levels of nested conditionals
     without a test covering each branch.

## Style
- Prefer named exports over default exports.
- Avoid `any` in TypeScript — suggest a concrete type or `unknown`.

This file does double duty: Claude Code uses it for every task, not just reviews (implementing features, fixing bugs, answering questions), so you get consistent standards enforcement across your whole automation surface, not just this one pipeline.

Step 3: Build the GitHub Actions Workflow

Now for the core of the tutorial — the workflow file itself. We'll build this in automation mode, meaning we give Claude Code an explicit prompt input instead of waiting for someone to type @claude in a comment. This runs the review automatically on every PR event, with no human trigger required.

Create .github/workflows/multi-axis-review.yml:

name: Multi-Axis PR Review

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

concurrency:
  group: multi-axis-review-${{ github.event.pull_request.number }}
  cancel-in-progress: true

jobs:
  review:
    if: github.event.pull_request.draft == false
    runs-on: ubuntu-latest
    timeout-minutes: 15
    permissions:
      contents: read
      pull-requests: read
      issues: read
      id-token: write
    steps:
      - name: Checkout PR branch
        uses: actions/checkout@v6
        with:
          fetch-depth: 0

      - name: Run Claude Code multi-axis review
        uses: anthropics/claude-code-action@v1
        with:
          anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
          prompt: |
            Review the diff introduced by this pull request
            (#${{ github.event.pull_request.number }} in
            ${{ github.repository }}) against three independent axes:

            1. SECURITY — injection risks, broken auth checks, exposed
               secrets, unsafe deserialization, missing input validation.
            2. PERFORMANCE — N+1 queries, blocking I/O on hot paths,
               unbounded loops, unnecessary re-computation.
            3. TESTABILITY — missing or shallow test coverage for new
               logic, untested branches, hard-to-test function design.

            Follow the priorities and conventions defined in CLAUDE.md.

            For every issue you find, post an inline comment on the
            exact line using the GitHub inline comment tool. Label each
            comment with its axis, for example "[Security]" or
            "[Performance]", followed by a one-sentence explanation and
            a concrete suggested fix. If you find no issues on an axis,
            do not post anything for that axis. If the PR is completely
            clean, post a single short summary comment saying so.
          claude_args: |
            --model claude-sonnet-5
            --max-turns 8
            --allowedTools "mcp__github_inline_comment__create_inline_comment,mcp__github__get_pull_request_diff"

Breaking down the important parts

  • concurrency: cancels a stale review run if the author pushes another commit before the first review finishes — otherwise you'll get two sets of comments on two different versions of the diff.
  • if: github.event.pull_request.draft == false: skips draft PRs, so authors aren't getting automated feedback on work-in-progress code.
  • fetch-depth: 0: pulls full git history so Claude can diff against the base branch properly rather than working from a shallow, partial checkout.
  • permissions: intentionally minimal. We don't grant contents: write because this job only reads code and comments — it never pushes commits.
  • id-token: write: required for the action's default GitHub App authentication flow, even when the job itself doesn't otherwise need OIDC.
  • prompt: this is where the multi-axis instructions live. Because it's plain text rather than a packaged skill, Claude Code has no GitHub API access by default — which is exactly why the next field matters.
  • claude_args: passes CLI flags straight to Claude Code. --allowedTools explicitly grants the two GitHub MCP tools the review needs — one to read the diff, one to post inline comments — and nothing else. --max-turns 8 caps how many internal steps Claude can take, which bounds both latency and cost per run.

Note that on public repositories, GitHub withholds secrets from workflow runs triggered by pull requests from forks, so this pipeline reviews same-repository branches only unless you add a separate, more carefully sandboxed workflow for fork PRs.

Step 4: Test the Pipeline

Push the workflow file to your default branch, then open a test PR with a deliberately flawed change — something like an unparameterized SQL query, a database call inside a loop, and a new function with zero test coverage. Within a couple of minutes of the PR opening, you should see:

  • A check run appear on the PR from the Claude Code GitHub Action
  • Inline comments appear directly on the offending lines, each labeled by axis
  • A short summary if everything else in the diff was clean

If nothing happens, jump to the Troubleshooting section below before assuming the prompt is wrong — most first-run failures are permission or secret issues, not prompt issues.

Real-World Example: Catching an Injection Vector Before a Human Ever Looks

Here's a realistic scenario. An engineer opens a PR adding a search endpoint:

// routes/search.js
app.get("/api/search", async (req, res) => {
  const term = req.query.q;
  const results = await db.query(
    `SELECT * FROM products WHERE name LIKE '%${term}%'`
  );
  res.json(results);
});

Functionally, this works — searches return matching products. A busy human reviewer skimming for the PR's stated purpose ("add product search") might approve it without a second look. Claude Code, prompted with the multi-axis instructions above, catches two things immediately:

  • [Security] on the db.query line: the term variable is concatenated directly into the SQL string, creating a classic SQL injection vector. It suggests switching to a parameterized query using the project's existing db client conventions from CLAUDE.md.
  • [Testability] on the new route handler: there's no corresponding test file under /test/routes, and the CLAUDE.md rule requires one for new service logic.

Both comments land on the PR before the human reviewer opens it. The author fixes the query, adds a test, pushes again, and the concurrency group cancels the stale review and kicks off a fresh one. By the time a senior engineer actually looks at the PR, the SQL injection is already gone — they're reviewing the design of the search feature, not hunting for injection bugs.

🚀 Pro Tips

  • Version-pin the action. Use anthropics/claude-code-action@v1 rather than @main, so a breaking change upstream doesn't silently alter your review behavior overnight.
  • Split reviews by file type for large monorepos. If your repo mixes frontend and backend code, consider two workflow jobs with different CLAUDE.md-equivalent instructions (or a paths filter) so backend security rules don't get applied nonsensically to CSS changes.
  • Use allowed_non_write_users sparingly. By default, only users with write access can trigger automation-mode runs on commented/interactive flows; opening this up to more users increases your exposure to prompt injection from untrusted PR descriptions.
  • Set a hard cost ceiling. Combine --max-turns with GitHub's built-in concurrency controls and a workflow timeout-minutes so a confused agent can't spiral into an expensive, runaway loop.
  • Let Claude escalate, not just flag. In your prompt, explicitly instruct Claude to distinguish "must fix before merge" from "nice to have" — this keeps the human reviewer's signal-to-noise ratio high.
  • Feed it your incident history. If your team has had real production incidents (a specific N+1 query that took down a service, a leaked API key), add those patterns explicitly to CLAUDE.md. Generic advice is good; institutional memory is better.

Common Mistakes to Avoid

  • Forgetting id-token: write. Without it, the action's default GitHub App authentication silently fails, and you'll see cryptic authentication errors instead of a clear message.
  • Granting contents: write to a review-only job. If the workflow only reads and comments, don't give it write access to repository contents — least privilege matters even more once an LLM agent is the one holding the token.
  • Using secrets.GITHUB_TOKEN for the GitHub token input. GitHub doesn't trigger new workflow runs from commits or comments made with the default GITHUB_TOKEN, which breaks any downstream automation that's supposed to react to Claude's activity. Let the action authenticate as the Claude GitHub App instead, or pass a dedicated custom app token.
  • Skipping --allowedTools. A plain-text prompt gets zero tool access by default. If Claude's comments aren't showing up on the PR, this is almost always why — the model reasoned about the code correctly but had no tool to actually post the comment.
  • Not filtering draft PRs. Reviewing work-in-progress code wastes tokens and annoys authors who explicitly marked a PR as not ready.
  • Treating this as a replacement for human review. An agent is excellent at catching known patterns and enforcing rubrics; it's not a substitute for a human's judgment on architecture, product tradeoffs, or "is this the right feature to build at all." Position it as a first pass, not a final gate.
  • Ignoring fork PRs entirely. If your project accepts external contributions, remember that secrets are withheld from fork-triggered runs by default on public repos — plan a separate, sandboxed review path for those rather than assuming the same workflow covers them.

Best Practices for a Production-Grade Pipeline

  • Keep CLAUDE.md concise. It's read on every single run, so a bloated file adds latency and cost to every review without adding proportional value. Prioritize the rules that actually prevented real incidents.
  • Review the reviewer. Periodically audit a sample of Claude's comments for false positives and false negatives, and tighten your prompt or CLAUDE.md rules accordingly — treat it like any other piece of infrastructure that needs tuning.
  • Separate the "advisory" review from your merge gate. Let the multi-axis review post comments freely, but don't block merges purely on an LLM's judgment call unless your team has built enough trust in its accuracy over time. A required status check that blocks on a security finding is reasonable; blocking on a style nitpick is not.
  • Rotate credentials like any other secret. Treat ANTHROPIC_API_KEY with the same operational rigor as your database credentials — scoped, rotated, and monitored for anomalous usage.
  • Centralize the workflow for organizations with many repos. Define the job once as a reusable workflow and call it from each repository, rather than copy-pasting the YAML everywhere and letting definitions drift.
  • Track cost and adoption. Both GitHub Actions minutes and API tokens are metered resources. Keep an eye on usage as adoption grows past a handful of repositories, especially if you switch from a per-repo API key to an organization-wide one.

Conclusion

Manual code review doesn't scale linearly with team size — it scales with the number of senior engineers willing to context-switch into someone else's diff. Putting Claude Code into your GitHub Actions pipeline doesn't remove humans from the loop; it changes what they spend their limited review time on. Instead of hunting for the SQL injection buried in line 47 of a 300-line diff, your reviewers open PRs that have already had the obvious security, performance, and testability issues flagged and, often, already fixed by the time they look.

The setup itself is a few YAML files and a CLAUDE.md, but the payoff compounds: every PR gets the same rigorous, multi-axis pass, at 2 a.m. or during a release freeze, without waiting on a human's calendar. Start with a narrow, well-scoped workflow like the one in this tutorial, watch how it performs against your real PRs for a few weeks, and expand its authority — more repos, tighter merge gates — only as it earns your trust.

References

Discussion

All Articles
Claude CodeGitHub ActionsCI/CDCode Review AutomationDevOpsAI Agents

Written by

Niraj Kumar

Software Developer — building scalable systems for businesses.