Skip to content
Skip to main content
A row of identical wooden matches on a bone-white studio surface, six already burnt to black stubs, one mid-flame, the rest unused — a metaphor for every Claude Code GitHub Actions run starting cold and burning a fresh set of tokens
8 min readBy Carlos Aragon

Claude Code GitHub Actions Cost: The Real Math

Claude Code in GitHub Actions bills you on two separate lines: runner minutes, at $0.006/minon a standard Linux 2-core runner, and Claude tokens. The minutes are rounding error. The tokens are the bill — and the reason CI tokens cost more than the same work on your laptop is that a fresh runner never hits the prompt cache. Every run re-sends your system prompt, your tool definitions and all of CLAUDE.md at full input price before it reads one line of the diff. Which means the unit of cost is the run, not the diff. That one sentence is worth more than any pricing table.

Two Bills, and Only One of Them Matters

Anthropic's docs are upfront about this: each run consumes GitHub Actions minutes and Claude API tokens, billed by two different companies. People fixate on the wrong one.

LineRate10-min review
Linux 2-core runner$0.006 / min$0.06
Windows runner~1.67x Linux$0.10
macOS runner~10x Linux$0.62
Claude tokens (Sonnet 5)$2 / $10 per MTok~$0.30–$0.80

Public repos get standard runners free with no cap. Private repos get 2,000 included minutes a month on Free, 3,000 on Team, 50,000 on Enterprise Cloud. Unless you are running Claude on macOS runners — don't — the minutes never show up on a budget review. Everything below is about the bottom row.

Every CI Run Starts Cold. That's the Whole Story.

On your laptop, Claude Code is cheap because of prompt caching. The cached prefix lives an hour on a subscription and five minutes on an API key, so a session that's been open all afternoon reads most of its input back at a tenth of the input rate. Run /usagemid-session and you'll see a line like 91% of input tokens from cache. That is the number doing all the work.

A GitHub Actions runner is destroyed when the job ends. Run two shares nothing with run one. So every CI run pays, at full uncached input price:

  • the system prompt and the full tool definitions
  • the entire contents of CLAUDE.md, which the agent reads on every single run
  • the diff, plus every file it opens to understand the diff

Call that the cold-start floor. Here's the part people miss: that floor is charged identically whether the PR rewrote four hundred lines or fixed one typo in a comment. There is no such thing as a cheap run. There are only fewer runs.

This is also why the docs' bland advice to “keep your CLAUDE.mdconcise” has actual teeth in CI. On your laptop a bloated memory file is a one-time cache write you amortize over an afternoon. In CI it is uncached input, every run, forever. If your project memory file has grown past a couple hundred lines, move the workflow detail into skills that load on demand.

What One Review Actually Costs

Let's do the arithmetic on published Claude Sonnet 5 rates — $2 per million input, $10 per million output, cache reads at $0.20, five-minute cache writes at $2.50. Within a single run the cache does work: turns land seconds apart, so turn two onward reads the prefix back. Across runs it does nothing.

Take a mid-size PR review: a ~30K-token stable prefix (system + tools + CLAUDE.md), ~40K of diff and file reads accumulated over eight turns, ~15K of output.

cold prefix write  30K x $2.50 = $0.075  ← paid every run
cache reads (7 turns) 350K x $0.20 = $0.070
fresh input       40K x $2.00 = $0.080
output            15K x $10.00 = $0.150
                                → ~$0.38 / review

Under forty cents.Which is exactly why “how much does one review cost” is the wrong question. Anthropic's own published figure for enterprise Claude Code deployments is roughly $13 per developer per active dayand $150–$250 per developer per month, with 90% of users under $30 a day. Nobody gets there forty cents at a time by reviewing thoughtfully. They get there by running a lot.

The Multiplier Nobody Budgets: synchronize

The review workflow triggers on pull_request: types: [opened, synchronize]. synchronize fires on every push to the branch. A PR that takes twelve pushes to go green runs twelve full reviews — each paying the same cold-start floor — and eleven of those pushes were a lint fix, a rebase, and a typo in a test name.

Twelve runs at $0.38 is $4.56 for one pull request. Five engineers doing that eight times a month is a little over $180. That is the entire Claude Code CI bill, and none of it came from the reviews you wanted.

The action does give you some free defense: it skips draft PRs, skips closed ones, skips PRs it judges trivial or automated, and rejects bot actors unless you list them in allowed_bots — that last one specifically so bots can't trigger Claude in a loop. Useful, but none of it stops the twelve-push case. That one is on you.

API Key or Subscription Token? This Decides Who Pays

The action takes either anthropic_api_key or claude_code_oauth_token. They look interchangeable in the YAML. They are not.

An API key bills tokens to the Claude Console, where a workspace spend limit is a real ceiling and per-user reporting exists. An OAuth token from claude setup-tokenbills to the subscription of whoever ran the command — and draws on the same rolling five-hour and weekly windows as that person's interactive sessions and their Claude chat. CI does not get its own quota.

