Skip to main content

CI/CD Integration

Integrating Claude Code into your CI/CD pipeline lets you make automated PR reviews, code quality checks, and automatic documentation part of the pipeline itself.

Key use casesโ€‹

  • Automated PR reviews: Claude writes review comments when a PR is opened
  • Automatic issue resolution: mention Claude on an issue and it opens a fix PR
  • Automatic test generation: tests suggested automatically for new code
  • Release note automation: release notes generated from commit history
  • Code quality gates: block PRs that fail quality criteria

The official GitHub Actionโ€‹

Anthropic's anthropics/claude-code-action@v1 integrates Claude Code into GitHub Actions with minimal setup.

Quick start: PR reviewโ€‹

.github/workflows/claude-review.yml:

name: Claude Code Review

on:
pull_request:
types: [opened, synchronize, reopened]
issue_comment:
types: [created]

jobs:
claude-review:
if: |
github.event_name == 'pull_request' ||
(github.event_name == 'issue_comment' &&
contains(github.event.comment.body, '@claude'))
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
issues: write

steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}

That's all it takes โ€” mentioning @claude on a PR now triggers an automated review.

Key configuration parametersโ€‹

ParameterDescriptionRequired
anthropic_api_keyAnthropic API keyO*
github_tokenGitHub token (for API access)-
promptInstructions for Claude (text or a skill name)-
claude_argsClaude Code CLI arguments (--max-turns, --model, etc.)-
trigger_phraseMention trigger phrase (default: @claude)-
use_bedrockUse AWS Bedrock-
use_vertexUse Google Vertex AI-

* Not required when using Bedrock/Vertex

Beta โ†’ v1 migration

If you're upgrading from the beta: remove mode (now auto-detected), rename direct_prompt โ†’ prompt, move custom_instructions/max_turns/model into claude_args, and convert claude_env to the settings JSON format.

Custom prompt exampleโ€‹

- uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
prompt: |
Focus the code review on these criteria:
1. Security vulnerabilities (OWASP Top 10)
2. Potential performance bottlenecks
3. TypeScript type safety
4. Areas lacking test coverage
claude_args: "--model claude-sonnet-5"

Automatic issue resolutionโ€‹

Mention @claude on an issue to have it open a fix PR automatically:

name: Claude Issue Resolver

on:
issues:
types: [opened, assigned]
issue_comment:
types: [created]

jobs:
resolve:
if: |
(github.event_name == 'issue_comment' &&
contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'issues' &&
contains(github.event.issue.assignees.*.login, 'claude-bot'))
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
issues: write

steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
assignee_trigger: true

AWS Bedrock integrationโ€‹

- uses: anthropics/claude-code-action@v1
with:
use_bedrock: true
claude_args: "--model us.anthropic.claude-sonnet-5 --max-turns 10"
env:
AWS_REGION: us-west-2
Bedrock authentication

OIDC authentication (auto-refreshing temporary credentials) is recommended. Set up an IAM role with aws-actions/configure-aws-credentials@v4.

Google Vertex AI integrationโ€‹

- uses: anthropics/claude-code-action@v1
with:
use_vertex: true
claude_args: "--model claude-sonnet-5 --max-turns 10"
env:
ANTHROPIC_VERTEX_PROJECT_ID: ${{ steps.auth.outputs.project_id }}
CLOUD_ML_REGION: us-east5
Official Action vs custom workflow

The official Action handles PR context loading, issue integration, and comment posting automatically. Use the official Action for simple CI jobs; use a custom workflow (below) for heavily customized pipelines.

Custom workflowsโ€‹

These workflows use the Claude Code CLI directly instead of the official Action.

PR review (direct CLI)โ€‹

name: Claude Code Review (Custom)

on:
pull_request:
types: [opened, synchronize]

jobs:
review:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write

steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'

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

- name: Run Code Review
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
CHANGED_FILES=$(git diff --name-only origin/${{ github.base_ref }}...HEAD)

claude -p "Review the changes in the following files.
Check for bugs, security issues, performance problems, and code style.
Provide specific feedback for each file:
$CHANGED_FILES" \
--allowedTools "Read,Grep,Glob" > review.md

