Agent Skills: CI/CD Integration Patterns

Patterns for integrating Claude Code into CI/CD pipelines — GitHub Actions, GitLab CI, pre-commit hooks, automated PR reviews, headless mode, and cost control

UncategorizedID: lobbi-docs/claude/cicd-integration

Install this agent skill to your local

pnpm dlx add-skill https://github.com/markus41/claude/tree/HEAD/plugins/claude-code-expert/skills/cicd-integration

Skill Files

Browse the full folder contents for cicd-integration.

Download Skill

Loading file tree…

plugins/claude-code-expert/skills/cicd-integration/SKILL.md

Skill Metadata

Name
cicd-integration
Description
Patterns for integrating Claude Code into CI/CD pipelines — GitHub Actions, GitLab CI, pre-commit hooks, automated PR reviews, headless mode, and cost control

CI/CD Integration Patterns

Integrate Claude Code into CI/CD pipelines for automated PR reviews, code generation, test validation, security scanning, and documentation updates. This skill covers GitHub Actions, GitLab CI, pre-commit hooks, and headless execution modes.

GitHub Actions Integration

Use the official anthropics/claude-code-action@v1 action for turnkey GitHub integration.

Supported Features

  • Trigger on pull requests, push, schedule, or workflow dispatch
  • Environment variable support: ANTHROPIC_API_KEY, CLAUDE_MODEL
  • Pipe mode (claude -p) with JSON output
  • Tool access filtering via --allowedTools
  • Multiple model routing (Opus for reviews, Haiku for checks)
  • Cost tracking and budget enforcement

Setup

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

on:
  pull_request:
    types: [opened, synchronize]
  workflow_dispatch:

jobs:
  review:
    runs-on: ubuntu-latest
    permissions:
      pull-requests: write
      contents: read
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - uses: anthropics/claude-code-action@v1
        with:
          task: |
            Review the changes in this PR and provide:
            1. Security issues found (if any)
            2. Code style or complexity concerns
            3. Test coverage gaps
            4. Performance suggestions
            Format as JSON for PR comment automation.
          model: claude-opus-4-1-20250805
          allowed-tools: Read,Grep,Glob
          output-format: json
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}

Usage in PR Comments

# .github/workflows/claude-pr-analysis.yml
name: Claude PR Analysis with Comments

on:
  pull_request:
    types: [opened, synchronize]

jobs:
  analyze:
    runs-on: ubuntu-latest
    permissions:
      pull-requests: write
      contents: read
    steps:
      - uses: actions/checkout@v4

      - uses: anthropics/claude-code-action@v1
        id: claude
        with:
          task: |
            {
              "goal": "Review files in this PR",
              "files": "${{ github.event.pull_request.title }}",
              "output": "json"
            }
          output-format: json
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}

      - name: Comment Review on PR
        if: always()
        uses: actions/github-script@v7
        with:
          script: |
            const result = JSON.parse('${{ steps.claude.outputs.result }}');
            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: `## Claude Code Review\n\n${result.summary}`
            });

Code Generation Workflow

# .github/workflows/claude-codegen.yml
name: Generate Code on Dispatch

on:
  workflow_dispatch:
    inputs:
      feature:
        description: Feature to generate
        required: true
      model:
        description: Model to use
        default: claude-opus-4-1-20250805
        required: false

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

      - uses: anthropics/claude-code-action@v1
        with:
          task: Generate ${{ github.event.inputs.feature }}
          model: ${{ github.event.inputs.model }}
          output-format: json
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}

      - name: Create PR with Generated Code
        uses: peter-evans/create-pull-request@v5
        with:
          commit-message: "feat: ${{ github.event.inputs.feature }}"
          title: "Generate: ${{ github.event.inputs.feature }}"
          body: "Auto-generated code from Claude Code Expert"

GitLab CI Integration

Configure Claude Code in GitLab CI pipelines using Docker containers and the CLI.

Setup

# .gitlab-ci.yml
stages:
  - review
  - test
  - generate

