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.
The exam will likely ask:
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:
or:
The CLI reference describes claude -p "query" as querying Claude Code and exiting, and also supports piping content into non-interactive runs. (Claude)
Bad CI pattern
Why bad:
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)
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'
Exam point:
Use
--output-format jsonand--json-schemawhen another CI step needs to parse Claude’s findings.
4. Example CI review command
SCHEMA='{
"type": "object",
"properties": {
"findings": {
"type": "array",
"items": {
"type": "object",
"properties": {
"file": { "type": "string" },
"line": { "type": "integer" },
"severity": { "type": "string", "enum": ["important", "nit"] },
"message": { "type": "string" },
"evidence": { "type": "string" }
},
"required": ["file", "line", "severity", "message"]
}
}
},
"required": ["findings"]
}'
git diff origin/main...HEAD | claude -p "
Review this diff for correctness bugs, security issues, broken edge cases, and regressions.
Only report issues introduced by this diff.
Do not report formatting, lint, or type errors that CI already checks.
Return findings matching the provided schema.
" \
--output-format json \
--json-schema "$SCHEMA" \
> claude-review.json
Then a later step can post comments:
jq -c '.structured_output.findings[]' claude-review.json | while read finding; do
file=$(echo "$finding" | jq -r '.file')
line=$(echo "$finding" | jq -r '.line')
message=$(echo "$finding" | jq -r '.message')
echo "Would post comment on $file:$line - $message"
done
5. 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.
6. 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)
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
7. 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.
Example with explicit context:
claude --bare -p "Review this diff using the rules in REVIEW_CONTEXT.md" \
--append-system-prompt-file REVIEW_CONTEXT.md \
--output-format json \
--json-schema "$SCHEMA"
8. 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)
Bad pattern
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)
9. Re-running reviews without duplicate comments
When CI reviews run on every push, duplicate findings are a real problem.
The official skill requirement:
Include prior review findings in context.
Ask Claude to report only new or still-unaddressed issues.
Example prompt:
You are re-running a PR review after new commits.
Prior review findings:
@prior-findings.json
Current diff:
@current-diff.patch
Instructions:
- Do not repeat findings that were already addressed.
- If a prior finding is still present, report it with status "still_unaddressed".
- If a finding is new in this diff, report it with status "new".
- Do not report old nits again unless they are correctness issues.
- Return only structured findings matching the schema.
Schema:
{
"type": "object",
"properties": {
"findings": {
"type": "array",
"items": {
"type": "object",
"properties": {
"status": {
"type": "string",
"enum": ["new", "still_unaddressed"]
},
"prior_finding_id": {
"type": ["string", "null"]
},
"file": { "type": "string" },
"line": { "type": "integer" },
"severity": {
"type": "string",
"enum": ["important", "nit"]
},
"message": { "type": "string" }
},
"required": ["status", "file", "line", "severity", "message"]
}
}
},
"required": ["findings"]
}
Claude Code’s Code Review docs include a similar “re-review convergence” idea: tell Claude how to behave after a PR has already been reviewed, such as suppressing repeated nits and reporting only important findings after the first review. (Claude)
10. Test generation in CI: provide existing tests
The official guide emphasizes:
Bad prompt:
Likely bad output:
Duplicates existing happy-path tests.
Misses actual coverage gaps.
Ignores fixture conventions.
Creates low-value tests.
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)
11. CI review prompt template
Review this pull request diff as an independent reviewer.
Use repository CLAUDE.md for:
- testing standards
- fixture conventions
- review criteria
- generated-file exclusions
Inputs:
- current diff: @diff.patch
- prior findings: @prior-findings.json
- existing related tests: @related-tests.txt
Rules:
1. Report only issues introduced by this PR.
2. Report only correctness bugs, security issues, regressions, or missing tests required by project standards.
3. Do not report formatting, lint, or type errors that CI already checks.
4. Do not duplicate prior findings.
5. If a prior finding is still unaddressed, mark it "still_unaddressed".
6. If the issue is new, mark it "new".
7. Return JSON matching the schema.
12. CI pipeline design pattern
1. Checkout repo.
2. Generate diff against base branch.
3. Collect related context:
- CLAUDE.md
- relevant test files
- prior review findings
- current failing test output, if any
4. Run Claude Code with -p.
5. Enforce --output-format json and --json-schema.
6. Parse structured_output.
7. Post inline comments or summary.
8. Save findings for next run to avoid duplicates.
13. Good vs bad examples
Bad: unstructured review
Problems:
No schema.
Hard to parse.
No severity.
No file/line guarantee.
May duplicate previous findings.
May report issues CI already covers.
Better: structured, contextual review
git diff origin/main...HEAD > diff.patch
claude -p "
Review @diff.patch as an independent CI reviewer.
Use CLAUDE.md for project standards.
Prior findings are in @prior-findings.json.
Report only new or still-unaddressed issues.
Return JSON matching the provided schema.
" \
--output-format json \
--json-schema "$REVIEW_SCHEMA" \
> claude-review.json
14. Scenario-based practice questions
Question 1
A CI job runs:
The job sometimes hangs waiting for input.
What is the best fix?
A) Add more prompt instructions.
B) Use claude -p or claude --print for non-interactive execution.
C) Add CLAUDE.md.
D) Rename the workflow.
Answer
B. CI needs non-interactive execution. The -p / --print flag runs the query and exits.
Question 2
A pipeline needs to post Claude’s review findings as inline PR comments. The current output is prose and hard to parse.
What should you use?
A) --output-format json and --json-schema.
B) Plan mode.
C) A longer prompt only.
D) Glob.
Answer
A. Structured output lets the pipeline parse file, line, severity, and message fields reliably.
Question 3
Claude’s CI-generated tests duplicate scenarios already covered in existing test files.
What should you provide?
A) Only the production source file.
B) Existing related test files and fixture conventions, with instructions not to duplicate covered scenarios.
C) No context; let Claude infer everything.
D) A generic “write good tests” instruction.
Answer
B. Claude needs existing tests and fixture conventions to identify true gaps instead of duplicating coverage.
Question 4
A repository wants CI-invoked Claude to follow project-specific testing standards and review criteria.
Where should the durable guidance live?
A) In CLAUDE.md.
B) Only in each workflow run’s prompt.
C) In a developer’s personal shell history.
D) In a random issue comment.
Answer
A. CLAUDE.md provides persistent project context and can include testing standards, review criteria, and fixture conventions.
Question 5
A CI review is re-run after a new commit and posts the same comments again.
What should you do?
A) Disable review re-runs.
B) Include prior findings in context and instruct Claude to report only new or still-unaddressed issues.
C) Remove JSON schema.
D) Ask Claude to be shorter.
Answer
B. Prior findings are needed for deduplication and re-review convergence.
Question 6
Claude generated a feature in one long session. You want a quality review before merging.
What is best?
A) Ask the same session to review its own work.
B) Use an independent review instance or fresh subagent context that sees the diff and review criteria.
C) Skip review because Claude wrote it.
D) Only run formatting.
Answer
B. A fresh reviewer sees the diff without the implementation session’s assumptions, making it better at catching gaps.
Question 7
A CI job uses --bare, then Claude ignores CLAUDE.md.
What happened?
A) --bare skips auto-discovered context such as CLAUDE.md.
B) CLAUDE.md is unsupported.
C) JSON schema disables project context.
D) -p cannot read files.
Answer
A. --bare is useful for hermetic scripts, but it skips CLAUDE.md unless you explicitly provide equivalent context.
Question 8
A workflow hardcodes an Anthropic API key in the YAML file.
What is wrong?
A) Nothing.
B) API keys should be stored in CI secrets and referenced from the workflow.
C) Claude Code cannot run in GitHub Actions.
D) The key should be in CLAUDE.md.
Answer
B. Use GitHub Secrets or the equivalent CI secret store. Do not commit credentials.
Question 9
Claude reports formatting and lint issues that are already enforced by CI, creating noisy PR comments.
What should you change?
A) Tell Claude to report only correctness/security/regression issues and skip findings already enforced by CI.
B) Remove the linter.
C) Use interactive mode.
D) Disable structured output.
Answer
A. The review prompt or CLAUDE.md / review guidance should define what counts as valuable findings.
Question 10
A pipeline wants to fail only when Claude reports important correctness issues, not nits.
What schema field is most useful?
A) severity with values like important and nit.
B) random_text.
C) model_temperature.
D) emoji.
Answer
A. Structured severity lets the pipeline decide whether to fail the build, post a warning, or ignore the issue.
15. High-yield D3.6 checklist
Memorize this:
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.
D3.6 mental model
-p prevents interactivity.
json + schema makes output parseable.
CLAUDE.md supplies project standards.
Prior findings prevent duplicate comments.
Existing tests prevent duplicate test suggestions.
Fresh review context catches what the generating session may miss.
The exam’s favorite distinction is:
Interactive Claude Code is for humans. CI Claude Code should be non-interactive, schema-constrained, context-aware, deduplicated, and independently reviewed.