Back to all articles
12 MIN READ

Claude Code GitHub Actions: AI-Powered CI/CD Automation

By Learnia Team

Claude Code GitHub Actions: AI-Powered CI/CD Automation

This article is written in English. Our training modules are available in French.

GitHub Actions brings Claude Code into your CI/CD pipeline. Automate code reviews, generate PR descriptions, triage issues, and even implement features—all triggered by GitHub events. This is AI-powered development at scale.


What Can Claude Code Do in CI/CD?

Use CaseTriggerAction
Code ReviewPull RequestReview changes, suggest improvements
PR DescriptionPull RequestGenerate detailed PR descriptions
Issue TriageIssue CreatedCategorize, prioritize, assign
Bug FixingIssue LabeledAnalyze and create fix PR
DocumentationCode ChangedUpdate docs automatically
Test GenerationCode ChangedCreate tests for new code
Security ScanPull RequestCheck for vulnerabilities
Dependency UpdatesScheduleReview and update dependencies

Getting Started

Prerequisites

  1. GitHub repository
  2. Anthropic API key
  3. GitHub App installed (optional, for enhanced features)

Install GitHub App

The easiest setup uses the Claude GitHub App:

> /install-github-app

Opening GitHub to install Claude Code App...

1. Select repositories to grant access
2. Confirm permissions
3. Copy the installation token

Installation complete. Your workflows can now use Claude Code.

Manual Setup

For API key-based access:

  1. Add your Anthropic API key to repository secrets:

    • Go to Settings → Secrets → Actions
    • Add
      ANTHROPIC_API_KEY
  2. Create workflow file in

    .github/workflows/


Basic Workflow Structure

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

on:
  pull_request:
    types: [opened, synchronize]

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 Claude Code
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
        run: |
          claude --print --dangerously-skip-permissions \
            -p "Review the changes in this PR and comment on issues"

Code Review Workflow

Automated code review on every pull request:

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

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

permissions:
  contents: read
  pull-requests: write

jobs:
  review:
    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: Get changed files
        id: changed
        run: |
          echo "files=$(git diff --name-only origin/${{ github.base_ref }}...HEAD | tr '\n' ' ')" >> $GITHUB_OUTPUT
      
      - name: Review code
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
        run: |
          claude --print --dangerously-skip-permissions \
            -p "Review these changed files for:
                - Code quality issues
                - Potential bugs
                - Security vulnerabilities
                - Performance concerns
                - Style guide compliance
                
                Files: ${{ steps.changed.outputs.files }}
                
                Format your review as markdown with sections for each category.
                Include line numbers for specific issues." > review.md
      
      - name: Post review comment
        uses: actions/github-script@v7
        with:
          script: |
            const fs = require('fs');
            const review = fs.readFileSync('review.md', 'utf8');
            
            github.rest.issues.createComment({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: context.issue.number,
              body: `## 🤖 AI Code Review\n\n${review}`
            });

Enhanced Review with Inline Comments