gh pr comment ${{ github.event.pull_request.number }} --body-file review.md

Automated release notesโ€‹

name: Release Notes

on:
push:
tags:
- 'v*'

jobs:
release-notes:
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: Generate Release Notes
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
PREV_TAG=$(git describe --tags --abbrev=0 HEAD~1)
COMMITS=$(git log $PREV_TAG..HEAD --oneline)

claude -p "Based on the following commit list,
write user-friendly release notes.
Group them into new features, bug fixes, and improvements:
$COMMITS" > release-notes.md

gh release edit ${{ github.ref_name }} --notes-file release-notes.md

GitLab CI integrationโ€‹

.gitlab-ci.yml:

stages:
- review

claude-review:
stage: review
image: node:20
script:
- npm install -g @anthropic-ai/claude-code
- CHANGED=$(git diff --name-only origin/main...HEAD)
- claude -p "Review this code: $CHANGED"
--allowedTools "Read,Grep,Glob" > review.md
- cat review.md
only:
- merge_requests
variables:
ANTHROPIC_API_KEY: $ANTHROPIC_API_KEY

Headless modeโ€‹

In CI environments, use non-interactive mode with the -p (or --print) flag:

# Run a single command and exit
claude -p "Analyze this code for security vulnerabilities" < vulnerable-code.ts

# Process piped input
cat error.log | claude -p "Analyze this error log and find the root cause"

# JSON output format
claude -p "Generate an API schema" --output-format json

# Streaming output
claude -p "Analyze this code" --output-format stream-json

Multi-turn conversations (via the SDK)โ€‹

claude -p is single-turn. When you need multiple turns, use the SDK:

import { ClaudeCode } from "@anthropic-ai/claude-code";

const claude = new ClaudeCode();
const conversation = await claude.startConversation();

// Turn 1: analyze
const analysis = await conversation.send("Analyze this code");
// Turn 2: fix based on the analysis
const fix = await conversation.send("Fix the issues you found");

Security configurationโ€‹

API key managementโ€‹

# Store in GitHub Secrets
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}

Never put an API key directly in a workflow file.

Least-privilege permissionsโ€‹

permissions:
contents: read # read code only
pull-requests: write # post PR comments
issues: write # issue comments (if needed)

Tool restrictionsโ€‹

In CI environments, restrict the available tools with --allowedTools and --disallowedTools:

# Read-only review
claude -p "Review this code" \
--allowedTools "Read,Grep,Glob" \
--disallowedTools "Bash,Edit,Write"

# Allow edits (only in isolated environments)
claude -p "Fix this bug" \
--allowedTools "Read,Edit,Write,Bash(npm test *)"
Permission modes in CI

In CI, explicitly allowlisting only the tools you need with --allowedTools is safer than --dangerously-skip-permissions. Use bypass mode only in isolated containers.

Cost considerationsโ€‹

Using the Claude API in CI incurs cost. Manage it with these strategies:

# Run only on PRs with a specific label
if: contains(github.event.pull_request.labels.*.name, 'needs-review')

# Limit the number of changed files
- name: Check file count
run: |
COUNT=$(git diff --name-only origin/main...HEAD | wc -l)
if [ $COUNT -gt 20 ]; then
echo "Too many files - skipping Claude review"
exit 0
fi

# Use a lightweight model
- uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
claude_args: "--model claude-haiku-4-5-20251001"

A full pipeline in practiceโ€‹

name: Full CI Pipeline with Claude

on:
pull_request:
push:
branches: [main]

jobs:
# Stage 1: lint and build
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci
- run: npm run build
- run: npm run lint

# Stage 2: test
test:
runs-on: ubuntu-latest
needs: build
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci
- run: npm test -- --coverage

# Stage 3: Claude review (PRs only)
claude-review:
runs-on: ubuntu-latest
needs: test
if: github.event_name == 'pull_request'
permissions:
contents: read
pull-requests: write
issues: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
prompt: |
Check the following in your code review:
1. Bugs and security vulnerabilities
2. Performance issues
3. Test coverage

# Stage 4: deploy (main branch only)
deploy:
runs-on: ubuntu-latest
needs: [build, test]
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- name: Deploy
run: echo "Running deployment script"