🇫🇷 Français

CI/CD and Headless Mode with Claude Code

Day 15 - Automate your pipelines with AI

By Angelo Lima

Claude Code isn’t limited to interactive use. With headless mode, you can integrate it into your CI/CD pipelines. Let’s see how to automate intelligently.

Headless Mode: -p

The -p (or --print) flag allows running Claude Code without interaction:

claude -p "Explain what this code does" < file.js

Claude reads the prompt, executes the task, and returns the result to stdout.

Basic Syntax

# Simple prompt
claude -p "Generate a .gitignore file for Node.js"

# With stdin input
cat src/utils.ts | claude -p "Find potential bugs"

# With files in context
claude -p "Refactor @src/api/auth.ts to use async/await"

Headless Mode Options

Option Description
-p "prompt" Execute with this prompt
--output-format json Structured JSON output
--output-format text Text output (default)
--max-turns N Limit iterations
--allowedTools Restrict tools

GitHub Actions Integration

Automatic Code Review Workflow

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

on:
  pull_request:
    types: [opened, synchronize]

jobs:
  review:
    runs-on: ubuntu-latest
    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: Get changed files
        id: changed
        run: |
          echo "files=$(git diff --name-only origin/main...HEAD | tr '\n' ' ')" >> $GITHUB_OUTPUT

      - name: Claude Review
        env:
          ANTHROPIC_API_KEY: $
        run: |
          claude -p "Review these modified files and identify potential issues: $" \
            --output-format json > review.json

      - name: Post Review Comment
        uses: actions/github-script@v7
        with:
          script: |
            const fs = require('fs');
            const review = JSON.parse(fs.readFileSync('review.json', 'utf8'));
            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: `## 🤖 Claude Code Review\n\n${review.result}`
            });

Test Generation Workflow

# .github/workflows/claude-tests.yml
name: Generate Missing Tests

on:
  workflow_dispatch:
    inputs:
      file:
        description: 'File to generate tests for'
        required: true

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

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

      - name: Generate Tests
        env:
          ANTHROPIC_API_KEY: $
        run: |
          claude -p "Generate comprehensive tests for @$" \
            --allowedTools Read,Write

      - name: Create PR
        uses: peter-evans/create-pull-request@v6
        with:
          title: "test: add tests for $"
          body: "Tests automatically generated by Claude Code"
          branch: claude/tests-$

GitLab CI Integration

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

claude-review:
  stage: review
  image: node:20
  before_script:
    - npm install -g @anthropic-ai/claude-code
  script:
    - |
      claude -p "Review the code in this MR and list issues" \
        --output-format json > review.json
    - cat review.json
  artifacts:
    paths:
      - review.json
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"

generate-docs:
  stage: generate
  image: node:20
  before_script:
    - npm install -g @anthropic-ai/claude-code
  script:
    - claude -p "Generate JSDoc documentation for all src/**/*.ts files without documentation"
  when: manual

Production Use Cases

1. Automatic Code Review

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

PR_FILES=$(git diff --name-only origin/main...HEAD)

claude -p "
You are a senior reviewer. Analyze these modified files:
$PR_FILES

Look for:
1. Potential bugs
2. Performance issues
3. Security vulnerabilities
4. Convention violations

Format: JSON with severity (high/medium/low)
" --output-format json

2. Changelog Generation

#!/bin/bash
# scripts/generate-changelog.sh

LAST_TAG=$(git describe --tags --abbrev=0)
COMMITS=$(git log $LAST_TAG..HEAD --pretty=format:"%s")

claude -p "
Generate a changelog from these commits:
$COMMITS

Keep a Changelog format with sections:
- Added
- Changed
- Fixed
- Removed
"

3. Automatic Code Migration

#!/bin/bash
# scripts/migrate-to-ts.sh

for file in src/**/*.js; do
  claude -p "Convert this JavaScript file to TypeScript with strict types: @$file" \
    --allowedTools Read,Write
done

4. Security Audit

# .github/workflows/security-audit.yml
name: Security Audit

on:
  schedule:
    - cron: '0 2 * * 1'  # Every Monday at 2am

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

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

      - name: Security Audit
        env:
          ANTHROPIC_API_KEY: $
        run: |
          claude -p "
            Perform a comprehensive security audit:
            1. Scan dependencies for known vulnerabilities
            2. Check for dangerous code patterns
            3. Identify potentially exposed secrets

            Generate a report with priorities.
          " --output-format json > security-report.json

      - name: Upload Report
        uses: actions/upload-artifact@v4
        with:
          name: security-report
          path: security-report.json

Permission Control in CI

claude -p "Generate tests" \
  --allowedTools Read,Grep,Glob \
  --dangerously-skip-permissions

⚠️ --dangerously-skip-permissions should only be used in isolated environments (CI containers).

Tool Restriction

# Read-only
claude -p "Analyze this code" --allowedTools Read,Grep,Glob

# With limited write access
claude -p "Fix the bugs" --allowedTools Read,Write,Edit

# Full access (dangerous)
claude -p "Setup the project" --allowedTools "*"

Cost Management in CI

Limit Tokens

# Limit execution turns
claude -p "Quick review" --max-turns 3

# For simple tasks
claude -p "Explain this function" --max-turns 1

Cost Estimation

Task Estimated tokens Approximate cost
Simple code review ~5,000 ~$0.02
Test generation ~15,000 ~$0.05
Complete refactoring ~50,000 ~$0.15
Security audit ~30,000 ~$0.10

Daily Budget

# Example: limit runs per day
jobs:
  review:
    if: github.event.pull_request.draft == false
    # Avoid reviewing drafts

JSON Output Format

Response Structure

claude -p "Analyze this code" --output-format json
{
  "result": "Code analysis...",
  "cost": {
    "input_tokens": 1234,
    "output_tokens": 567,
    "total_cost": 0.01
  },
  "session_id": "abc123",
  "duration_ms": 5432
}

Parsing in Scripts

#!/bin/bash

RESULT=$(claude -p "Check for bugs" --output-format json)

BUGS=$(echo $RESULT | jq '.result')
COST=$(echo $RESULT | jq '.cost.total_cost')

echo "Bugs found: $BUGS"
echo "Cost: $COST"

CI/CD Best Practices

1. Cache Claude Artifacts

- name: Cache Claude artifacts
  uses: actions/cache@v4
  with:
    path: ~/.claude
    key: claude-$-$

2. Reproducible Environment

- name: Setup Claude environment
  run: |
    npm install -g @anthropic-ai/claude-code@latest
    echo "CLAUDE_CODE_USE_BEDROCK=0" >> $GITHUB_ENV

3. Error Handling

#!/bin/bash
set -e

if ! claude -p "Task" --output-format json > result.json; then
  echo "Claude failed, falling back to manual review"
  exit 0  # Don't block the pipeline
fi

4. Detailed Logging

- name: Claude with logging
  run: |
    claude -p "Task" 2>&1 | tee claude-output.log
  env:
    CLAUDE_CODE_DEBUG: "1"

What’s Coming Tomorrow

In Day 16, we’ll talk about billing and cost optimization - understanding and mastering your Claude Code consumption.


This article is part of the “Master Claude Code in 20 Days” series. Day 14: VS Code and JetBrains

Share: