Running Claude Code non-interactively with claude -p: scripts, cron and CI

Claude Code Published:

Use Claude Code's -p mode from scripts and CI: stdin input, --output-format json, allowing tools with --allowedTools, and bounding cost and loops with --max-turns.

Verified on Sep 7, 2026 These tools change quickly. Please also check the latest official documentation.
Contents
  1. Basic form
  2. JSON output
  3. Allowing tools
  4. Keeping runs and cost bounded
  5. Example: GitHub Actions PR summary
  6. Where it fits
  7. Summary

Claude Code is interactive by default, but the -p (print) option turns it into a non-interactive command: pass one prompt, get the answer on standard output, exit. That makes it usable from shell scripts, cron jobs and CI pipelines, for jobs like summarizing a pull request, diagnosing a failing test or updating documentation.

This article goes from the basic invocation to JSON output, tool permissions and the controls that stop a CI run from spiraling.

KEY POINT

What you will learn

  • The basics of claude -p, including stdin and files as input
  • Processing results with --output-format json
  • Permission, turn and cost controls for CI

Basic form

claude -p "Explain the directory structure of this repository in five lines"

The answer is written to stdout and the process exits. You can pipe data in:

git diff main...HEAD | claude -p "Summarize this diff. Put any breaking changes first."
cat error.log | claude -p "Identify the likely cause of these errors and list the files to inspect"

CLAUDE.md and settings.json are loaded exactly as in interactive mode. Operations that require confirmation, however, are not executed automatically.

JSON output

claude -p "List dependencies in package.json that are a major version behind" --output-format json

The JSON includes the answer text, session ID, duration, cost in USD and token counts. Extract them with jq:

result=$(claude -p "$PROMPT" --output-format json)
echo "$result" | jq -r '.result'          # the answer
echo "$result" | jq -r '.total_cost_usd'  # cost
echo "$result" | jq -r '.session_id'      # for --resume later

--output-format stream-json emits progress as newline-delimited JSON, useful for long runs.

用語解説

Continuing a session: -p also accepts --resume <session_id>, so a script can do research in one call and act on it in a second.

Allowing tools

In non-interactive mode, tools that need confirmation do not run. To let Claude edit files or run commands, allow them explicitly with --allowedTools:

claude -p "Fix the lint errors" \
  --allowedTools "Edit" "Bash(npm run lint)" "Bash(npm run lint:fix)"

The syntax matches the permissions in settings.json; see Claude Code permissions in settings.json. --disallowedTools blocks tools the same way.

Use --dangerously-skip-permissions only in throwaway environments

--dangerously-skip-permissions disables every confirmation. On a host machine that means arbitrary commands run unchecked. Limit it to disposable containers and CI runners where nothing of value can be damaged.

Keeping runs and cost bounded

OptionEffect
--max-turns NCaps the agent loop so it cannot retry forever
--modelPick the model; routine jobs are usually fine on a Sonnet-class model
--allowedToolsGrant only what the job needs
--output-format jsonRecord total_cost_usd and aggregate it daily
claude -p "$PROMPT" --max-turns 10 --model claude-sonnet-5 --output-format json

Example: GitHub Actions PR summary

A minimal workflow that comments a summary on each pull request. The API key comes from repository secrets.

name: PR summary
on:
  pull_request:
    types: [opened, synchronize]

jobs:
  summary:
    runs-on: ubuntu-latest
    permissions:
      pull-requests: write
      contents: read
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - run: curl -fsSL https://claude.ai/install.sh | bash
      - name: Summarize
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
        run: |
          git diff origin/${{ github.base_ref }}...HEAD \
            | ~/.local/bin/claude -p "Summarize this diff and list three review points" \
              --max-turns 3 --output-format json \
            | jq -r '.result' > summary.md
      - uses: actions/github-script@v7
        with:
          script: |
            const fs = require('fs');
            await github.rest.issues.createComment({
              ...context.repo,
              issue_number: context.issue.number,
              body: fs.readFileSync('summary.md', 'utf8'),
            });

The install path varies by environment; check the installer's output if claude is not found. For a fuller integration (replying to comments, fixing issues), the official GitHub Action is simpler.

Where it fits

  • Cron every morning: summarize the dependency vulnerability report and post it to Slack
  • pre-push hook: a lightweight review of the diff (--max-turns 2)
  • Batch jobs: ask the same question across many repositories and collect the answers in a CSV
  • Docs generation: update docs/ to match changed APIs and open a PR

Summary

  • claude -p "prompt" runs non-interactively; data can come from stdin
  • --output-format json returns the answer, cost and session ID for jq
  • Grant edits and commands explicitly with --allowedTools, and cap loops with --max-turns
  • Keep --dangerously-skip-permissions to disposable, isolated environments

FAQ

What happens to confirmation prompts in non-interactive mode?
Operations that would need confirmation are not executed. Allow them explicitly with --allowedTools, or use --dangerously-skip-permissions inside an isolated environment.
How do I process the result programmatically?
Add --output-format json. The output includes the answer, the session ID, cost and token usage.
How does authentication work in CI?
Set the ANTHROPIC_API_KEY environment variable to an API key from the Anthropic Console. This is pay-as-you-go, so cap runs with --max-turns.

Primary sources

This article was drafted by AI from official documentation and reviewed by the site operator before publishing. Found a mistake? Let us know via the contact page.