Everything we have covered so far assumes you are sitting at a terminal, having a conversation with Claude. But some of the most powerful applications of Claude Code happen when no human is present at all. Automated PR reviews that run at 3 AM. Documentation that regenerates on every merge. Release notes that write themselves from commit history. This is where headless mode and CI/CD integration come in.
This lesson teaches you to run Claude Code programmatically, pipe its output through Unix tools, integrate it into GitHub Actions and GitLab CI pipelines, and build AI-powered automation workflows that work while you sleep.
Learning Objectives
- Run Claude Code in headless mode with the
-pflag for non-interactive automation - Control output formats (text, JSON, streaming) for different integration needs
- Pipe data into and out of Claude Code using standard Unix tools
- Set up the official GitHub Actions integration for automated PR review and code generation
- Configure GitLab CI/CD pipelines with Claude Code for merge request automation
Headless Mode: The -p Flag
Interactive mode is designed for humans. Headless mode is designed for machines. The -p (or --print) flag runs Claude Code non-interactively: it accepts a prompt, processes it, prints the result to stdout, and exits. No REPL, no follow-up questions, no interactive permission prompts.
claude -p "What does the auth module do?"This single command starts Claude, loads your project context (including CLAUDE.md), processes the prompt against your codebase, and returns the answer. It is the foundation for every automation pattern in this lesson.
Terminology note
The -p flag was previously called "headless mode" in earlier documentation. Anthropic now refers to it as the CLI mode of the Agent SDK. The behavior is identical: -p runs Claude non-interactively and returns output to stdout.
Auto-Approving Tools
In interactive mode, Claude asks for permission before running commands or editing files. In automation, there is no human to approve. Use --allowedTools to pre-authorize specific tools:
claude -p "Run the test suite and fix any failures" \
--allowedTools "Bash,Read,Edit"You can scope permissions tightly using prefix matching. The trailing space-asterisk pattern allows any command starting with that prefix:
claude -p "Look at my staged changes and create an appropriate commit" \
--allowedTools "Bash(git diff *),Bash(git log *),Bash(git status *),Bash(git commit *)"The space before the * matters. Bash(git diff *) matches git diff --staged and git diff HEAD. Without the space, Bash(git diff*) would also match unintended commands like git diff-index.
Security in automation
Never use --allowedTools "Bash" without restrictions in CI/CD. This gives Claude unrestricted shell access on your runner. Always scope to specific commands: Bash(npm test *), Bash(git *), etc. Think of --allowedTools as a security boundary, not a convenience toggle.
Customizing the System Prompt
You can append instructions to Claude's default system prompt or replace it entirely:
# Append security review instructions
gh pr diff "$PR_NUMBER" | claude -p \
--append-system-prompt "You are a security engineer. Review for vulnerabilities." \
--output-format json
# Fully replace the system prompt (advanced)
claude -p "Analyze this code" \
--system-prompt "You are a code quality reviewer. Output only issues found."Continuing Conversations
Headless mode supports multi-turn conversations by resuming sessions:
# First request
claude -p "Review this codebase for performance issues"
# Continue the most recent conversation
claude -p "Now focus on the database queries" --continue
# Or capture and resume a specific session
session_id=$(claude -p "Start a review" --output-format json | jq -r '.session_id')
claude -p "Continue that review" --resume "$session_id"This is useful for multi-stage pipelines where each step builds on the previous analysis.
Output Formats
Headless mode supports three output formats, each suited to different automation needs.
Plain Text (Default)
claude -p "Summarize this project"Returns human-readable text. Best for simple scripts, log output, and cases where you just need the answer.
Structured JSON
claude -p "Summarize this project" --output-format jsonReturns a JSON object containing the result text, session ID, usage metadata, and cost information. The text response lives in the result field. Use jq to extract it:
claude -p "Summarize this project" --output-format json | jq -r '.result'You can also enforce a specific response structure using JSON Schema. Claude will conform its output to your schema, and the structured data appears in the structured_output field:
claude -p "Extract the main function names from auth.py" \
--output-format json \
--json-schema '{"type":"object","properties":{"functions":{"type":"array","items":{"type":"string"}}},"required":["functions"]}' \
| jq '.structured_output'This is powerful for building toolchains where downstream scripts need predictable data shapes.
Streaming JSON
claude -p "Explain recursion" --output-format stream-json --verbose --include-partial-messagesReturns newline-delimited JSON objects as they are generated. Each line represents an event (text delta, tool call, result, etc.). This is ideal for real-time dashboards, progress indicators, or any system that needs to process tokens as they arrive.
Filter for just the streaming text:
claude -p "Write a poem" \
--output-format stream-json --verbose --include-partial-messages | \
jq -rj 'select(.type == "stream_event" and .event.delta.type? == "text_delta") | .event.delta.text'Unix Piping: Claude as a Pipeline Stage
Because headless mode reads from stdin and writes to stdout, Claude Code fits naturally into Unix pipelines. This is where automation gets creative.
Piping Input to Claude
# Analyze a file
cat src/auth.py | claude -p "Review this code for security issues"
# Review a PR diff
gh pr diff 42 | claude -p "Summarize the changes in this PR"
# Analyze test failures
npm test 2>&1 | claude -p "Explain why these tests are failing and suggest fixes"Piping Claude's Output
# Extract structured data and process it
claude -p "List all TODO comments in the codebase" \
--output-format json | jq -r '.result'
# Chain Claude with other tools
claude -p "Generate a changelog from the last 10 commits" \
--output-format json | jq -r '.result' > CHANGELOG.md
# Multi-stage pipeline
git diff HEAD~5..HEAD | \
claude -p "Identify breaking changes" --output-format json | \
jq -r '.result' | \
claude -p "Write migration instructions for these breaking changes"Practical Script Example
Here is a shell script that reviews all changed files in a PR:
#!/bin/bash
# review-pr.sh — AI-powered PR review
PR_NUMBER="${1:?Usage: review-pr.sh <pr-number>}"
# Get the diff and send it to Claude
gh pr diff "$PR_NUMBER" | claude -p \
"Review this pull request diff. For each file:
1. Note any bugs or logic errors
2. Flag security concerns
3. Suggest improvements
Format as markdown with file headers." \
--allowedTools "Read" \
--output-format json | jq -r '.result'GitHub Actions Integration
Anthropic provides an official GitHub Action, anthropics/claude-code-action, that brings Claude directly into your GitHub workflow. Claude can respond to @claude mentions in issues and PRs, automatically review code, and create pull requests.
Quick Setup
The fastest way to install is from within Claude Code itself:
/install-github-app
This command walks you through installing the Claude GitHub App and configuring the required secrets. For manual setup, follow these three steps:
Install the Claude GitHub App
Visit github.com/apps/claude and install it to your repository. The app requires read/write permissions for Contents, Issues, and Pull Requests.
Add your API key as a repository secret
Go to your repository's Settings, then Secrets and variables, then Actions. Add a new secret named ANTHROPIC_API_KEY with your Claude API key from console.anthropic.com.
Create the workflow file
Add a workflow file to .github/workflows/claude.yml in your repository.
Basic Workflow: Respond to @claude Mentions
This workflow listens for comments on issues and PRs. When someone writes @claude followed by a request, Claude responds:
name: Claude Code
on:
issue_comment:
types: [created]
pull_request_review_comment:
types: [created]
jobs:
claude:
runs-on: ubuntu-latest
steps:
- uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}That is the entire workflow. The action automatically detects @claude mentions and responds in context. Team members can now write comments like:
@claude implement this feature based on the issue description@claude fix the TypeError in the user dashboard component@claude how should I approach caching for this endpoint?
Automated PR Review on Every Push
This workflow runs a code review every time a PR is opened or updated:
name: Claude PR Review
on:
pull_request:
types: [opened, synchronize]
jobs:
review:
runs-on: ubuntu-latest
steps:
- uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
prompt: "/review"
claude_args: "--max-turns 5"The /review skill tells Claude to perform a structured code review. The --max-turns 5 flag limits how many iterations Claude takes, controlling both cost and runtime.
Scheduled Automation
You can also run Claude on a schedule for recurring tasks:
name: Daily Code Quality Report
on:
schedule:
- cron: "0 9 * * 1-5" # Weekdays at 9 AM UTC
jobs:
report:
runs-on: ubuntu-latest
steps:
- uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
prompt: "Generate a summary of yesterday's commits and open issues. Flag any PRs that have been open for more than 3 days."Passing CLI Arguments
The claude_args parameter accepts any Claude Code CLI flag:
- uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
prompt: "Review this PR for security vulnerabilities"
claude_args: |
--max-turns 10
--model claude-opus-4-6
--append-system-prompt "Focus on OWASP Top 10 vulnerabilities"Cost control
Always set --max-turns in CI/CD workflows. Without it, Claude defaults to 10 turns, which can be expensive on large codebases. For simple reviews, 3-5 turns is usually sufficient. For implementation tasks, 10-15 turns may be needed.
GitLab CI/CD Integration
Claude Code also integrates with GitLab pipelines. The setup uses the Claude Code CLI directly in your .gitlab-ci.yml instead of a pre-built action.
Beta status
Claude Code for GitLab CI/CD is currently in beta. The integration is maintained by GitLab. Features and configuration may evolve.
Basic GitLab Pipeline
stages:
- ai
claude:
stage: ai
image: node:24-alpine3.21
rules:
- if: '$CI_PIPELINE_SOURCE == "web"'
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
variables:
GIT_STRATEGY: fetch
before_script:
- apk update
- apk add --no-cache git curl bash
- curl -fsSL https://claude.ai/install.sh | bash
script:
- >
claude
-p "${AI_FLOW_INPUT:-'Review this MR and suggest improvements'}"
--permission-mode acceptEdits
--allowedTools "Bash Read Edit Write"
--debugThe key differences from GitHub Actions:
- You install Claude Code directly in the
before_scriptphase - The
ANTHROPIC_API_KEYis set as a masked CI/CD variable in GitLab settings (Settings > CI/CD > Variables) - Trigger context comes through
AI_FLOW_*variables when using mention-driven triggers - The
--permission-mode acceptEditsflag allows Claude to make file changes without interactive approval
Mention-Driven MR Reviews in GitLab
To enable @claude mentions in merge requests, configure a project webhook for "Comments (notes)" that triggers the pipeline with context variables. Claude analyzes the MR and pushes changes to the branch or responds in a comment. The workflow follows the same pattern:
- A team member writes
@claude fix the failing test in auth_spec.rb - A webhook triggers the pipeline with the comment as
AI_FLOW_INPUT - Claude runs, analyzes the MR, and implements the fix
- Changes appear as new commits on the MR branch
Common CI/CD Use Cases
Here are the automation patterns that deliver the most value in practice:
IDE Integration: Complementing the CLI
While this lesson focuses on CLI and CI/CD automation, it is worth noting that Claude Code also integrates with popular IDEs:
- VS Code: The Claude Code extension provides inline chat, code actions, and terminal integration directly in your editor. It uses the same Claude Code engine under the hood.
- JetBrains: A plugin is available for IntelliJ, WebStorm, PyCharm, and other JetBrains IDEs, bringing Claude Code's capabilities into the JetBrains ecosystem.
These IDE integrations complement CLI usage. Use the IDE extension for interactive development work and the CLI with -p for automation and scripting. Your CLAUDE.md files and project configuration are shared across both.
The Agent SDK: Programmatic Control
For advanced integrations beyond CLI scripting, Claude Code is available as a library through the Agent SDK. This gives you the same tools, agent loop, and context management as the CLI, but with full programmatic control from TypeScript or Python.
import { ClaudeCode } from "@anthropic-ai/claude-code";
const result = await ClaudeCode.run({
prompt: "Review the latest PR for security issues",
allowedTools: ["Read", "Bash(git *)"],
outputFormat: "json",
});
console.log(result.structured_output);The SDK supports structured outputs with JSON Schema validation, tool approval callbacks for fine-grained permission control, streaming with event callbacks, and native message objects for building custom UIs. See the Agent SDK documentation for the full API reference.
Build an AI-Powered PR Review Pipeline
intermediate30 minGoal: Create a GitHub Actions workflow that automatically reviews pull requests using Claude Code.
Steps:
- Create the workflow file at
.github/workflows/claude-review.yml:
name: Claude PR Review
on:
pull_request:
types: [opened, synchronize]
issue_comment:
types: [created]
permissions:
contents: read
pull-requests: write
issues: write
jobs:
review:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
prompt: |
Review this PR. For each changed file:
1. Check for bugs, logic errors, and edge cases
2. Flag any security concerns
3. Note style inconsistencies with the rest of the codebase
4. Suggest concrete improvements with code examples
Be constructive and specific. Skip nitpicks.
claude_args: "--max-turns 5"-
Add the
ANTHROPIC_API_KEYsecret to your repository settings. -
Install the Claude GitHub App from github.com/apps/claude.
-
Test the workflow by opening a pull request with a deliberate bug (e.g., an off-by-one error or missing null check). Verify that Claude posts a review comment identifying the issue.
-
Extend the workflow by adding a second job that runs only on merge to
main, using Claude to update the project changelog.
Bonus: Add @claude mention support by including the issue_comment trigger (already present in the workflow above). Test it by commenting @claude suggest a better approach for the error handling in this PR on an open PR.
Key Takeaway
The -p flag transforms Claude Code from an interactive assistant into a programmable automation tool. Combined with --output-format json for structured output, --allowedTools for scoped permissions, and Unix piping for composability, it becomes a building block for AI-powered development workflows. The official anthropics/claude-code-action GitHub Action and GitLab CI/CD integration make it straightforward to add automated PR reviews, documentation generation, and code quality checks to your existing pipelines. Start with a simple @claude mention workflow and expand from there.