How-to

Claude Code + GitHub Actions: A CI/CD Integration Guide

How to wire Claude Code into your GitHub Actions pipeline — from automated PR review to scheduled maintenance jobs.

O
OpenHelm Team· Engineering
··10 min read
Claude Code + GitHub Actions: A CI/CD Integration Guide

There's a natural question that arises once you've been using Claude Code for a few weeks: if it can handle a pull request's worth of changes on its own, why is it sitting outside your CI pipeline?

The honest answer is that most CI pipelines were built before AI coding agents existed. GitHub Actions workflows are designed to run deterministic checks — tests pass or they fail, linters report violations, deployments trigger on merge. They weren't built to incorporate an agent that can read, reason, and change code during the run itself.

That's changing. Claude Code GitHub Actions integration isn't especially complex, but the patterns for doing it well aren't obvious. This guide covers the practical approach: what works, what to watch out for, and how to structure goals that function reliably in a CI context.

What CI Integration Actually Means

A Claude Code GitHub Actions integration can mean different things depending on what you want. Three distinct use cases are worth separating:

Automated code review. Claude Code reads the diff on a pull request and comments on it — flagging potential issues, suggesting improvements, or checking for violations of conventions you've specified.

Automated remediation. Claude Code doesn't just comment; it makes changes. A CI job that runs Claude Code with a goal like "fix any linting errors in this PR's diff" and commits the result back to the branch.

Scheduled maintenance jobs. Recurring GitHub Actions workflows that fire on a cron schedule and use Claude Code to handle ongoing housekeeping: updating dependencies, regenerating documentation, backfilling tests.

The patterns for each are slightly different, but the underlying setup is the same.

Basic Setup: Running Claude Code in a GitHub Action

Before getting into specific workflows, a few prerequisites worth stating clearly.

Anthropic API key in GitHub Secrets. Claude Code uses the Anthropic API. Add your key as ANTHROPIC_API_KEY in your repository's Settings → Secrets and variables → Actions.

Claude Code CLI headless mode. The claude CLI supports a --print flag for non-interactive headless use. That's what you need in CI contexts — no TTY, no interactive session.

Permissions. If Claude Code will commit changes back to the repository, your workflow needs contents: write permission.

A minimal workflow that runs Claude Code on pull requests looks like this:

name: Claude Code Review
on:
  pull_request:
    types: [opened, synchronize]

permissions:
  contents: read
  pull-requests: write

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

      - name: Install Claude Code
        run: npm install -g @anthropic-ai/claude-code

      - name: Run code review
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
        run: |
          DIFF=$(git diff origin/${{ github.base_ref }}...HEAD)
          claude --print "Review the following diff for obvious bugs, missing error handling, or potential security issues. Output a concise list of findings, or 'No issues found' if the diff looks clean. Diff: $DIFF"

This gives you a working baseline. What makes it production-grade is what you build around it.

Writing Goals That Work in CI

The most common failure point with Claude Code GitHub Actions integration isn't the YAML — it's the prompt.

Goals that work well for interactive Claude Code sessions often fail in CI because they rely on implicit context. When you're at the terminal, you can clarify ambiguity on the fly. In a CI job at 3am, there's no one there to do that.

A few rules for CI-safe goals:

Make context explicit. Don't assume Claude Code knows your project's conventions. Include them. "Follow the existing pattern in src/handlers/ for error handling" is actionable. "Handle errors properly" is not.

Specify the scope precisely. "Review the PR diff" is fine for a code review job. "Review the codebase" will trigger a long, expensive run over everything. In CI, loose scoping costs money and time.

Set a hard exit condition. "Output exactly 5 bullet points maximum, then stop" prevents runaway generation. More critical for remediation jobs than review jobs, but worth applying everywhere.

Test the prompt locally first. GitHub Actions CI minutes are forgiving, but testing a prompt locally with claude --print "..." before wiring it into CI saves a lot of iteration cycles.

PR Remediation: Committing Changes Back

A step up from code review is having Claude Code actually fix things. The workflow pattern is a bit more involved because it needs to commit back to the branch:

name: Auto-fix linting
on:
  pull_request:
    types: [opened, synchronize]

permissions:
  contents: write

