Guide

Headless Claude Code in Scripts and CI

Run Claude Code non-interactively using the print flag, stdin piping, and CI/CD automation pipelines.

~8 min read

Most developers interact with Claude Code as a conversational terminal session. You ask questions, review diffs, and approve commands interactively. But when you want to run code reviews on every pull request, verify documentation during nightly builds, or audit migrations automatically, an interactive prompt is a blocker.

Claude Code supports full non-interactive execution through its `-p` (print) flag. In headless mode, Claude Code accepts input from command arguments or standard input, loads your project context and skills, executes necessary tools autonomously, prints the final response to standard output, and exits cleanly.

The -p flag: non-interactive execution

The `-p` flag turns Claude Code into a scriptable CLI command that integrates seamlessly into standard bash, zsh, and PowerShell pipelines.

Command: claude -p "summarize the architecture of this repository in three bullet points"
Output: - Monorepo structure with Next.js frontend and Fastify API backend
Output: - PostgreSQL database managed through Prisma migrations in packages/db
Output: - Shared TypeScript interfaces and validation schemas in packages/shared
Note: The command executed tools silently, printed the answer, and returned control.
Execute a headless query and capture output directly.

Piping input from git diffs, linters, and test runners

Because headless mode reads from standard input, you can pipe output from other developer tools directly into Claude Code for analysis.

Command: git diff origin/main...HEAD | claude -p "flag any security or credential leaks in this diff"
Output: No credentials or security risks detected in the 4 modified files.
Command: npm test 2>&1 | claude -p "identify the failing test and provide the fix"
Output: Test failure in src/auth.test.ts: Token expiry expected 86400 but received 3600.
Output: Fix: In src/auth.ts line 24, update JWT_EXPIRY to 86400.
Piping diffs and test output into headless Claude Code.

Authentication in CI runners and automated environments

On your personal laptop, Claude Code authenticates via an interactive browser window. In headless CI environments (such as GitHub Actions, GitLab CI, or Docker containers), no browser exists.

To authenticate in automated environments, set the `ANTHROPIC_API_KEY` environment variable in your CI repository secrets. When Claude Code detects `ANTHROPIC_API_KEY`, it bypasses browser sign-in and authenticates directly via the Console API.

Building a GitHub Actions PR review workflow

Here is a minimal, working GitHub Actions workflow that runs Claude Code headlessly on every pull request to review changes against your repository conventions:

name: Claude Code PR Audit
on: [pull_request]

jobs:
  audit:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: Install Claude Code
        run: curl -fsSL https://claude.ai/install.sh | bash
      - name: Run Headless Audit
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
        run: |
          git diff origin/main...HEAD | \
          ~/.claude/bin/claude -p "audit this diff against CLAUDE.md conventions. Report only violations." > pr-audit.md
          cat pr-audit.md

Safety boundaries and budget guardrails

When running autonomous agents in headless pipelines, enforce sensible guardrails:

  • Timeouts: Wrap headless calls in the coreutils `timeout` command (for example: `timeout 180s claude -p ...`) so a slow run never hangs your CI pipeline.
  • Single-turn focus: Keep headless queries focused on review, linting, or summary tasks rather than multi-stage autonomous refactors.
  • Read-only checkouts: In CI runners, checkout code with a read-only git token unless automated commits are explicitly desired.

Handling exit codes in shell scripts

Claude Code adheres to standard UNIX exit conventions: it returns exit code 0 on success, and a non-zero exit code if an unhandled error or network failure occurs. This allows you to chain commands safely using standard `set -e` bash error handling.

Command: claude -p "audit src/services/billing.ts"
Output: Audit passed: Zero policy violations detected.
Command: echo $?
Output: 0
Note: Standard exit codes enable bash set -e scripts to fail fast when errors occur.
Checking process exit codes in automated bash pipelines.
Stay updated

Get new guides in your inbox

One task, one guide, done fast. Practical Claude Code skills, zero noise.