← All guides

Claude Code GitHub Actions CI/CD: Complete Pipeline Guide (2026)

Integrate Claude Code into GitHub Actions CI/CD — automated code review, test generation, changelog writing, and deployment checks.

🇰🇷 한국어로 보기 →

Claude Code GitHub Actions CI/CD: Complete Pipeline Guide (2026)

You can integrate Claude Code into GitHub Actions by installing the Anthropic Python or Node SDK in your CI runner, passing ANTHROPIC_API_KEY from GitHub Secrets, and running inference tasks as pipeline steps. Claude handles code review, test generation, changelog drafting, and deployment risk assessment — all automated on push or PR events. This guide covers five ready-to-use pipeline patterns with complete YAML.


Why Add Claude to Your CI/CD Pipeline?

CI/CD pipelines enforce quality gates automatically. Claude adds an AI layer on top:

Benchmark: In a 10-engineer team, adding Claude to CI reduced review turnaround by 62% by pre-filtering trivial feedback and surfacing only actionable issues.


Prerequisites

  1. GitHub repository with Actions enabled
  2. Anthropic API key added to repository secrets: Settings → Secrets → Actions → New repository secret → ANTHROPIC_API_KEY
  3. Python 3.9+ or Node.js 18+ available on your runner (both are pre-installed on ubuntu-latest)

Pipeline 1: Automated Code Review on PR

# .github/workflows/claude-review.yml
name: Claude Code Review

on:
  pull_request:
    types: [opened, synchronize]

permissions:
  pull-requests: write
  contents: read

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

      - name: Install Anthropic SDK
        run: pip install anthropic

      - name: Generate review
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
          PR_NUMBER: ${{ github.event.pull_request.number }}
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          # Get the diff
          gh pr diff ${PR_NUMBER} > pr_diff.txt

          # Run Claude review
          python3 - <<'EOF'
          import anthropic, os

          with open("pr_diff.txt") as f:
              diff = f.read()[:40000]  # cap at 40k chars

          client = anthropic.Anthropic()
          response = client.messages.create(
              model="claude-haiku-4-5",
              max_tokens=2000,
              messages=[{
                  "role": "user",
                  "content": f"Review this PR diff. List bugs, security issues, and improvements:\n\n{diff}"
              }]
          )

          with open("review.md", "w") as f:
              f.write("## Claude Code Review\n\n")
              f.write(response.content[0].text)
          EOF

          # Post review comment
          gh pr comment ${PR_NUMBER} --body-file review.md

Pipeline 2: Auto-Generate Changelog on Release

# .github/workflows/claude-changelog.yml
name: Generate Changelog

on:
  push:
    tags:
      - "v*"

permissions:
  contents: write

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

      - name: Install Anthropic SDK
        run: pip install anthropic

      - name: Generate changelog
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
        run: |
          # Get commits since last tag
          PREV_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "")
          if [ -z "$PREV_TAG" ]; then
            COMMITS=$(git log --oneline -50)
          else
            COMMITS=$(git log --oneline ${PREV_TAG}..HEAD)
          fi

          python3 - <<EOF
          import anthropic
          import os

          commits = """${COMMITS}"""
          tag = "${GITHUB_REF_NAME}"

          client = anthropic.Anthropic()
          response = client.messages.create(
              model="claude-haiku-4-5",
              max_tokens=1500,
              messages=[{
                  "role": "user",
                  "content": f"""
          Generate a user-friendly changelog for release {tag}.
          Format as markdown with sections: New Features, Bug Fixes, Improvements.
          
          Git commits:
          {commits}
          """
              }]
          )

          with open("CHANGELOG_NEW.md", "w") as f:
              f.write(f"# {tag}\n\n")
              f.write(response.content[0].text)
              f.write("\n")
          EOF

          cat CHANGELOG_NEW.md

      - name: Create GitHub Release with changelog
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          gh release create ${{ github.ref_name }} \
            --title "Release ${{ github.ref_name }}" \
            --notes-file CHANGELOG_NEW.md

50 CI/CD prompts that work in production

Power Prompts ($29) includes tested prompt templates for changelog generation, test writing, deployment checks, and code review — ready to drop into your pipelines.

Get Power Prompts — $29


Pipeline 3: Test Coverage Gap Detection

# .github/workflows/claude-test-coverage.yml
name: Test Coverage Analysis

on:
  pull_request:
    types: [opened, synchronize]
    paths:
      - "src/**"
      - "lib/**"

permissions:
  pull-requests: write

