How to set up Claude code review in GitHub Actions with your Claude subscription

Most guides set up Claude code review with the official code-review plugin. In GitHub Actions that plugin posts "no findings" without reviewing anything. Here is a setup that actually reviews, runs on the Claude Pro or Max plan you already have, and needs no API key.

Zacharias Creutznacher Zacharias Creutznacher

How to set up Claude code review in GitHub Actions with your Claude subscription

If you have a Claude Pro or Max plan, you can let Claude review every pull request in GitHub Actions. No API key and no separate billing: the review runs on your subscription, just like Claude Code on your machine.

One warning first: most guides, including popular ones, set this up with Anthropic's official code-review plugin. We did the same. For a while the check was green and Claude posted "no findings" on every pull request. It had never reviewed a single line. The plugin starts its agents in the background, and the GitHub Action ends the run before they report back.

This is the setup we replaced it with on one of our Laravel projects. It takes about 15 minutes, and in a test it found all three bugs we planted. The details on the plugin problem, and how to check whether your own setup is affected, are at the end.

#What you need

  • A Claude Pro or Max subscription
  • Claude Code installed locally
  • Admin access to the GitHub repository

#Step 1: Install the Claude GitHub app

Install the Claude GitHub app on your repository. The action uses it to post comments as "claude" instead of your own account.

#Step 2: Create a subscription token

Run this locally and log in with your Claude account:

 1claude setup-token

It prints a long-lived OAuth token. Store it as a repository secret:

 1gh secret set CLAUDE_CODE_OAUTH_TOKEN

Paste the token when asked. That is the whole "API key" part: the action authenticates with this token, and usage counts against your plan.

The token belongs to the subscription of whoever ran claude setup-token. That is fine for your own repositories. For a team, where reviews should not depend on one person's plan, the official docs recommend an API key instead.

Shortcut: /install-github-app inside Claude Code walks you through steps 1 and 2 and creates a workflow file. Replace that workflow with the one below.

#Step 3: Add the workflow

Create .github/workflows/claude-review.yml:

 1name: Claude Review
 2
 3on:
 4  pull_request:
 5    types: [opened, ready_for_review]
 6
 7jobs:
 8  review:
 9    if: github.event.pull_request.draft == false
10    runs-on: ubuntu-latest
11    timeout-minutes: 30
12    permissions:
13      contents: read
14      pull-requests: write
15      issues: read
16      actions: read
17      id-token: write
18    steps:
19      - uses: actions/checkout@v7
20        with:
21          fetch-depth: 1
22
23      - uses: anthropics/claude-code-action@v1
24        with:
25          claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
26          prompt: |
27            REPO: ${{ github.repository }}
28            PR NUMBER: ${{ github.event.pull_request.number }}
29
30            Review this pull request yourself and completely. Do not start subagents
31            and do not wait for anything: the run ends as soon as you answer.
32
33            1. Read title and description with `gh pr view` and the full diff with
34               `gh pr diff`. You may read files in the checkout for context.
35            2. Read the project rules in `.ai/guidelines/`.
36            3. Only report high-confidence findings:
37               - bugs: code that will definitely fail, throw or compute wrong results
38               - security issues in the changed code
39               - clear violations of a rule in `.ai/guidelines/` you can quote
40               Do not report style, taste, guesses or issues that existed before.
41            4. Verify every finding against the code again. If unsure, drop it.
42            5. Post each finding as an inline comment with
43               `mcp__github_inline_comment__create_inline_comment` and `confirmed: true`.
44            6. Always finish with exactly one `gh pr comment`, also without findings:
45               a `## Code review` heading, one sentence per finding or "No findings.",
46               and one line on what you checked.
47          claude_args: |
48            --model opus
49            --allowedTools "Bash(gh pr view:*),Bash(gh pr diff:*),Bash(gh pr comment:*),mcp__github_inline_comment__create_inline_comment"

Point step 2 of the prompt at wherever your project rules live. We use .ai/guidelines/ because our CLAUDE.md is generated by Laravel Boost and not committed.

Commit the workflow to your default branch and open a pull request. One thing that cost us a test round: claude-code-action only runs a review workflow whose file is identical to the one on the default branch. A pull request that changes the workflow skips the review with "Workflow validation failed", so you can only test workflow changes after merging them.