- name: Review with inline comments
  env:
    ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
    GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
  run: |
    claude --print --dangerously-skip-permissions \
      -p "Review this PR and for each issue found, output JSON:
          {\"file\": \"path/to/file\", \"line\": 42, \"comment\": \"Issue description\"}
          
          One JSON object per line." > issues.jsonl
    
    # Post inline comments
    while IFS= read -r line; do
      file=$(echo "$line" | jq -r '.file')
      line_num=$(echo "$line" | jq -r '.line')
      comment=$(echo "$line" | jq -r '.comment')
      
      gh pr comment ${{ github.event.pull_request.number }} \
        --body "**Line $line_num in $file**: $comment"
    done < issues.jsonl

PR Description Generator

Auto-generate detailed PR descriptions:

# .github/workflows/pr-description.yml
name: Generate PR Description

on:
  pull_request:
    types: [opened]

permissions:
  pull-requests: write

jobs:
  describe:
    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 description
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
        run: |
          git diff origin/${{ github.base_ref }}...HEAD > changes.diff
          
          claude --print --dangerously-skip-permissions \
            -p "Based on this diff, generate a detailed PR description:
                
                $(cat changes.diff)
                
                Include:
                ## Summary
                Brief overview of changes
                
                ## Changes Made
                - Bullet points of specific changes
                
                ## Testing
                How to test these changes
                
                ## Screenshots
                (if UI changes, note what screenshots would be helpful)
                
                ## Related Issues
                Mention any issue numbers if apparent from code" > description.md
      
      - name: Update PR description
        uses: actions/github-script@v7
        with:
          script: |
            const fs = require('fs');
            const description = fs.readFileSync('description.md', 'utf8');
            
            github.rest.pulls.update({
              owner: context.repo.owner,
              repo: context.repo.repo,
              pull_number: context.issue.number,
              body: description
            });

Issue Triage Bot

Automatically categorize and assign issues:

# .github/workflows/issue-triage.yml
name: Issue Triage

on:
  issues:
    types: [opened]

permissions:
  issues: write

jobs:
  triage:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Install Claude Code
        run: npm install -g @anthropic-ai/claude-code
      
      - name: Analyze issue
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
        run: |
          claude --print --dangerously-skip-permissions \
            -p "Analyze this GitHub issue and provide triage:
                
                Title: ${{ github.event.issue.title }}
                Body: ${{ github.event.issue.body }}
                
                Return JSON only:
                {
                  \"labels\": [\"bug\"|\"feature\"|\"documentation\"|\"question\"],
                  \"priority\": \"low\"|\"medium\"|\"high\"|\"critical\",
                  \"component\": \"frontend\"|\"backend\"|\"api\"|\"infra\"|\"other\",
                  \"summary\": \"One line summary\",
                  \"suggested_assignee\": \"team-area or null\"
                }" > triage.json
      
      - name: Apply triage
        uses: actions/github-script@v7
        with:
          script: |
            const fs = require('fs');
            const triage = JSON.parse(fs.readFileSync('triage.json', 'utf8'));
            
            // Add labels
            const labels = [...triage.labels, `priority:${triage.priority}`];
            await github.rest.issues.addLabels({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: context.issue.number,
              labels: labels
            });
            
            // Add triage comment
            await github.rest.issues.createComment({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: context.issue.number,
              body: `🤖 **Automated Triage**\n\n` +
                    `**Summary:** ${triage.summary}\n` +
                    `**Component:** ${triage.component}\n` +
                    `**Priority:** ${triage.priority}`
            });

Automated Bug Fixing

Create fix PRs for labeled issues:

# .github/workflows/auto-fix.yml
name: Auto Fix Bug

on:
  issues:
    types: [labeled]

permissions:
  contents: write
  pull-requests: write
  issues: write

jobs:
  fix:
    if: github.event.label.name == 'auto-fix'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Install Claude Code
        run: npm install -g @anthropic-ai/claude-code
      
      - name: Create fix branch
        run: |
          git checkout -b fix/issue-${{ github.event.issue.number }}
      
      - name: Analyze and fix
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
        run: |
          claude --dangerously-skip-permissions \
            -p "Fix this issue:
                
                Title: ${{ github.event.issue.title }}
                Description: ${{ github.event.issue.body }}
                
                1. Find the relevant code
                2. Implement the fix
                3. Add or update tests
                4. Ensure code passes linting
                
                Make the minimal changes needed to fix the issue."
      
      - name: Commit and push
        run: |
          git config user.name "Claude Code Bot"
          git config user.email "claude@example.com"
          git add -A
          git commit -m "Fix: ${{ github.event.issue.title }}" || exit 0
          git push origin fix/issue-${{ github.event.issue.number }}
      
      - name: Create pull request
        uses: actions/github-script@v7
        with:
          script: |
            const pr = await github.rest.pulls.create({
              owner: context.repo.owner,
              repo: context.repo.repo,
              title: `Fix: ${{ github.event.issue.title }}`,
              body: `Automated fix for #${{ github.event.issue.number }}\n\nGenerated by Claude Code`,
              head: `fix/issue-${{ github.event.issue.number }}`,
              base: 'main'
            });
            
            // Link PR to issue
            await github.rest.issues.createComment({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: context.issue.number,
              body: `🤖 Created fix PR: #${pr.data.number}`
            });

Test Generation

Generate tests for new code:

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

on:
  pull_request:
    types: [opened, synchronize]
    paths:
      - 'src/**/*.ts'
      - 'src/**/*.js'

permissions:
  contents: write
  pull-requests: write

jobs:
  generate-tests:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ github.head_ref }}
          fetch-depth: 0
      
      - name: Install dependencies
        run: npm install
      
      - name: Install Claude Code
        run: npm install -g @anthropic-ai/claude-code
      
      - name: Get changed source files
        id: changed
        run: |
          files=$(git diff --name-only origin/${{ github.base_ref }}...HEAD | grep -E 'src/.*\.(ts|js)$' | grep -v '\.test\.' | tr '\n' ' ')
          echo "files=$files" >> $GITHUB_OUTPUT
      
      - name: Generate tests
        if: steps.changed.outputs.files != ''
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
        run: |
          claude --dangerously-skip-permissions \
            -p "Generate comprehensive tests for these changed files:
                ${{ steps.changed.outputs.files }}
                
                For each file:
                1. Create a corresponding .test.ts file if it doesn't exist
                2. Add tests for new functions/methods
                3. Include edge cases and error scenarios
                4. Follow existing test patterns in the codebase
                
                Run 'npm test' to verify tests pass."
      
      - name: Commit test files
        run: |
          git config user.name "Claude Code Bot"
          git config user.email "claude@example.com"
          git add -A '*.test.*'
          git commit -m "Add generated tests" || exit 0
          git push

