Skip to main content
Integrate Claude into your CI/CD pipeline for automated PR reviews, changelog generation, code refactoring, and more.

What You’ll Build

Automated workflows that:
  • Review pull requests and suggest improvements
  • Generate changelogs from commits
  • Refactor code on schedule
  • Run code analysis and security audits

Architecture

Two Approaches

There are two ways to give Claude access to your code in CI/CD:
  1. Possession Mode - Claude reads files directly from the runner via --allow-possession
  2. Deploy Workspace - Upload code to Chucky cloud with chucky deploy, then run jobs
Possession Mode is simpler for quick tasks. Deploy is better for complex operations or when you want changes tracked in git bundles.

GitHub Actions Examples

PR Review Bot

# .github/workflows/ai-review.yml
name: AI Code Review

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 Chucky CLI
        run: npm install -g @chucky.cloud/cli

      - name: Run AI Review
        env:
          CHUCKY_API_KEY: ${{ secrets.CHUCKY_API_KEY }}
        run: |
          chucky prompt "Review the code changes in this PR for:
          - Security vulnerabilities
          - Performance issues
          - Code style improvements
          - Potential bugs

          Focus on files changed in this PR. Provide specific, actionable feedback." \
          --allow-possession \
          --dangerously-skip-permissions \
          --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'));

            await github.rest.issues.createComment({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: context.issue.number,
              body: `## AI Code Review\n\n${review.result}\n\n---\n*Powered by Chucky*`
            });

Changelog Generator

# .github/workflows/changelog.yml
name: Generate Changelog

on:
  release:
    types: [created]

jobs:
  changelog:
    runs-on: ubuntu-latest
    permissions:
      contents: write

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

      - name: Install Chucky CLI
        run: npm install -g @chucky.cloud/cli

      - name: Get commits since last release
        id: commits
        run: |
          LAST_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "")
          if [ -n "$LAST_TAG" ]; then
            COMMITS=$(git log $LAST_TAG..HEAD --oneline)
          else
            COMMITS=$(git log --oneline -50)
          fi
          echo "commits<<EOF" >> $GITHUB_OUTPUT
          echo "$COMMITS" >> $GITHUB_OUTPUT
          echo "EOF" >> $GITHUB_OUTPUT

      - name: Generate Changelog
        env:
          CHUCKY_API_KEY: ${{ secrets.CHUCKY_API_KEY }}
        run: |
          chucky prompt "Generate a user-friendly changelog from these commits:

          ${{ steps.commits.outputs.commits }}

          Format as:
          ## What's New
          - Feature descriptions

          ## Bug Fixes
          - Fix descriptions

          ## Other Changes
          - Other changes

          Be concise. Group related changes. Use plain language." \
          --output-format json > changelog.json

      - name: Update Release
        uses: actions/github-script@v7
        with:
          script: |
            const fs = require('fs');
            const changelog = JSON.parse(fs.readFileSync('changelog.json', 'utf8'));

            await github.rest.repos.updateRelease({
              owner: context.repo.owner,
              repo: context.repo.repo,
              release_id: context.payload.release.id,
              body: changelog.result
            });

Automated Refactoring

# .github/workflows/refactor.yml
name: AI Refactoring

on:
  workflow_dispatch:
    inputs:
      task:
        description: 'Refactoring task'
        required: true
        default: 'Update deprecated API usage'
      path:
        description: 'Path to refactor (glob pattern)'
        required: true
        default: 'src/**/*.ts'

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

    steps:
      - uses: actions/checkout@v4

      - name: Install Chucky CLI
        run: npm install -g @chucky.cloud/cli

      - name: Deploy workspace
        env:
          CHUCKY_API_KEY: ${{ secrets.CHUCKY_API_KEY }}
        run: chucky deploy

      - name: Run Refactoring
        env:
          CHUCKY_API_KEY: ${{ secrets.CHUCKY_API_KEY }}
        run: |
          chucky jobs create "${{ github.event.inputs.task }} in files matching ${{ github.event.inputs.path }}" \
            --wait --apply

      - name: Create Pull Request
        uses: peter-evans/create-pull-request@v5
        with:
          token: ${{ secrets.GITHUB_TOKEN }}
          commit-message: "refactor: ${{ github.event.inputs.task }}"
          title: "AI Refactoring: ${{ github.event.inputs.task }}"
          body: |
            This PR was automatically generated by AI refactoring.

            **Task:** ${{ github.event.inputs.task }}
            **Path:** ${{ github.event.inputs.path }}

            Please review the changes carefully.
          branch: ai-refactor-${{ github.run_id }}

Security Audit

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

on:
  schedule:
    - cron: '0 0 * * 0' # Weekly on Sunday
  workflow_dispatch:

jobs:
  audit:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Install Chucky CLI
        run: npm install -g @chucky.cloud/cli

      - name: Run Security Audit
        env:
          CHUCKY_API_KEY: ${{ secrets.CHUCKY_API_KEY }}
        run: |
          chucky prompt "Perform a security audit of this codebase. Look for:

          1. SQL injection vulnerabilities
          2. XSS vulnerabilities
          3. Authentication/authorization issues
          4. Sensitive data exposure
          5. Insecure dependencies
          6. Hardcoded secrets
          7. CSRF vulnerabilities

          For each issue found, provide:
          - File and line number
          - Severity (Critical/High/Medium/Low)
          - Description
          - Recommended fix

          Format as a security report." \
          --allow-possession \
          --dangerously-skip-permissions \
          --output-format json > audit.json

      - name: Create Issue
        uses: actions/github-script@v7
        with:
          script: |
            const fs = require('fs');
            const audit = JSON.parse(fs.readFileSync('audit.json', 'utf8'));

            await github.rest.issues.create({
              owner: context.repo.owner,
              repo: context.repo.repo,
              title: `Security Audit - ${new Date().toISOString().split('T')[0]}`,
              body: `## Weekly Security Audit\n\n${audit.result}`,
              labels: ['security', 'automated']
            });

GitLab CI Examples

MR Review

# .gitlab-ci.yml
ai-review:
  stage: review
  image: node:20
  script:
    - npm install -g @chucky.cloud/cli
    - |
      chucky prompt "Review the code changes in this merge request.
      Focus on code quality and potential issues." \
      --allow-possession \
      --dangerously-skip-permissions \
      --output-format json > review.json
    - |
      # Post to GitLab MR
      curl --request POST \
        --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
        --data "body=$(cat review.json | jq -r .result)" \
        "$CI_API_V4_URL/projects/$CI_PROJECT_ID/merge_requests/$CI_MERGE_REQUEST_IID/notes"
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
  variables:
    CHUCKY_API_KEY: $CHUCKY_API_KEY

Using Background Jobs

For long-running tasks, use background jobs with webhooks:
# .github/workflows/background-task.yml
name: Background AI Task

on:
  workflow_dispatch:
    inputs:
      task:
        description: 'Task description'
        required: true

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

      - name: Start Background Job
        env:
          CHUCKY_API_KEY: ${{ secrets.CHUCKY_API_KEY }}
        run: |
          npm install -g @chucky.cloud/cli
          chucky deploy

          # Start job with webhook callback
          chucky jobs create "${{ github.event.inputs.task }}" \
            --callback-url "${{ secrets.WEBHOOK_URL }}" \
            --callback-secret "${{ secrets.WEBHOOK_SECRET }}"
Then handle the webhook in your server:
// api/webhooks/chucky.ts
import crypto from 'crypto';

export async function POST(req: Request) {
  const signature = req.headers.get('x-chucky-signature');
  const body = await req.text();

  // Verify signature
  const expected = crypto
    .createHmac('sha256', process.env.WEBHOOK_SECRET!)
    .update(body)
    .digest('hex');

  if (signature !== expected) {
    return new Response('Invalid signature', { status: 401 });
  }

  const payload = JSON.parse(body);

  if (payload.type === 'job.completed') {
    // Job finished - create PR, post comment, etc.
    await handleJobCompletion(payload);
  }

  return new Response('OK');
}

Best Practices

1. Set Budget Limits

- name: Run AI Task
  env:
    CHUCKY_API_KEY: ${{ secrets.CHUCKY_API_KEY }}
  run: |
    chucky prompt "..." --max-budget-usd 1.00

2. Handle Failures Gracefully

- name: Run AI Review
  id: review
  continue-on-error: true
  run: chucky prompt "..."

- name: Handle Failure
  if: steps.review.outcome == 'failure'
  run: echo "AI review failed, continuing without it"

3. Cache Workspace

- name: Cache Chucky workspace
  uses: actions/cache@v3
  with:
    path: ~/.chucky
    key: chucky-${{ runner.os }}-${{ hashFiles('.chucky.json') }}

4. Use Secrets Properly

env:
  CHUCKY_API_KEY: ${{ secrets.CHUCKY_API_KEY }}
  # Never echo or log this

5. Rate Limit AI Calls

# Only run on specific conditions
on:
  pull_request:
    types: [opened] # Not on every push
    paths:
      - 'src/**' # Only when source changes

Common Tasks

All commands below assume --allow-possession --dangerously-skip-permissions flags:
TaskCommand
PR Reviewchucky prompt "Review this PR for issues"
Generate Testschucky prompt "Generate unit tests for changed files"
Update Docschucky prompt "Update README based on recent changes"
Fix Lintingchucky prompt "Fix all ESLint errors"
Translatechucky prompt "Translate strings to Spanish"
Deprecationchucky prompt "Update deprecated API usage"
Add --apply to automatically apply changes from the git bundle after Claude makes modifications.

Next Steps