#Why the prompt looks like this

  • "Do not start subagents" and no Agent in --allowedTools. Everything has to happen in the main loop, because that is the only thing the action waits for. More on that below.
  • Opus instead of the default model. One strong pass does the whole review. It takes about 30 seconds.
  • Only high-confidence findings. A review bot that comments on style gets ignored within a week. Bugs, security issues and quotable rule violations are worth an interruption.
  • Rules from the source, not from a generated CLAUDE.md. The action restores sensitive paths like CLAUDE.md from the base branch before Claude starts, so you cannot rely on a file generated in an earlier step.
  • Always a comment. The summary says what was checked. A silent green check is not a review.

#Does it actually find bugs?

We tested it with a pull request containing three planted bugs, disguised as a harmless refactoring:

  • a refund that was added to the price instead of subtracted
  • a variable renamed in one place but not in the other, so it was undefined
  • rand() instead of random_int() when generating a password

The review found all three. Each finding got an inline comment with a short explanation and a suggestion block with the correct code. The refund bug came with a worked example (100 minus 30 refunded now resulted in 130), and the rand() change was flagged as a security issue. There were no false positives.

The numbers for that run: 30 seconds, 9 turns, zero denied tool calls. The action reported about $0.16 in API-equivalent cost. With a subscription token that is not billed, it counts against your plan's usage limits instead. Keep in mind that those limits are shared with your own Claude Code sessions.

#Why not the official code-review plugin?

Most guides point you to Anthropic's code-review plugin:

 1- uses: anthropics/claude-code-action@v1
 2  with:
 3    claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
 4    plugin_marketplaces: "https://github.com/anthropics/claude-code.git"
 5    plugins: "code-review@claude-code-plugins"
 6    prompt: "/code-review:code-review --comment ${{ github.repository }}/pull/${{ github.event.pull_request.number }}"

On paper the plugin is great: four reviewer agents in parallel, two of them Opus agents hunting bugs, and a validation agent for every finding. We ran it for a while. The check was green on every pull request, and Claude posted "No findings."

Then a pull request with 24 changed files got the same comment after 20 seconds. A real run of that plugin takes several minutes. Once we lined up all past runs, the pattern was obvious:

  • Every run ended after 4 to 37 seconds.
  • The result showed "is_error": false, so the check was always green.
  • modelUsage only ever listed one model. The plugin's agents never ran.

With show_full_output: true (private repositories only, the log then contains your code) the final message was refreshingly honest:

I reviewed the diff myself and did not start any subagents. [...] I did not go through the test files line by line.

And then it posted "No findings" anyway.

#The root cause

  1. Subagents run in the background by default. Since Claude Code 2.1.198 the Agent tool launches subagents asynchronously, and the main agent ends its turn to wait for them.
  2. The action stops at the first result. In an interactive session the background agents would report back. In the action, the job is already gone. See claude-code-action#1852 and claude-code-action#1646.
  3. Newer models route around it. With recent versions the model often skips the agents entirely, skims the diff and still posts the plugin's "no issues found" summary, reported in claude-code#100401.

There are more reports with the same signature, for example claude-code#85275 and claude-code-action#1515. Prompt workarounds like "wait for your agents" do not fix it reliably, and at the time of writing there is no official fix. Anthropic's own solutions guide for the action does not use the plugin either. It uses a plain review prompt, like the one above.

#Check your existing setup

If you already run the plugin in GitHub Actions:

  1. Open a run of your review job and find the "type": "result" block in the log.
  2. Look at duration_ms and modelUsage. A few seconds with only one model listed means the agents never ran.
  3. For details, set show_full_output: true temporarily and search the transcript for "Async agent launched" or "did not start any subagents".

#Wrap-up

With a Claude subscription, a token secret and one workflow file, every pull request gets a real review in about 30 seconds. Skip the plugin in CI for now: it works well locally, where Claude Code waits for background agents, but in GitHub Actions it produces green checks without reviews.

If you are setting up AI-assisted reviews or CI for a Laravel project and want a second pair of eyes, get in touch.