Project 24: Headless Pipeline - CI/CD Integration

Build a CI/CD pipeline using Claude Code headless mode: automated code review on PRs, commit message validation, changelog generation, and documentation updates. Runs in GitHub Actions.

Quick Reference

Attribute Value
Difficulty Intermediate
Time Estimate 1 week
Language Bash + YAML (Alternatives: Python, TypeScript)
Prerequisites Basic Claude Code usage, CI/CD understanding
Key Topics Headless mode, -p flag, GitHub Actions, JSON output, automation
Main Book “Continuous Delivery” by Jez Humble & David Farley

1. Learning Objectives

By completing this project, you will:

  1. Master Claude Code headless mode: Use the -p flag for non-interactive automation in pipelines
  2. Integrate AI into CI/CD workflows: Embed Claude into GitHub Actions for automated code review
  3. Parse structured output: Handle --output-format json for programmatic result processing
  4. Control costs in automation: Use --max-turns and model selection for budget management
  5. Build production-ready workflows: Create robust error handling and graceful degradation
  6. Understand secrets management: Securely handle API keys in CI environments
  7. Design effective prompts for automation: Craft prompts that produce consistent, actionable output

2. Real World Outcome

When complete, you’ll have a working GitHub Actions workflow that automatically reviews pull requests:

# .github/workflows/claude-review.yml

name: Claude Code Review
on: [pull_request]

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

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

      - name: Run Code Review
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
        run: |
          # Get changed files
          CHANGED_FILES=$(git diff --name-only origin/main...HEAD)

          # Run Claude review
          claude -p "Review these changes for bugs and improvements: $CHANGED_FILES" \
            --output-format json \
            --max-turns 5 \
            > review.json

      - name: Post Review Comment
        uses: actions/github-script@v7
        with:
          script: |
            const review = require('./review.json');
            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: review.result
            });

Example Output on a Pull Request

## Claude Code Review

### Summary
This PR adds user authentication with JWT tokens. Overall the implementation looks solid, but I've identified a few areas for improvement.

### Issues Found

**Security Concerns:**
- Line 45 in `auth/login.ts`: Password comparison using `==` instead of timing-safe comparison
- Line 78 in `auth/login.ts`: JWT secret appears to be hardcoded

**Code Quality:**
- Line 23 in `api/users.ts`: Missing null check before accessing user.email
- Line 56 in `utils/validate.ts`: Regex can be simplified

### Recommendations
1. Use `crypto.timingSafeEqual()` for password comparison
2. Move JWT secret to environment variables
3. Add input validation for email format

3. The Core Question You’re Answering

“How do I integrate Claude Code into automated CI/CD pipelines for code review, documentation, and quality checks?”

Headless mode transforms Claude from an interactive assistant into an automation component. This project teaches you to use Claude in build pipelines, PR checks, and automated workflows - without requiring human interaction during execution.

Why This Matters

Traditional code review is a bottleneck in software development:

  • Human reviewers have limited bandwidth
  • Review quality varies by time of day and workload
  • Junior developers may miss subtle issues

AI-assisted review provides:

  • Consistent, tireless review coverage
  • Immediate feedback on every PR
  • Pattern detection across the entire codebase
  • Educational explanations for flagged issues

4. Concepts You Must Understand First

Stop and research these before coding:

4.1 Headless Mode Flags

Understanding Claude Code’s non-interactive mode is essential:

# Basic headless execution
claude -p "Your prompt here"

# With JSON output for parsing
claude -p "Review this code" --output-format json

# Limit turns to control costs
claude -p "Quick review" --max-turns 3

# Use a cheaper model for automated tasks
claude -p "Review" --model haiku

Key Questions:

  • What does -p do differently from interactive mode?
  • What output formats are available (text, json, stream-json)?
  • How do you limit turns and control costs?
  • What’s in the JSON output object?

Reference: Claude Code documentation - “Headless Mode”

4.2 GitHub Actions Fundamentals

# Workflow syntax essentials
name: Workflow Name           # Display name
on: [push, pull_request]      # Trigger events
jobs:
  job-name:
    runs-on: ubuntu-latest    # Runner environment
    steps:
      - uses: actions/checkout@v4  # Pre-built action
      - name: Custom Step
        run: echo "Hello"     # Shell command
        env:
          SECRET: ${{ secrets.MY_SECRET }}  # Secret access

