Claude Code for GitHub Actions & CI/CD — Complete Guide
Claude Code is exceptionally useful for writing and debugging CI/CD pipelines — YAML is verbose, error messages are cryptic, and the feedback loop (push → wait → fail → read log → fix → push) is slow. With Claude Code, you describe what you want and Claude generates correct workflow YAML with proper job ordering, caching, and secrets handling. This guide covers CLAUDE.md setup for CI/CD repos, GitHub Actions workflow generation, GitLab CI, actionlint validation, and deployment pipeline patterns.
CI/CD CLAUDE.md Template
# Project: [Your Repository Name]
## CI/CD Platform
- Primary: GitHub Actions (.github/workflows/)
- Runtime: ubuntu-22.04 runners (or self-hosted — specify)
- Cloud: AWS (us-east-1) — ECR for images, ECS Fargate for services
## Application stack
- Language: Node.js 20 / TypeScript
- Build: npm ci + tsc
- Test: Jest (npm test)
- Docker: multi-stage Dockerfile, push to ECR
- Deploy: ECS task definition update via aws-cli
## CI conventions
- Pin all actions to full commit SHAs (not version tags) for security
- Use OIDC for AWS authentication (no long-lived IAM keys as secrets)
- Cache: npm ci cache keyed on package-lock.json hash
- Matrix: test on Node 18 and Node 20 for library packages
- Fail-fast: false on matrix (let all matrix jobs complete for full picture)
- Required checks: test, lint, typecheck — all must pass before merge
## Secrets (all set in repo/org settings — never hardcode)
- AWS_ROLE_TO_ASSUME: OIDC IAM role ARN
- ECR_REPOSITORY: ECR repository URL
- ECS_CLUSTER: cluster name
- ECS_SERVICE: service name
## Environments
- staging: auto-deploy on push to main
- production: manual approval gate required
actionlint Validation Hook
Validate workflow YAML locally after every edit so Claude sees errors immediately:
// .claude/settings.json
{
"allowedTools": ["Edit", "Write", "Bash", "Read", "Glob", "Grep"],
"hooks": [
{
"event": "PostToolUse",
"matcher": "Edit|Write",
"hooks": [{
"type": "command",
"command": "actionlint .github/workflows/ 2>&1 | head -30"
}]
}
]
}
Install actionlint:
brew install actionlint (macOS) or go install github.com/rhymond/actionlint/cmd/actionlint@latest. It catches invalid action references, type errors in expressions, missing required inputs, and shell script issues — all locally before pushing.YAML syntax check (no actionlint installed)
{
"event": "PostToolUse",
"matcher": "Write",
"hooks": [{
"type": "command",
"command": "python3 -c \"import yaml,sys; [yaml.safe_load(open(f)) for f in __import__('glob').glob('.github/workflows/*.yml')]; print('YAML valid')\" 2>&1"
}]
}
GitHub Actions Workflow Patterns
PR check workflow (Node.js)
claude "add a GitHub Actions CI workflow at .github/workflows/ci.yml.
Trigger: pull_request on main and develop branches.
Permissions: contents read, pull-requests write (for PR comments).
Jobs:
1. test: ubuntu-22.04, Node 20, npm ci (cached), npm test, upload coverage artifact
2. lint: ubuntu-22.04, Node 20, npm run lint
3. typecheck: ubuntu-22.04, Node 20, npm run typecheck
4. pr-comment: needs [test], post test coverage % as a PR comment using marocchino/sticky-pull-request-comment
All jobs run on every PR; fail the check if any job fails.
Pin all actions to commit SHAs."
Deploy to AWS ECS via OIDC
claude "add a deploy workflow at .github/workflows/deploy.yml.
Trigger: push to main.
Auth: AWS OIDC (aws-actions/configure-aws-credentials@SHA with role-to-assume: secrets.AWS_ROLE_TO_ASSUME)
Steps:
1. Configure AWS credentials (OIDC, region: us-east-1)
2. Login to ECR (aws-actions/amazon-ecr-login@SHA)
3. Build Docker image tagged with git SHA: docker build -t $ECR_URL:$GITHUB_SHA .
4. Push image to ECR
5. Update ECS task definition to use new image (aws-actions/amazon-ecs-render-task-definition@SHA)
6. Deploy to ECS service, wait for stability (aws-actions/amazon-ecs-deploy-task-definition@SHA)
No hardcoded values — all via secrets and env.
Pin all actions to SHA."
Matrix test strategy
claude "update the test job in ci.yml to use a matrix strategy.
Matrix: node-version [18, 20, 22], os [ubuntu-22.04, windows-latest].
fail-fast: false (run all matrix combinations even if one fails).
Cache npm on all OS using the built-in actions/cache with OS-specific key.
Upload test results artifact per matrix combination named test-results-${{ matrix.os }}-${{ matrix.node-version }}."
Debugging CI Failures with Claude Code
Paste the failing workflow YAML plus the error log into Claude Code. Common patterns:
| Failure type | Claude Code prompt |
|---|---|
| Permissions error | "This step fails with 'Resource not accessible by integration'. Here's the workflow YAML and error. Fix the permissions block." |
| Cache miss every run | "The npm cache never hits. Key: ${{ hashFiles('**/package-lock.json') }}. Workflow runs on ubuntu and windows. Fix the cache strategy." |
| Docker push 403 | "Docker push to ECR fails with 403. OIDC is configured. Here's the configure-aws-credentials step and the error. What's wrong?" |
| Action version breaking | "actions/checkout@v4 started failing. Convert all actions in this workflow to pinned SHA references." |
| Flaky tests in CI | "Tests pass locally but fail in CI ~30% of the time with this error. Identify the race condition." |
| Long pipeline runtime | "This pipeline takes 18 minutes. Identify the bottlenecks and restructure jobs to maximize parallelism." |
GitLab CI Pipelines
# CLAUDE.md additions for GitLab CI
## CI Platform
- GitLab CI (.gitlab-ci.yml)
- Runner: GitLab-hosted shared runners (linux/amd64) or self-hosted (specify)
- Stages: test → build → deploy-staging → deploy-production
- Rules: MR pipelines run test+lint; push to main adds build+deploy-staging
- Production deploy: manual (when: manual) with environment: production
## Variables (all set in project CI/CD settings)
- AWS_ROLE_ARN: OIDC assume-role ARN
- ECR_REPOSITORY: ECR URL
- KUBE_CONTEXT: kubectl context for production cluster
## Features used
- include: for reusable job templates
- extends: for DRY job configurations
- needs: (DAG) for parallel job execution
- artifacts:reports:junit for test result visualization in MR
- environments for Review Apps on feature branches
claude "write a .gitlab-ci.yml for a Python Django service.
Stages: test, lint, build, deploy-staging, deploy-production.
test job: python:3.12-slim, install deps with pip, run pytest with JUnit XML output artifact.
lint job: run black --check and ruff (parallel to test via needs: []).
build job: needs: [test, lint], build Docker image, push to ECR using OIDC.
deploy-staging job: needs: [build], kubectl set image on staging namespace, auto on main.
deploy-production job: needs: [deploy-staging], manual gate, kubectl set image on prod namespace.
Use extends: .aws-oidc-setup for the OIDC boilerplate."
Reusable Workflows & Composite Actions
claude "extract the docker-build-and-push steps from ci.yml into a reusable workflow
at .github/workflows/docker-build.yml (workflow_call trigger).
Inputs: image-name (required), tag (required, default: ${{ github.sha }}).
Outputs: image-url (the full ECR URL with tag).
Call it from the deploy workflow with 'uses: ./.github/workflows/docker-build.yml'.
This lets 3 other workflows reuse the same Docker build logic."
claude "create a composite action at .github/actions/setup-node/action.yml.
Steps: checkout, setup-node (Node 20), npm ci with cache, restore build cache.
Accept input: node-version (default: '20').
Replace the 4 repeated setup steps in all 3 jobs in ci.yml with:
uses: ./.github/actions/setup-node"
5 Tips for GitHub Actions + Claude Code
- Always paste your existing
package.jsonorrequirements.txtinto CLAUDE.md. Claude will then use the exact same Node/Python version in the workflow as your local environment, preventing "works locally, fails in CI" mismatches. - When debugging failures, paste the full job log output, not just the failing line. Context 10–20 lines before the error often contains the real cause — a missing tool, wrong working directory, or environment variable that wasn't set.
- Tell Claude your organization's security requirements up front: "Pin actions to SHA, use OIDC for cloud auth, add permissions block to every workflow." Claude will then generate compliant workflows by default rather than requiring corrections after the fact.
- Use
act(nektos/act) locally with a PostToolUse hook to run workflow jobs without pushing. This reduces the push-and-wait feedback loop to seconds for simple jobs that don't require cloud credentials. - For complex multi-job workflows, ask Claude to draw the dependency graph first: "Describe the job dependency order and which jobs run in parallel." Review the description before generating YAML — it's easier to catch logic errors in plain English than in nested YAML.