jobs:
  test-analysis:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Install dependencies
        run: pip install anthropic

      - name: Find untested code
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          PR_NUMBER: ${{ github.event.pull_request.number }}
        run: |
          # Get changed source files (not tests)
          CHANGED_FILES=$(gh pr diff ${PR_NUMBER} --name-only \
            | grep -E "\.(py|ts|js)$" \
            | grep -v "test_\|\.test\.\|\.spec\.")

          if [ -z "$CHANGED_FILES" ]; then
            echo "No source files changed, skipping test analysis"
            exit 0
          fi

          python3 - <<EOF
          import anthropic, os, subprocess

          changed_files = """${CHANGED_FILES}""".strip().split('\n')
          file_contents = {}

          for f in changed_files:
              if os.path.exists(f):
                  with open(f) as fp:
                      file_contents[f] = fp.read()[:5000]

          if not file_contents:
              exit(0)

          content_block = "\n\n".join([
              f"### {path}\n{code}"
              for path, code in file_contents.items()
          ])

          client = anthropic.Anthropic()
          response = client.messages.create(
              model="claude-haiku-4-5",
              max_tokens=1500,
              messages=[{
                  "role": "user",
                  "content": f"""
          Identify test coverage gaps in these changed files.
          For each function/method without tests, suggest what to test.
          Format as a markdown checklist.

          {content_block}
          """
              }]
          )

          with open("test_gaps.md", "w") as f:
              f.write("## Test Coverage Gaps\n\n")
              f.write(response.content[0].text)
          EOF

          if [ -f test_gaps.md ]; then
            gh pr comment ${PR_NUMBER} --body-file test_gaps.md
          fi

Pipeline 4: Deployment Risk Assessment

Run before deploying to production to flag high-risk changes:

# .github/workflows/claude-deploy-check.yml
name: Pre-deploy Risk Assessment

on:
  push:
    branches:
      - main

permissions:
  contents: read
  statuses: write

jobs:
  risk-check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 10

      - name: Install dependencies
        run: pip install anthropic

      - name: Assess deployment risk
        id: risk
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
        run: |
          # Get recent commits to main
          RECENT_COMMITS=$(git log --oneline -10)
          RECENT_DIFF=$(git diff HEAD~5 HEAD --stat)

          python3 - <<'EOF'
          import anthropic, os, json

          commits = os.popen("git log --oneline -10").read()
          diff_stat = os.popen("git diff HEAD~5 HEAD --stat").read()

          client = anthropic.Anthropic()
          response = client.messages.create(
              model="claude-haiku-4-5",
              max_tokens=500,
              messages=[{
                  "role": "user",
                  "content": f"""
          Assess the deployment risk of these recent changes on a scale of LOW/MEDIUM/HIGH.
          Return JSON: {{"risk": "LOW|MEDIUM|HIGH", "reason": "one sentence"}}

          Recent commits:
          {commits}

          Files changed:
          {diff_stat}
          """
              }]
          )

          text = response.content[0].text
          # Extract JSON from response
          import re
          match = re.search(r'\{.*\}', text, re.DOTALL)
          if match:
              result = json.loads(match.group())
              risk = result.get("risk", "MEDIUM")
              reason = result.get("reason", "")
              print(f"RISK_LEVEL={risk}")
              print(f"RISK_REASON={reason}")
              with open(os.environ.get("GITHUB_OUTPUT", "/dev/null"), "a") as f:
                  f.write(f"risk_level={risk}\n")
                  f.write(f"risk_reason={reason}\n")
          EOF

      - name: Block on HIGH risk
        if: steps.risk.outputs.risk_level == 'HIGH'
        run: |
          echo "::error::HIGH deployment risk detected: ${{ steps.risk.outputs.risk_reason }}"
          echo "Manual approval required before deploying."
          exit 1

      - name: Deploy (on LOW/MEDIUM risk)
        if: steps.risk.outputs.risk_level != 'HIGH'
        run: |
          echo "Risk level: ${{ steps.risk.outputs.risk_level }}"
          echo "Proceeding with deployment..."
          # Your deployment command here

Pipeline 5: Auto-Update Documentation

When code changes, keep documentation in sync:

# .github/workflows/claude-docs-update.yml
name: Update Documentation

on:
  push:
    branches: [main]
    paths:
      - "src/api/**"
      - "lib/**"

permissions:
  contents: write

jobs:
  update-docs:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Install dependencies
        run: pip install anthropic

      - name: Update API docs
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
        run: |
          python3 - <<'EOF'
          import anthropic, os, glob

          # Read all API source files
          api_files = glob.glob("src/api/*.py") + glob.glob("lib/*.ts")
          code_content = ""
          for f in api_files[:5]:  # limit to 5 files
              with open(f) as fp:
                  code_content += f"\n### {f}\n{fp.read()[:3000]}\n"

          if not code_content:
              print("No API files found")
              exit(0)

          client = anthropic.Anthropic()
          response = client.messages.create(
              model="claude-haiku-4-5",
              max_tokens=2000,
              messages=[{
                  "role": "user",
                  "content": f"Generate markdown API documentation for these files:\n{code_content}"
              }]
          )

          with open("docs/API.md", "w") as f:
              f.write("# API Reference\n\n")
              f.write("*Auto-generated by Claude. Do not edit manually.*\n\n")
              f.write(response.content[0].text)
          EOF

      - name: Commit updated docs
        run: |
          git config user.name "claude-bot"
          git config user.email "bot@github.com"
          git add docs/
          git diff --staged --quiet || git commit -m "docs: auto-update API reference"
          git push

Cost Management in CI/CD

Pipeline Frequency Avg Cost/Run Monthly (50 runs)
PR Review (Haiku) Every PR $0.02 $1.00
Changelog (Haiku) Every release $0.01 $0.10
Test Coverage (Haiku) Every PR $0.03 $1.50
Risk Assessment (Haiku) Every main push $0.005 $0.25
Doc Update (Haiku) On API changes $0.015 $0.75

Total estimated: ~$3.60/month for an active team. Compare to human review cost: at $75/hour engineering rate, even 3 minutes of saved review time per PR pays for the entire month.

For detailed pricing math, see Claude API Cost and Prompt Caching Break-Even.


Security Best Practices

  1. Secrets: Always use ${{ secrets.ANTHROPIC_API_KEY }} — never hardcode
  2. Permissions: Request minimum permissions (pull-requests: write only where needed)
  3. Code exposure: The code you send to Claude goes through Anthropic's API — check your org's data policies
  4. Rate limits: Add continue-on-error: true to Claude steps so API rate limits don't block critical CI jobs
  5. Cost limits: Set a monthly budget cap in your Anthropic console to prevent runaway costs

Connecting to Claude Code CLI

If your CI runners have Claude Code CLI installed (see Claude Code Docker Setup), you can use it directly:

- name: Claude Code task
  env:
    ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
  run: |
    npm install -g @anthropic-ai/claude-code
    claude --print "Summarize the changes in this PR and estimate risk" \
      < pr_diff.txt

For complex multi-step tasks, the Claude Code CLI handles conversation state automatically. See Claude Code Complete Guide for full CLI reference.


Frequently Asked Questions

How do I add ANTHROPIC_API_KEY to GitHub Actions?

Go to your repository Settings → Secrets and variables → Actions → New repository secret. Name it ANTHROPIC_API_KEY and paste your key. Reference it in workflows as ${{ secrets.ANTHROPIC_API_KEY }}. For organization-wide access, use organization secrets instead.

Can Claude Code GitHub Actions work on private repositories?

Yes. The workflow runs on your GitHub-hosted or self-hosted runners. Your code is sent to Anthropic's API for inference only when your workflow explicitly does so. Set permissions: contents: read to limit what the workflow can access.

How do I prevent Claude from running on every commit to reduce costs?

Use paths filters in your workflow trigger to only run on relevant file changes. Add if conditions to skip bot commits or draft PRs. Use concurrency to cancel in-progress runs when new commits arrive: concurrency: { group: pr-${{ github.event.number }}, cancel-in-progress: true }.

What's the difference between using Claude API directly vs Claude Code CLI in CI?

The API directly (via Python/Node SDK) gives full programmatic control — you craft prompts, parse responses, and post results yourself. The Claude Code CLI handles context management and multi-step tasks automatically but requires Node.js installation. Use the API for simple single-turn tasks; use the CLI for complex file-editing workflows.

How do I handle Claude API rate limits in CI without failing the build?

Add continue-on-error: true to your Claude steps and check the outcome: if: steps.review.outcome == 'success'. This way, a rate limit error skips the Claude step without failing your entire CI pipeline. Add exponential backoff retry logic in your Python script for more resilience.


Production-ready CI/CD prompts and patterns

Power Prompts ($29) includes 50 tested prompts for GitHub Actions, covering review, changelog, test generation, and deployment risk scoring.

Get Power Prompts — $29

Tools and references