Key Questions:

  • What events can trigger workflows?
  • How do you pass data between steps?
  • How are secrets stored and accessed?
  • What permissions does the workflow need?

Reference: GitHub Actions documentation

4.3 Structured Output Parsing

// Example claude --output-format json response
{
  "session_id": "abc123",
  "result": "The code review findings...",
  "cost": {
    "input_tokens": 1250,
    "output_tokens": 450,
    "total_cost": 0.0032
  },
  "duration_ms": 4500,
  "num_turns": 2
}

Key Questions:

  • How do you extract the result field reliably?
  • What happens if the JSON is malformed?
  • How do you handle empty or error responses?

Reference: Claude Code documentation - “–output-format”


5. Questions to Guide Your Design

Before implementing, think through these architectural decisions:

5.1 What to Automate?

Task Trigger Complexity Value
Code review on PRs pull_request Medium High
Commit message validation push Low Medium
Changelog generation release Medium High
Documentation updates File changes High Medium
Security scanning pull_request Medium Very High

5.2 Error Handling Strategy

┌─────────────────────────────────────────────────────────────────┐
│                    ERROR HANDLING TREE                           │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  Claude invocation fails                                         │
│       │                                                          │
│       ├── API key invalid ──► Fail workflow immediately         │
│       │                                                          │
│       ├── Rate limited ──► Retry with exponential backoff        │
│       │                                                          │
│       ├── Timeout ──► Retry once, then post warning              │
│       │                                                          │
│       └── Malformed output ──► Post "review unavailable"         │
│                                                                  │
│  Claude returns output                                           │
│       │                                                          │
│       ├── Valid JSON ──► Parse and post comment                  │
│       │                                                          │
│       └── Invalid JSON ──► Log error, post raw text              │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

5.3 Cost Control

Budget considerations for automated pipelines:

# Cost-conscious configuration
- name: Claude Review
  run: |
    claude -p "$PROMPT" \
      --model haiku \        # Cheaper model for routine reviews
      --max-turns 3 \        # Limit iterations
      --output-format json
  timeout-minutes: 5         # Hard timeout

Questions to answer:

  • What’s your monthly budget for AI reviews?
  • Which PRs need full Opus review vs. Haiku?
  • Should you limit reviews to certain file types?

6. Thinking Exercise

Design the Complete Pipeline

Before writing code, sketch out your pipeline:

┌─────────────────────────────────────────────────────────────────┐
│                      CI/CD PIPELINE                              │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  PR Created/Updated                                              │
│       │                                                          │
│       ▼                                                          │
│  ┌─────────────────┐                                            │
│  │ 1. CHECKOUT     │ Get PR code with full history              │
│  │    fetch-depth: 0                                            │
│  └────────┬────────┘                                            │
│           │                                                      │
│           ▼                                                      │
│  ┌─────────────────┐                                            │
│  │ 2. GET DIFF     │ git diff origin/main...HEAD                │
│  │    Find changed │ Filter by file type                        │
│  │    files        │                                            │
│  └────────┬────────┘                                            │
│           │                                                      │
│           ▼                                                      │
│  ┌─────────────────┐                                            │
│  │ 3. INSTALL      │ npm install -g @anthropic-ai/claude-code   │
│  │    CLAUDE       │                                            │
│  └────────┬────────┘                                            │
│           │                                                      │
│           ▼                                                      │
│  ┌─────────────────┐                                            │
│  │ 4. CLAUDE       │ claude -p "Review these changes"           │
│  │    REVIEW       │ --output-format json                       │
│  │                 │ --max-turns 5                              │
│  └────────┬────────┘                                            │
│           │                                                      │
│           ▼                                                      │
│  ┌─────────────────┐                                            │
│  │ 5. PARSE        │ Extract review from JSON                   │
│  │    OUTPUT       │ Handle errors gracefully                   │
│  └────────┬────────┘                                            │
│           │                                                      │
│           ▼                                                      │
│  ┌─────────────────┐                                            │
│  │ 6. POST         │ github.rest.issues.createComment           │
│  │    COMMENT      │ Format as markdown                         │
│  └─────────────────┘                                            │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