variables:
  CLAUDE_MODEL: claude-haiku-4-5-20251001
  CLAUDE_MAX_TURNS: "5"

claude_review:
  stage: review
  image: node:20-alpine
  before_script:
    - npm install -g @anthropic-ai/claude-code
  script:
    - |
      claude \
        -p "Review the MR changes and identify issues" \
        --allowedTools Read,Grep,Glob \
        --output-format json > review_output.json
  artifacts:
    paths:
      - review_output.json
    expire_in: 1 day
  only:
    - merge_requests

claude_test_gap:
  stage: test
  image: node:20-alpine
  before_script:
    - npm install -g @anthropic-ai/claude-code
  script:
    - |
      claude \
        -p "Find test coverage gaps in changed files" \
        --allowedTools Read,Grep,Glob \
        --max-turns 3
  allow_failure: true

With Caching

claude_cached_analysis:
  stage: review
  image: node:20-alpine
  cache:
    key: claude-analysis-${CI_COMMIT_SHA}
    paths:
      - .claude/cache/
      - .claude/memory/
  before_script:
    - npm install -g @anthropic-ai/claude-code
  script:
    - claude -p "Cached analysis of repo structure"

Pre-Commit Hook Integration

Validate code locally before pushing using Claude Code as a pre-commit hook.

Husky Setup

# Install dependencies
npm install husky lint-staged -D

# Initialize husky
npx husky install

# Create Claude hook
cat > .husky/pre-commit << 'EOF'
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

# Run lint-staged (including Claude)
npx lint-staged
EOF

chmod +x .husky/pre-commit

Lint-Staged Configuration

{
  "lint-staged": {
    "*.{ts,tsx,js,jsx}": [
      "eslint --fix",
      "claude -p 'Quick style check' --allowedTools Read,Grep"
    ],
    "*.{md,mdx}": [
      "markdown-lint",
      "claude -p 'Check documentation clarity' --allowedTools Read"
    ]
  }
}

Direct Pre-Commit Hook

#!/bin/bash
# .git/hooks/pre-commit
# Check staged files with Claude Code

STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep -E '\.(ts|tsx|js|jsx)$')

if [ -z "$STAGED_FILES" ]; then
  exit 0
fi

echo "Running Claude Code check on staged files..."

if ! claude -p "Security check: $STAGED_FILES" \
      --allowedTools Read,Grep,Glob \
      --max-turns 2; then
  echo "Claude Code check failed. Use 'git commit --no-verify' to bypass."
  exit 1
fi

Automated PR Reviews with Structured Output

Use JSON formatting to post structured reviews to PRs.

Review Configuration

#!/bin/bash
# scripts/claude-pr-review.sh

set -euo pipefail

REPO=$1
PR_NUMBER=$2
GITHUB_TOKEN=$3

# Clone PR branch
git clone "https://github.com/$REPO.git" /tmp/pr-check
cd /tmp/pr-check
git fetch origin pull/$PR_NUMBER/head
git checkout FETCH_HEAD

# Run Claude review
REVIEW_JSON=$(claude -p \
  "Analyze this PR for: security issues, code quality, test coverage, performance" \
  --allowedTools Read,Grep,Glob \
  --max-turns 3 \
  --output-format json)

# Parse results and post
SECURITY=$(echo "$REVIEW_JSON" | jq -r '.security // "None found"')
QUALITY=$(echo "$REVIEW_JSON" | jq -r '.quality // "Pass"')
TESTS=$(echo "$REVIEW_JSON" | jq -r '.test_coverage // "Adequate"')

curl -X POST \
  -H "Accept: application/vnd.github+json" \
  -H "Authorization: token $GITHUB_TOKEN" \
  "https://api.github.com/repos/$REPO/issues/$PR_NUMBER/comments" \
  -d @- << EOF
{
  "body": "## Claude Code Review\n\n**Security:** $SECURITY\n\n**Quality:** $QUALITY\n\n**Tests:** $TESTS"
}
EOF

rm -rf /tmp/pr-check

Headless Mode Patterns

Execute Claude Code in fully automated environments without interaction.

Read-Only Checks

# Security scan (no write access)
claude -p "Security audit" \
  --allowedTools Read,Grep,Glob \
  --output-format json \
  --max-turns 2

Constrained Sessions

# Limit turn count to prevent runaway costs
claude -p "Generate test stubs" \
  --allowedTools Read,Glob,Bash \
  --max-turns 5 \
  --output-format json

Model Selection for CI

# Haiku for fast checks (cheaper)
CLAUDE_MODEL=claude-haiku-4-5-20251001 claude -p "Style check"

# Opus for complex analysis (more capable)
CLAUDE_MODEL=claude-opus-4-1-20250805 claude -p "Architecture review"

Exit Code Handling

#!/bin/bash
# scripts/claude-ci-validator.sh

if claude -p "Validate build output" \
         --allowedTools Read,Glob \
         --output-format json; then
  echo "Validation passed"
  exit 0
else
  echo "Validation failed"
  exit 1
fi

SDK-Based CI Integration

Use the @anthropic-ai/claude-code npm package for programmatic control.

Installation

npm install @anthropic-ai/claude-code

Basic Usage

// scripts/ci-validator.mjs
import { claudeCode } from '@anthropic-ai/claude-code';

const result = await claudeCode.executeHeadless({
  task: 'Analyze test coverage and report gaps',
  allowedTools: ['Read', 'Grep', 'Glob'],
  outputFormat: 'json',
  maxTurns: 3,
  model: 'claude-haiku-4-5-20251001'
});

console.log(JSON.stringify(result, null, 2));
process.exit(result.success ? 0 : 1);

Streaming Output

// scripts/ci-streaming.mjs
import { claudeCode } from '@anthropic-ai/claude-code';

const stream = await claudeCode.streamHeadless({
  task: 'Generate missing test files',
  allowedTools: ['Read', 'Glob'],
  model: 'claude-opus-4-1-20250805'
});

for await (const chunk of stream) {
  process.stdout.write(chunk.text || '');
  if (chunk.status === 'complete') {
    process.exit(chunk.exitCode);
  }
}

Cost Control in CI

Manage Claude API costs in automated environments.

Budget Estimation

# Haiku: ~$0.80 per million input tokens, $2.40 per million output
# Estimated cost per CI run with Haiku: $0.01-0.05

# Opus: ~$15 per million input tokens, $45 per million output
# Estimated cost per CI run with Opus: $0.10-0.30

# Strategy: Use Haiku for checks, Opus for analysis on schedule

Cost-Optimized Workflow

# .github/workflows/claude-optimized.yml
on:
  pull_request:
    types: [opened, synchronize]
  schedule:
    - cron: '0 2 * * *'  # Deep analysis daily

jobs:
  fast-check:
    if: github.event_name == 'pull_request'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: anthropics/claude-code-action@v1
        with:
          task: Quick lint check
          model: claude-haiku-4-5-20251001
          allowed-tools: Grep,Glob
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}

  deep-analysis:
    if: github.event_name == 'schedule'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: anthropics/claude-code-action@v1
        with:
          task: Full architecture review
          model: claude-opus-4-1-20250805
          allowed-tools: Read,Grep,Glob,Bash
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}

Secrets Management

Safely handle API keys and credentials in CI/CD.

GitHub Secrets

env:
  ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}

jobs:
  review:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: anthropics/claude-code-action@v1
        with:
          task: Review changes
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}

GitLab CI Secrets

claude_review:
  variables:
    ANTHROPIC_API_KEY: $ANTHROPIC_API_KEY  # Set in GitLab UI
  script:
    - claude -p "Run analysis" --output-format json

Never Log Sensitive Data

#!/bin/bash
# Safe logging in CI

# DON'T do this:
# echo "API Key: $ANTHROPIC_API_KEY"

# DO this:
echo "Starting Claude review (API key configured)"

# Output result without exposing key
claude -p "Review files" 2>&1 | grep -v "Authorization" > output.log

Example Workflows (Copy-Paste Ready)