Picture the failure: someone opens a noisy PR, twelve reviews fire, and the developer who set up the workflow four months ago gets “you've hit your session limit” in their editor with no idea why. Anthropic's own org guidance says to use an API key rather than an OAuth token for a secret shared across repos, precisely because the token is tied to one person. If you'd rather store no long-lived secret at all, workload identity federation swaps the workflow's OIDC token for API access — set anthropic_federation_rule_id and grant id-token: write. Same pattern I use for service-token auth on n8n webhooks: stop storing the credential, start exchanging an identity.

The Workflow the Installer Hands You Has No Cost Cap

I went looking in my own repos while writing this. In n8n-mcp-server there are two workflow files I generated with /install-github-app back in the @beta days and never touched again. They still pin anthropics/claude-code-action@beta, still use the removed direct_prompt input, still pass model as a top-level key instead of through claude_args. And between the two of them: no --max-turns, no timeout-minutes, no concurrency block.

Those files have cost me exactly $0 — because they were never merged to the default branch, so they never fired once. That's luck, not discipline, and it's the honest version of this anecdote. Had they merged, the review workflow would have run on every push to every PR for a year with no ceiling of any kind. The generated workflow is a working example, not a safe one.

Here is the review job with the four lines that should have been there from day one:

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

concurrency:                                      # 1. cancel superseded runs
  group: claude-review-${{ github.event.pull_request.number }}
  cancel-in-progress: true

jobs:
  review:
    runs-on: ubuntu-latest
    timeout-minutes: 12                           # 2. hard wall-clock cap
    permissions:
      contents: read
      pull-requests: read
      id-token: write
    steps:
      - uses: actions/checkout@v6
        with:
          fetch-depth: 1                          # never 0 unless you need history
      - uses: anthropics/claude-code-action@v1
        with:
          anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
          prompt: "/code-review:code-review --comment ..."
          claude_args: |
            --max-turns 10                        # 3. stop the loop
            --model claude-sonnet-5               # 4. pin the tier

concurrency and timeout-minutesare plain GitHub features that cost nothing to add and are the two that actually save money — the first kills the review still chewing on the commit you just replaced, the second stops a wedged job billing until GitHub's six-hour default reaps it. --max-turns is the one Anthropic explicitly recommends, and --modelmatters because without it the action uses the Claude Code default, which is not a rate you picked. If you're weighing the tiers, I went through that in the Opus 5.5 migration post.

One more line item worth knowing about before you get clever with automation prompts: subagents and agent teams multiply this. Anthropic puts agent teams at roughly 7x the tokens of a standard session, because each teammate runs its own context window — and in CI, each of those windows is also cold. I broke that down in subagent token cost. A scheduled workflow that fans out is not a review job. Budget it separately, the same way you'd budget any agent running on autopilot.

Common Questions

How much does Claude Code cost per pull request in GitHub Actions?

Roughly $0.30–$0.80 of Sonnet 5 tokens plus a few cents of Linux runner time, on the token mix above. Treat that as arithmetic on published rates, not a measurement of your repo — run your own. The number that predicts your bill is how many runs fire per PR, not what one run costs.

Why is Claude Code more expensive in CI than on my laptop?

Cold cache. Interactive sessions keep a warm prefix for an hour on a subscription, five minutes on an API key. A runner is destroyed after every job, so nothing carries over — each run re-reads the system prompt, the tools and all of CLAUDE.md at full input price. Same caching mechanics I covered in prompt caching cost savings, just with the cache permanently switched off.

Does the OAuth token eat my personal Claude limits?

Yes. claude setup-token issues a token bound to your subscription, and CI runs draw on the same rolling five-hour and weekly windows as your own sessions and Claude chat. There is no separate CI quota. Use an API key with a Console workspace spend limit for anything shared.

Do GitHub Actions minutes matter here?

Almost never on Linux — $0.006/min, free and uncapped on public repos. They do matter on macOS runners at roughly 10x. If you're running a Claude review on macOS, that's the cheapest fix on this page.

What I'd Actually Do

Ship it on an API key in a dedicated Console workspace with a spend limit, on Linux runners, with the concurrency block and the timeout in place before the first PR. Pin Sonnet 5 and cap turns. Drop synchronize for the first month and see whether reviewing on open and ready_for_reviewis enough — for most teams it is, because the reviews that matter happen when a human decides the branch is ready, not when CI goes red on a lint rule.

Then go look at your Console spend after two weeks instead of guessing. Every number in this post is a published rate multiplied by an assumed token mix. Yours will be different, and the only way to find out by how much is to measure it — which is the same advice I give about every other part of a production Claude Code setup.

Putting an AI Agent in Your Pipeline?

The workflow file takes ten minutes. Working out what it will cost at 200 PRs a month, and capping it before finance asks, takes an afternoon. I build and audit these for clients — send me your setup and I'll tell you where the bill is hiding.

Action inputs, claude_argsflags, authentication modes and the cost guidance verified 24 September 2026 against Anthropic's Claude Code GitHub Actions docs and cost management guide; runner rates and included minutes from GitHub's Actions billing docs. The per-review figure is arithmetic on published Sonnet 5 rates for a stated token mix — not a measurement of your repository. Measure your own before you budget on it.

Related Posts