Issue 00 · Autumn 2026日本語 · RSS
AgentKoji

Running Claude Code in CI: Costs and Traps

Claude Code GitHub Actions costs come from two places: API tokens and runner minutes. A worked estimate, a cache trap, and how to stop runaway jobs.

Running Claude Code in GitHub Actions costs you in two places: the Claude API (or your subscription) and GitHub Actions minutes. We estimated both with official rates, then list traps we hit and settings that stop runaway jobs. Plan choice is covered in What Claude Code Really Costs; this is about running it in CI.

Two meters

Per the docs, each run consumes Actions minutes on GitHub-hosted runners and API tokens driven by prompt/response length, task complexity and codebase size; with an OAuth token, runs use your subscription instead of API billing (https://code.claude.com/docs/en/github-actions, checked 2026-10-16).

GitHub’s rates (https://docs.github.com/en/billing/concepts/product-billing/github-actions, checked 2026-10-16):

ItemOfficial figure
Standard runners, public reposFree
Self-hosted runnersNo Actions charge
Private free minutes / monthFree 2,000; Pro 3,000; Team 3,000
Overage, Linux 2-core$0.006/min
Overage, macOS$0.062/min

A worked estimate

Run counts, minutes and tokens below are assumptions, not measurements. API rates: Sonnet 5.5 at $2/MTok input, $10/MTok output (https://platform.claude.com/docs/en/about-claude/pricing, checked 2026-10-16).

RUNS = 100                         # runs per month (assumed)
MIN_PER_RUN = 6                    # minutes per run (assumed)
IN_TOK, OUT_TOK = 300_000, 20_000  # tokens per run (assumed, no caching)
API: $80.00/month  ($0.80 per run)
Linux 2-core: 600 min x $0.006 = $3.60/month
macOS: 600 min x $0.062 = $37.20/month

Under these assumptions the API dominates. 600 Linux minutes fit in the Free plan’s 2,000. macOS costs about ten times Linux per minute, so don’t run jobs there unless they need it. The docs suggest specific @claude requests, --max-turns in claude_args, workflow timeouts, concurrency limits, and a short CLAUDE.md, which is read every run (same source).

Stop runaway jobs in config

on:
  issue_comment:
    types: [created]
concurrency:
  group: claude-${{ github.event.issue.number }}
  cancel-in-progress: false
jobs:
  claude:
    if: contains(github.event.comment.body, '@claude')
    runs-on: ubuntu-latest
    timeout-minutes: 15
    steps:
      - uses: actions/checkout@v6
      - uses: anthropics/claude-code-action@v1
        with:
          anthropic_api_key: ${{ secrets.DUMMY_ANTHROPIC_API_KEY }}
          claude_args: --max-turns 10

actionlint 1.7.12 passed it (2026-10-16). Making timeout-minutes a string fails with expecting a single ${{...}} expression or float number literal. Lint before you push. timeout-minutes caps runner time; --max-turns caps API work. Keep keys in GitHub Secrets, never in the repo (same source); for other leak paths see Keep Secrets Away from Claude Code.

What we hit on a self-hosted runner

To save minutes, we used an always-on machine as a self-hosted runner.

  1. Caching was a net loss. On a persistent runner the package store already sits in the runner’s home, so a plain install was fastest.
  2. Merging jobs halved the wait. Too many small jobs exceeded the runner’s concurrency. Grouping by workspace to stay under it cut wall time from 21–25 minutes to 10 min 56 s.
  3. A workflow overwrote a real key. A deploy step wrote its key over the machine’s own; the old private key was unrecoverable. Read what a workflow writes under HOME before running it on a shared machine.

We don’t use self-hosted runners for public repos; GitHub says they should almost never be used there, since anyone can open a pull request (https://docs.github.com/en/actions/reference/security/secure-use, checked 2026-10-16). For running an always-on machine safely, see Run an AI Agent 24/7 on a VPS.

Green CI isn’t proof

Agents treat “CI is green” as the goal. Tests that check nothing are still green; see Green Tests Prove Nothing.

The reverse case, passing locally but failing in CI, is covered in Passes Locally, Fails in CI.

Summary