Documentation Updates

Keep docs in sync with code:

# .github/workflows/update-docs.yml
name: Update Documentation

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

permissions:
  contents: write

jobs:
  update-docs:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Install Claude Code
        run: npm install -g @anthropic-ai/claude-code
      
      - name: Update API docs
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
        run: |
          claude --dangerously-skip-permissions \
            -p "Update the API documentation in docs/API.md:
                
                1. Scan all files in src/api/
                2. Extract endpoint definitions
                3. Document request/response formats
                4. Include example usage
                5. Note any breaking changes
                
                Keep the existing documentation structure."
      
      - name: Commit doc updates
        run: |
          git config user.name "Claude Code Bot"
          git config user.email "claude@example.com"
          git add docs/
          git commit -m "Update API documentation" || exit 0
          git push

Security Scanning

AI-powered security review:

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

on:
  pull_request:
    types: [opened, synchronize]

permissions:
  pull-requests: write
  security-events: write

jobs:
  security:
    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: Security analysis
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
        run: |
          git diff origin/${{ github.base_ref }}...HEAD > changes.diff
          
          claude --print --dangerously-skip-permissions \
            -p "Perform a security review of these changes:
                
                $(cat changes.diff)
                
                Check for:
                1. SQL injection vulnerabilities
                2. XSS vulnerabilities
                3. Exposed secrets or credentials
                4. Insecure dependencies
                5. Authentication/authorization issues
                6. Data validation problems
                7. CSRF vulnerabilities
                8. Path traversal risks
                
                Format as:
                ## Security Review
                
                ### Critical Issues
                (blocking issues)
                
                ### Warnings
                (should fix)
                
                ### Notes
                (informational)
                
                ### Verdict
                PASS / FAIL" > security.md
      
      - name: Post security review
        uses: actions/github-script@v7
        with:
          script: |
            const fs = require('fs');
            const review = fs.readFileSync('security.md', 'utf8');
            
            github.rest.issues.createComment({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: context.issue.number,
              body: `## 🔒 Security Review\n\n${review}`
            });
      
      - name: Check for failures
        run: |
          if grep -q "### Verdict" security.md && grep -q "FAIL" security.md; then
            echo "Security review failed"
            exit 1
          fi

Scheduled Tasks

Run Claude Code on a schedule:

# .github/workflows/weekly-audit.yml
name: Weekly Code Audit

on:
  schedule:
    - cron: '0 9 * * 1'  # Monday 9 AM
  workflow_dispatch:

permissions:
  issues: write

