Claude Code in CI/CD Pipelines
Claude Code is a CLI tool — it runs anywhere bash runs. That means you can use it in GitHub Actions, GitLab CI, CircleCI, or any Docker-based pipeline to automate code review, PR summaries, test generation, and changelog updates without human intervention.
Prerequisites
- An Anthropic API key (set as a CI secret — never hardcode it)
- Node.js 18+ on your runner (most GitHub Actions runners include it)
- The
--no-interactiveflag on allclaudecommands (required in non-TTY environments)
GitHub Actions: Automated PR Review
This workflow runs Claude Code review on every pull request and posts the summary as a PR comment.
# .github/workflows/claude-review.yml
name: Claude Code PR 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 # full history for accurate diff
- name: Install Claude Code
run: npm install -g @anthropic-ai/claude-code
- name: Run Claude review
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
run: |
git diff origin/${{ github.base_ref }}...HEAD > /tmp/pr.diff
claude --no-interactive \
"Review this pull request diff for correctness, security issues, and style. Output a structured markdown review with sections: Summary, Issues (severity: high/medium/low), Suggestions. Be concise." \
< /tmp/pr.diff > /tmp/review.md
- name: Post review comment
env:
GH_TOKEN: ${{ github.token }}
run: |
gh pr comment ${{ github.event.pull_request.number }} \
--body "$(cat /tmp/review.md)"
GitHub Actions: PR Summary on Merge
Auto-generate a human-readable changelog entry when a PR merges to main.
# .github/workflows/claude-changelog.yml
name: Generate Changelog Entry
on:
pull_request:
types: [closed]
branches: [main]
jobs:
changelog:
if: github.event.pull_request.merged == true
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 changelog entry
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
run: |
git log --oneline origin/main~1..HEAD > /tmp/commits.txt
git diff origin/main~1..HEAD -- '*.ts' '*.js' '*.py' > /tmp/diff.txt
claude --no-interactive \
"Given these commits and code changes, write one concise changelog entry (1-3 sentences, plain language, user-facing focus). No bullet points. Start with a verb." \
< <(cat /tmp/commits.txt /tmp/diff.txt) >> CHANGELOG.md
- name: Commit changelog
run: |
git config user.email "ci@example.com"
git config user.name "Claude Code Bot"
git add CHANGELOG.md
git commit -m "chore: add changelog entry for PR #${{ github.event.pull_request.number }}" || true
git push
GitHub Actions: Test Generation on New Functions
Detect new functions in a PR and auto-generate test stubs.
name: Claude Test Generation
on:
pull_request:
types: [opened]
jobs:
gen-tests:
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 test stubs
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
run: |
# Extract only new/changed source files (not test files)
git diff origin/${{ github.base_ref }}...HEAD \
--name-only \
--diff-filter=AM \
| grep -E '\.(ts|js|py)$' \
| grep -v '__tests__\|\.test\.\|\.spec\.' \
> /tmp/changed_files.txt
if [ -s /tmp/changed_files.txt ]; then
while IFS= read -r file; do
claude --no-interactive \
"Generate Jest test stubs for all exported functions in this file. Use describe/it blocks, include happy path and one edge case per function. Output only the test file content." \
< "$file" > "${file%.ts}.test.ts"
done < /tmp/changed_files.txt
fi
- name: Commit generated tests
run: |
git config user.email "ci@example.com"
git config user.name "Claude Code Bot"
git add -A
git diff --staged --quiet || git commit -m "test: add generated test stubs"
git push origin HEAD:${{ github.head_ref }}
GitLab CI: Equivalent Setup
# .gitlab-ci.yml
stages:
- review
claude-review:
stage: review
image: node:20
only:
- merge_requests
script:
- npm install -g @anthropic-ai/claude-code
- git diff origin/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME..HEAD > /tmp/pr.diff
- claude --no-interactive
"Review this diff for bugs, security issues, and code quality. Output markdown."
< /tmp/pr.diff > /tmp/review.md
- |
curl --request POST \
--header "PRIVATE-TOKEN: $GITLAB_API_TOKEN" \
--header "Content-Type: application/json" \
--data "{\"body\": \"$(cat /tmp/review.md | jq -Rs .)\"}" \
"$CI_API_V4_URL/projects/$CI_PROJECT_ID/merge_requests/$CI_MERGE_REQUEST_IID/notes"
variables:
ANTHROPIC_API_KEY: $ANTHROPIC_API_KEY # set in GitLab CI/CD variables
CI Cost Estimation
| Task | Tokens (approx) | Cost (Sonnet 4.6) | Cost/month (50 PRs) |
|---|---|---|---|
| PR review (200-line diff) | ~8K in / 1K out | ~$0.03 | ~$1.50 |
| PR review (1000-line diff) | ~25K in / 2K out | ~$0.10 | ~$5.00 |
| Changelog entry | ~5K in / 0.2K out | ~$0.015 | ~$0.75 |
| Test stub generation (1 file) | ~3K in / 1.5K out | ~$0.02 | ~$1.00 |
Enable prompt caching on your CLAUDE.md content to cut repeated-context costs by ~90%. The cache write is a one-time cost per session; all subsequent calls in the same CI job reuse it at $0.003/1K tokens (vs $0.003 base rate — full read is $0.015/1K).
Best Practices for CI Use
- Always use
--no-interactive— CI has no TTY and will hang without it - Set a
--max-tokenslimit on review output to control costs and keep comments readable - Cache the
npm install -gstep using GitHub Actions cache to avoid the install delay on every run - Store
ANTHROPIC_API_KEYas a repository secret — never hardcode it in workflow files - Use
--output jsonwhen piping output to other tools — structured JSON is more reliable than parsing prose - Create a
CLAUDE.mdin your repo root — it's automatically loaded and tells Claude your coding conventions, avoiding generic suggestions - Scope the review diff to changed files only — pipe
git diff --name-onlybefore running Claude to avoid processing unchanged code
Security note: API key handling
Never commit your Anthropic API key. Use GitHub Actions secrets (${{ secrets.ANTHROPIC_API_KEY }}), GitLab CI/CD variables, or environment variable injection at runtime. The key has full API access — treat it like a production password.
Frequently Asked Questions
Can Claude Code run in GitHub Actions?
Yes. Install with npm install -g @anthropic-ai/claude-code, set ANTHROPIC_API_KEY from GitHub secrets, and use --no-interactive on all commands. See the workflow examples above for PR review and changelog automation.
How much does Claude Code CI automation cost?
A PR review costs ~$0.03-0.10 per PR on Sonnet 4.6 (depending on diff size). 50 PRs/month costs roughly $1.50-5.00. Enable prompt caching on your CLAUDE.md to reduce repeated-context costs by ~90%.
Does Claude Code work in GitLab CI?
Yes. Use the same CLI commands in any Node.js Docker image. Set ANTHROPIC_API_KEY as a GitLab CI/CD variable (masked). The --no-interactive flag is required in all CI environments.
Can Claude Code post comments on GitHub pull requests?
Not directly — it outputs to stdout. Pipe the output to gh pr comment <number> --body "$(cat review.md)" using the GitHub CLI (pre-installed on GitHub-hosted runners). See the PR review workflow above for a complete example.
→ Full GitHub integration guide
→ Claude Code vs GitHub Copilot