Design Questions

  1. What happens if the diff is too large?
    • Claude has context limits
    • Consider summarizing or chunking large diffs
    • Maybe review only the most critical files
  2. Should you run different models for different tasks?
    • Haiku for routine reviews
    • Opus for security-critical changes
    • Sonnet as a good middle ground
  3. How do you handle rate limits?
    • Exponential backoff
    • Queue PRs during high traffic
    • Consider a review queue service

7. The Interview Questions They’ll Ask

Prepare for these common questions:

7.1 “How would you integrate an AI assistant into a CI/CD pipeline?”

Good answer structure:

  1. Identify the automation target (code review, docs, etc.)
  2. Choose headless mode with appropriate flags
  3. Parse structured output for downstream processing
  4. Handle errors gracefully (don’t block PRs on AI failures)
  5. Control costs with model selection and turn limits

7.2 “What’s headless mode and why is it important for automation?”

Key points:

  • Headless mode (-p flag) runs Claude without interactive input
  • Essential for CI/CD where no human is present
  • Returns immediately with output (or streams it)
  • Can output in structured formats (JSON) for parsing

7.3 “How do you handle costs in automated AI workflows?”

Strategies:

  • Use cheaper models (Haiku) for routine tasks
  • Limit turns with --max-turns
  • Filter which PRs get AI review
  • Monitor usage and set budget alerts
  • Cache repeated analyses

7.4 “What are the security considerations for AI in CI/CD?”

Considerations:

  • Never expose API keys in logs
  • Use GitHub secrets for credentials
  • Be careful about what context you send to the API
  • Consider data sensitivity (don’t review files with secrets)
  • Rate limit to prevent abuse

7.5 “How do you handle failures in AI-powered automation?”

Best practices:

  • Never block PRs on AI failures (graceful degradation)
  • Retry with exponential backoff for transient errors
  • Post informative comments when review unavailable
  • Log failures for monitoring
  • Have fallback to human review

8. Hints in Layers

Use these hints progressively if you get stuck:

Hint 1: Start with a Simple Review

Don’t try to build everything at once. Start with the simplest possible workflow:

- name: Simple Review
  run: |
    echo "Changed files: $(git diff --name-only origin/main...HEAD)"
    claude -p "Review this code for bugs" --output-format text

Hint 2: Add JSON Output

Once basic review works, switch to JSON for parsing:

- name: Structured Review
  run: |
    claude -p "Review these changes" \
      --output-format json \
      > review.json

    # Debug: see what we got
    cat review.json | jq .

Hint 3: Limit Costs

Add cost controls before you accidentally spend too much:

- name: Cost-Controlled Review
  run: |
    claude -p "Review" \
      --output-format json \
      --max-turns 3 \
      --model haiku \
      > review.json

Hint 4: Handle Errors

Make the workflow robust:

- name: Robust Review
  run: |
    if ! claude -p "Review" --output-format json > review.json 2>&1; then
      echo '{"result": "Review unavailable - Claude error"}' > review.json
    fi

    # Validate JSON
    if ! jq -e . review.json > /dev/null 2>&1; then
      echo '{"result": "Review unavailable - invalid output"}' > review.json
    fi

9. Books That Will Help

Topic Book Chapter/Section
CI/CD patterns “Continuous Delivery” by Humble & Farley Ch. 5: Anatomy of the Deployment Pipeline
CI/CD patterns “Continuous Delivery” by Humble & Farley Ch. 6: Build and Deployment Scripting
CI/CD patterns “Continuous Delivery” by Humble & Farley Ch. 7: The Commit Stage
Automation “The Phoenix Project” by Kim, Behr, Spafford Ch. 10-15: Build automation
DevOps “Accelerate” by Forsgren, Humble, Kim All: Metrics-driven improvement
GitHub Actions GitHub Actions Documentation Workflow syntax and examples

10. Implementation Guide

10.1 Complete Workflow Example