jobs:
  autofix:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ github.head_ref }}
          token: ${{ secrets.GITHUB_TOKEN }}

      - uses: actions/setup-node@v4
        with:
          node-version: '20'

      - run: npm ci

      - name: Install Claude Code
        run: npm install -g @anthropic-ai/claude-code

      - name: Fix linting errors
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
        run: |
          claude --print "Run `npm run lint -- --fix` on this project, then check if any lint errors remain that couldn't be auto-fixed and list them. If everything is clean, output 'All clean.'"

      - name: Commit changes
        run: |
          git config user.name "claude-bot"
          git config user.email "claude@ci.bot"
          git add -A
          git diff --staged --quiet || git commit -m "chore: auto-fix lint errors [skip ci]"
          git push

The [skip ci] in the commit message prevents the workflow from triggering itself in a loop. That's important when a workflow commits back to the branch that triggered it.

Scheduled Maintenance Workflows

The third pattern — recurring maintenance jobs — is often the most valuable. These are the jobs where "this has been deferred" is the real problem, and automation is the structural fix.

Some examples that work reliably in practice:

JobScheduleGoal pattern
Dependency updatesWeekly, Sunday 0200Upgrade minor/patch versions, run tests, note failures
Doc freshness checkMonthlyReview /docs files not touched in 6 months, flag outdated API references
Dead code scanBi-weeklyFind exported functions with no callers, list candidates for removal
Test coverage gapsWeeklyFind files with 0% test coverage, write smoke tests for top 5 by import count

For these, the workflow uses schedule: rather than pull_request::

on:
  schedule:
    - cron: '0 2 * * 0'  # Sunday at 2am UTC

The practical limit of GitHub Actions for this use case is that CI minutes are expensive at scale, and there's no run history beyond what Actions logs provide. For teams running more than a handful of scheduled Claude Code jobs, a dedicated scheduler like OpenHelm alongside GitHub Actions tends to be a cleaner architecture: use Actions for pipeline-triggered checks, use OpenHelm for persistent background maintenance jobs that need silence detection and structured run history.

Handling Rate Limits and Costs

Two operational concerns come up reliably with Claude Code GitHub Actions integration at any meaningful scale.

Rate limits. If you're running Claude Code on every PR across an active team, you'll hit Anthropic API rate limits. The mitigation is a combination of path filtering (only trigger on changes to relevant files), concurrency limits in the workflow, and batching where possible. A review job that only fires when src/**/*.ts changes is cheaper and faster than one that fires on every commit.

Cost visibility. Each CI run that calls Claude Code has a direct API cost. Setting billing alerts in the Anthropic Console catches runaway jobs before they appear on a monthly statement. A CI job that hits a 10-minute silence loop costs significantly more than you'd expect — typically 4–8× a normal run.

"The CI integration made our PR review process genuinely faster. The key was writing tight, specific prompts for each job type rather than one generic review prompt." — Developer in the OpenHelm community Slack, March 2026

FAQs

Can I use Claude Code in GitHub Actions without storing my API key in GitHub?

You can use OIDC to federate credentials if your setup supports it, but for most teams a GitHub Secret with the Anthropic API key is the practical approach. Treat it with the same care as any other production API credential — rotate it periodically, and use environment-level protection for production-triggered workflows.

How do I stop Claude Code from making changes I didn't intend?

Scope the goal tightly and use --print mode when you only want output, not file changes. For remediation jobs, review the diff before merging — the [skip ci] pattern gives you a chance to check the automated commit before it triggers downstream workflows.

What's the difference between using Claude Code in CI versus in OpenHelm?

GitHub Actions is the right layer for pipeline-triggered automation: code review on PRs, checks on push, post-merge hooks. OpenHelm handles persistent, scheduled background jobs that run on a schedule independent of git activity. The two complement each other rather than compete. The Claude Code Background Jobs guide covers the differences in execution model in more detail.

How do I debug a Claude Code CI job that's failing silently?

Add set -x to your shell steps for verbose output and pipe the Claude Code output to a log artefact. The --print flag outputs to stdout, so claude --print "..." 2>&1 | tee review-output.txt gives you a persistent artefact to inspect after the job completes.

More from the blog