Integrate Claude Code into CI/CD Pipelines
This module is about running Claude Code non-interactively in automation, producing machine-readable output, and keeping CI reviews high-signal.
How do you stop Claude Code from hanging in CI?
How do you force JSON output?
How do you make PR comments machine-parseable?
How do you avoid duplicate review comments on re-runs?
Why should a fresh review instance review generated code?
How does CLAUDE.md improve CI-invoked Claude behavior?
1. Core Mental Model
In CI/CD, Claude Code should behave like a deterministic pipeline step:
Input:
diff, files, test output, prior findings, project context
Claude Code invocation:
claude -p ... --output-format json --json-schema ...
Output:
structured findings that another script can parse and post as comments
Claude Code’s -p / --print flag runs a prompt non-interactively and exits, which is the key mode for scripts and CI jobs. The docs also show that --output-format json returns structured metadata, while --json-schema enforces a specific structured output shape in the structured_output field. (Claude)
2. Use -p / --print in CI
In CI, Claude Code must not wait for a human to type into an interactive terminal.
Use -p for non-interactive mode:
The CLI reference describes claude -p "query" as querying Claude Code and exiting, and also supports piping content into non-interactive runs. (Claude)
2.1 Bad CI Pattern
Why bad:
- Starts an interactive session.
- May wait for input.
- Can hang the CI job.
- Harder to parse output.
2.2 Correct CI Pattern
git diff origin/main...HEAD | claude -p "Review this diff for correctness bugs. Return concise findings."
Why good:
3. Structured Output: --output-format json + --json-schema
For CI, prose is hard to parse. Use structured output.
Basic JSON output:
Schema-constrained output:
claude -p "Extract review findings from this diff" \
--output-format json \
--json-schema '{
"type": "object",
"properties": {
"findings": {
"type": "array",
"items": {
"type": "object",
"properties": {
"file": { "type": "string" },
"line": { "type": "integer" },
"severity": {
"type": "string",
"enum": ["important", "nit"]
},
"title": { "type": "string" },
"description": { "type": "string" },
"suggested_fix": { "type": "string" }
},
"required": ["file", "line", "severity", "title", "description"]
}
}
},
"required": ["findings"]
}'
The docs state that --output-format json returns structured JSON with result, session ID, and metadata.
When paired with --json-schema, the schema-constrained answer appears in structured_output. (Claude)
3.1 Extracting Structured Output
RESULT=$(git diff origin/main...HEAD | claude -p "Review this diff" \
--output-format json \
--json-schema "$SCHEMA")
echo "$RESULT" | jq '.structured_output.findings'
Heuristic:
Use
--output-format jsonand--json-schemawhen another CI step needs to parse Claude’s findings.
4. GitHub Actions Integration
Claude Code can run through the official GitHub Action or through direct CLI scripting. The GitHub Actions docs show anthropics/claude-code-action@v1, including a prompt, anthropic_api_key, and optional claude_args. They also emphasize using GitHub Secrets rather than hardcoding API keys. (Claude)
Example:
name: Claude PR Review
on:
pull_request:
types: [opened, synchronize]
jobs:
claude-review:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Review PR with Claude
uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
prompt: |
Review this PR for correctness bugs, security issues, and regressions.
Use the repository CLAUDE.md for testing standards and review criteria.
claude_args: |
--max-turns 10
The exam’s likely emphasis is not GitHub Actions syntax itself. The emphasis is:
Use non-interactive execution.
Use secrets for credentials.
Use structured output when downstream automation parses results.
Use CLAUDE.md to supply durable project context.
5. CLAUDE.md As CI Context
CI-invoked Claude needs project-specific guidance just like interactive Claude.
Put this in CLAUDE.md:
# CI Review Guidance
## Testing Standards
- Prefer targeted tests over full-suite runs unless the change is cross-cutting.
- New API routes must include integration tests.
- Bug fixes should include regression tests.
## Valuable Test Criteria
Good tests:
- cover behavior, not implementation details
- include edge cases and failure modes
- use existing fixtures when available
- avoid duplicating scenarios already covered
Low-value tests:
- assert mocks were called without checking behavior
- snapshot large objects without meaningful intent
- duplicate existing fixture coverage
## Fixtures
- API fixtures live in test/fixtures/api/
- Billing fixtures live in test/fixtures/billing/
- Use existing factory helpers before creating new fixtures.
Claude Code docs say CLAUDE.md is loaded at the start of sessions and is the place for project instructions like Bash commands, code style, workflow rules, testing instructions, preferred test runners, and review checklists. They also recommend checking it into git so the team can share it. (Claude)
5.1 Why This Matters for CI
Without CLAUDE.md, Claude may generate generic review comments or generic tests.
With CLAUDE.md, Claude can know:
Which test runner to use
Where fixtures live
What counts as valuable test coverage
Which checks CI already enforces
Which review findings matter in this repo
Which files are generated and should be ignored
6. Important Nuance: --bare And CLAUDE.md
Current Claude Code docs recommend --bare for scripted calls when you want reproducible behavior, but --bare skips auto-discovery of hooks, skills, plugins, MCP servers, auto memory, and CLAUDE.md.
Without --bare, claude -p loads the same context an interactive session would, including working-directory and user configuration. (Claude)
Exam-safe distinction:
Need project CLAUDE.md context in CI?
Do not use --bare, or explicitly pass equivalent context.
Need hermetic scripted behavior with only explicit inputs?
Use --bare and pass the required context via flags/files.
7. Independent Review Instance Vs Same Session
The official statement says the same Claude session that generated code is less effective at reviewing its own changes than an independent review instance.
Why?
The generating session has the reasoning path that led to the implementation.
It may share the same assumptions that caused the bug.
It may evaluate intent instead of the actual diff.
It may overlook omissions because it “remembers” what it meant to do.
Claude Code’s best-practices docs recommend an adversarial review step: have a reviewer in a fresh context see only the diff and review criteria, not the reasoning that produced the change. The docs explicitly say the longer Claude works unattended, the more an independent check matters. (Claude)
7.1 Bad Pattern
7.2 Better Pattern
Session A:
Implement feature.
Session B / CI Claude:
Review the diff independently using CLAUDE.md, prior findings, and review schema.
This matches the code review architecture where independent review agents analyze the diff and surrounding code, then findings are verified and deduplicated. (Claude)
8. Test Generation in CI: Provide Existing Tests
The official guide emphasizes:
Better prompt:
Generate missing tests for checkoutService.
Context:
- Existing test file: @src/checkout/checkoutService.test.ts
- Shared fixtures: @test/fixtures/checkout.ts
- Testing standards: see CLAUDE.md
Instructions:
- Do not duplicate scenarios already covered.
- Identify coverage gaps first.
- Add only high-value tests for uncovered edge cases.
- Use existing fixtures and factories.
- Return a structured list of proposed tests before editing.
Claude Code best practices recommend providing specific context, pointing to existing patterns, and giving Claude verification checks such as tests/builds/linters that it can run and iterate against. (Claude)
9. Checklist
1. Use claude -p or claude --print for CI/non-interactive runs.
2. Avoid plain interactive claude in pipelines because it can hang.
3. Use --output-format json for machine-readable output.
4. Use --json-schema to enforce structured findings.
5. Parse structured_output, not free-form prose.
6. Use file, line, severity, message fields for PR comments.
7. Store API keys in CI secrets, never in repo files.
8. Use CLAUDE.md for testing standards, fixture conventions, and review criteria.
9. Provide existing test files so generated tests avoid duplicate coverage.
10. Include prior review findings on re-runs.
11. Ask Claude to report only new or still-unaddressed issues.
12. Use an independent reviewer/fresh context for review of Claude-generated code.
13. Do not rely on the same generation session to be the final reviewer.
14. Use --bare only when you want explicit, hermetic context; remember it skips CLAUDE.md.
15. Keep CI review prompts focused on issues CI cannot already catch.