name: Claude Code Review
on:
  pull_request:
    types: [opened, synchronize]

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

    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          fetch-depth: 0  # Full history for diff

      - name: Setup Node
        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: |
          FILES=$(git diff --name-only origin/${{ github.base_ref }}...HEAD | tr '\n' ' ')
          echo "files=$FILES" >> $GITHUB_OUTPUT
          echo "Changed files: $FILES"

      - name: Check if Files to Review
        id: check
        run: |
          if [ -z "${{ steps.changed.outputs.files }}" ]; then
            echo "skip=true" >> $GITHUB_OUTPUT
          else
            echo "skip=false" >> $GITHUB_OUTPUT
          fi

      - name: Claude Review
        if: steps.check.outputs.skip != 'true'
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
        run: |
          claude -p "
          Review these changed files for:
          1. Bugs or potential issues
          2. Code quality improvements
          3. Security concerns
          4. Performance issues

          Files: ${{ steps.changed.outputs.files }}

          Format your response as markdown with clear sections.
          Be concise and actionable.
          " --output-format json --max-turns 3 --model haiku > review.json

      - name: Post Comment
        if: steps.check.outputs.skip != 'true'
        uses: actions/github-script@v7
        with:
          script: |
            const fs = require('fs');
            let body;

            try {
              const review = JSON.parse(fs.readFileSync('review.json', 'utf8'));
              body = `## Claude Code Review\n\n${review.result || 'No issues found.'}`;
            } catch (e) {
              body = '## Claude Code Review\n\n_Review unavailable - please check workflow logs._';
            }

            await github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body
            });

      - name: Skip Notice
        if: steps.check.outputs.skip == 'true'
        run: echo "No files to review"

10.2 Extended Features

Once the basic review works, consider adding:

Commit Message Validation:

- name: Validate Commit Messages
  run: |
    COMMITS=$(git log origin/${{ github.base_ref }}..HEAD --format="%s")
    claude -p "Check if these commit messages follow conventional commits: $COMMITS" \
      --output-format json > commit-check.json

Changelog Generation:

- name: Generate Changelog Entry
  run: |
    DIFF=$(git diff origin/${{ github.base_ref }}...HEAD)
    claude -p "Generate a changelog entry for these changes: $DIFF" \
      --output-format json > changelog.json

Security Scanning:

- name: Security Scan
  run: |
    claude -p "Scan these files for security vulnerabilities: $FILES" \
      --output-format json \
      --model opus \  # Use Opus for security
      > security.json

11. Learning Milestones

Track your progress:

Milestone Description Verification
1 Workflow runs on PR See workflow in Actions tab
2 Claude executes successfully Check step logs for output
3 JSON output is valid jq .result review.json works
4 Comment appears on PR See comment on test PR
5 Costs are controlled Check Anthropic dashboard
6 Error handling works Force a failure and verify graceful handling

12. Common Pitfalls

12.1 Missing Permissions

# WRONG: No permissions specified
jobs:
  review:
    runs-on: ubuntu-latest
    # Claude runs but can't post comments!

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

12.2 Shallow Clone

# WRONG: Shallow clone can't compute diff
- uses: actions/checkout@v4
  # Default fetch-depth: 1

# RIGHT: Full history for diff
- uses: actions/checkout@v4
  with:
    fetch-depth: 0

12.3 Exposing Secrets in Logs

# WRONG: Secret might appear in error messages
- run: |
    echo "Using key: $ANTHROPIC_API_KEY"  # NEVER DO THIS
    claude -p "Review"

# RIGHT: Let the tool read from env
- run: |
    claude -p "Review"
  env:
    ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}

12.4 Not Handling Large Diffs

# Problem: diff too large for Claude context
DIFF=$(git diff origin/main...HEAD)  # Could be huge

# Solution: limit to file list and let Claude read them
FILES=$(git diff --name-only origin/main...HEAD | head -20)
claude -p "Review files: $FILES"  # Claude reads files itself

13. Extension Ideas

Once the basic pipeline works:

  1. Multi-stage review: Run Haiku first, escalate to Opus for issues
  2. Review caching: Skip re-review if files unchanged
  3. Metrics dashboard: Track issues found, false positives, cost
  4. Custom rules: Train Claude on your style guide
  5. IDE integration: Preview reviews before pushing
  6. Review queue: Handle high PR volume gracefully

14. Summary

This project teaches you to:

  • Use Claude Code in headless mode for automation
  • Integrate AI into GitHub Actions workflows
  • Parse structured JSON output
  • Control costs and handle errors gracefully
  • Build production-ready CI/CD components

The skills transfer directly to any CI/CD platform (GitLab, Azure DevOps, Jenkins) and any automation task where you need AI analysis without human interaction.

Key takeaway: Headless mode (-p flag) transforms Claude from an interactive tool into an automation component. Combined with structured output (--output-format json), you can build sophisticated AI-powered pipelines that integrate seamlessly with existing DevOps workflows.