jobs:
  audit:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Install Claude Code
        run: npm install -g @anthropic-ai/claude-code
      
      - name: Run audit
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
        run: |
          claude --print --dangerously-skip-permissions \
            -p "Perform a comprehensive code audit:
                
                1. Check for TODO/FIXME comments that are stale
                2. Identify unused exports and dead code
                3. Find potential performance issues
                4. Check for outdated dependencies
                5. Review error handling completeness
                6. Identify code duplication
                
                Provide a summary report with actionable items." > audit.md
      
      - name: Create audit issue
        uses: actions/github-script@v7
        with:
          script: |
            const fs = require('fs');
            const audit = fs.readFileSync('audit.md', 'utf8');
            
            github.rest.issues.create({
              owner: context.repo.owner,
              repo: context.repo.repo,
              title: `Weekly Code Audit - ${new Date().toISOString().split('T')[0]}`,
              body: audit,
              labels: ['audit', 'automated']
            });

Workflow Tips

Caching for Speed

- name: Cache Claude Code
  uses: actions/cache@v4
  with:
    path: ~/.npm
    key: claude-code-${{ runner.os }}

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

Rate Limiting

Prevent excessive API usage:

jobs:
  review:
    # Only run on real PRs, not drafts
    if: github.event.pull_request.draft == false
    
    # Concurrency prevents parallel runs
    concurrency:
      group: claude-${{ github.ref }}
      cancel-in-progress: true

Environment Variables

Pass context to Claude:

- name: Run with context
  env:
    ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
    PR_TITLE: ${{ github.event.pull_request.title }}
    PR_AUTHOR: ${{ github.event.pull_request.user.login }}
    BASE_BRANCH: ${{ github.base_ref }}
  run: |
    claude --print --dangerously-skip-permissions \
      -p "Review this PR titled '$PR_TITLE' by $PR_AUTHOR..."

Conditional Execution

- name: Review only large PRs
  if: github.event.pull_request.additions > 100
  run: claude ...

- name: Skip bot PRs
  if: "!contains(github.event.pull_request.user.login, 'bot')"
  run: claude ...

Security Considerations

API Key Protection

# Use GitHub Secrets
env:
  ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}

# Never echo keys
- run: echo "Key length: ${#ANTHROPIC_API_KEY}"  # OK
- run: echo "$ANTHROPIC_API_KEY"  # NEVER DO THIS

Permission Scoping

# Minimal permissions
permissions:
  contents: read
  pull-requests: write
  
# Not this
permissions: write-all

Sandboxed Execution

# Claude runs with --dangerously-skip-permissions
# Ensure workflows can't escape their scope

- name: Run in isolated directory
  run: |
    mkdir -p /tmp/workspace
    cp -r . /tmp/workspace
    cd /tmp/workspace
    claude --dangerously-skip-permissions ...

Review Generated Code

Always require human approval for generated changes:

# Create PR instead of direct push
- name: Create PR
  run: |
    gh pr create --title "AI Generated Changes" \
      --body "⚠️ Review required - generated by Claude Code"

Integration with Other Features

Using MCP in Actions

- name: Setup MCP
  run: |
    claude mcp add github --transport http https://api.github.com/mcp/
  env:
    GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

See Model Context Protocol (MCP) for Claude Code: Complete Guide.

Using Custom Commands

- name: Run custom command
  run: |
    claude --dangerously-skip-permissions -p "/review"

See Custom Slash Commands in Claude Code: Build Your Own.

Headless SDK Usage

For complex workflows, use the SDK:

- name: Run SDK script
  run: node scripts/claude-workflow.js

See Headless & Programmatic Claude Code: SDK & Automation.


Key Takeaways

  1. Automate reviews: Let AI catch issues before humans review.

  2. Generate content: PR descriptions, docs, tests—all automated.

  3. Triage at scale: Handle issues automatically.

  4. Security first: Use minimal permissions, protect API keys.

  5. Human in the loop: AI creates PRs; humans approve them.


Master AI-Powered Automation

GitHub Actions with Claude Code is just the beginning of AI automation. Learn to build complete autonomous workflows.

In our Module 6 — Autonomous Agents, you'll learn:

  • Designing reliable AI workflows
  • Error handling and recovery
  • Human-in-the-loop patterns
  • Scaling AI automation

Explore Module 6: Autonomous Agents

GO DEEPER

Module 6 — AI Agents & ReAct

Create autonomous agents that reason and take actions.