1. PR Review Bot (GitHub Actions)

# .github/workflows/claude-review-pr.yml
name: Claude PR Review Bot

on:
  pull_request:
    types: [opened, synchronize]
    paths-ignore:
      - '**.md'
      - 'docs/**'

jobs:
  review:
    runs-on: ubuntu-latest
    permissions:
      pull-requests: write
      contents: read
    if: github.event.action != 'closed'
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - uses: anthropics/claude-code-action@v1
        id: review
        with:
          task: |
            Review this PR and provide assessment in JSON:
            {
              "overall_score": 1-10,
              "security_issues": [],
              "code_quality": "pass|warning|fail",
              "test_coverage": "adequate|needs_improvement",
              "suggestions": []
            }
          model: claude-opus-4-1-20250805
          allowed-tools: Read,Grep,Glob
          output-format: json
          max-turns: 3
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}

      - name: Post Review Comment
        uses: actions/github-script@v7
        if: always()
        with:
          script: |
            const review = JSON.parse(`${{ steps.review.outputs.result }}`);
            const comment = `
## Claude Code Review

**Overall Score:** ${review.overall_score}/10
**Code Quality:** ${review.code_quality}
**Test Coverage:** ${review.test_coverage}

${review.suggestions.length > 0 ? '**Suggestions:**\n' + review.suggestions.map(s => `- ${s}`).join('\n') : 'No suggestions'}
            `;
            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: comment
            });

2. Test Gap Detector (GitHub Actions)

# .github/workflows/claude-test-gaps.yml
name: Detect Test Gaps

on:
  pull_request:
    paths:
      - 'src/**'

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

      - uses: anthropics/claude-code-action@v1
        with:
          task: |
            Identify test coverage gaps in changed files:
            1. List files without tests
            2. Find untested functions
            3. Suggest test cases
            Output as JSON array.
          model: claude-haiku-4-5-20251001
          allowed-tools: Read,Grep,Glob
          output-format: json
          max-turns: 2
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}

      - name: Fail if critical gaps
        run: |
          gaps=$(cat ${{ steps.claude.outputs.result }} | jq '.critical_gaps | length')
          if [ "$gaps" -gt 0 ]; then
            echo "Critical test gaps found!"
            exit 1
          fi

3. Security Scanner (GitHub Actions)

# .github/workflows/claude-security-scan.yml
name: Security Scan

on:
  pull_request:
  schedule:
    - cron: '0 3 * * 1'  # Monday 3 AM

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

      - uses: anthropics/claude-code-action@v1
        with:
          task: |
            Security audit:
            - Check for hardcoded secrets
            - Identify SQL injection risks
            - Review authentication logic
            - Check dependency vulnerabilities
            Format: { "vulnerabilities": [], "risk_level": "low|medium|high" }
          model: claude-opus-4-1-20250805
          allowed-tools: Read,Grep,Glob
          output-format: json
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}

      - name: Block on high risk
        run: |
          risk=$(jq -r '.risk_level' ${{ steps.claude.outputs.result }})
          if [ "$risk" = "high" ]; then
            echo "High security risk detected!"
            exit 1
          fi

4. Documentation Updater (GitHub Actions)

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

on:
  push:
    branches: [main]
    paths:
      - 'src/**'

jobs:
  update:
    runs-on: ubuntu-latest
    permissions:
      contents: write
      pull-requests: write
    steps:
      - uses: actions/checkout@v4

      - uses: anthropics/claude-code-action@v1
        id: docs
        with:
          task: |
            Update API documentation based on code changes:
            1. Regenerate parameter descriptions
            2. Update return type docs
            3. Add code examples where missing
            Output updated markdown files.
          model: claude-opus-4-1-20250805
          allowed-tools: Read,Glob,Write
          max-turns: 5
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}

      - name: Create Documentation PR
        uses: peter-evans/create-pull-request@v5
        with:
          commit-message: 'docs: auto-update from code changes'
          title: 'docs: regenerated from source'
          body: 'Auto-generated documentation updates'
          branch: auto-docs-update