Run Claude Code headlessly with -p / —print for scripting, CI/CD pipelines, and programmatic use.
Non-interactive mode (-p / --print) runs Claude Code as a single-shot command: send a prompt, get a response, exit. There is no REPL, no UI, and no user interaction. This makes it suitable for shell pipelines, CI/CD jobs, and SDK-style integrations.
The workspace trust dialog is skipped when Claude is run with -p. Only use this flag in directories you trust.
Claude processes the prompt, prints the response to stdout, and exits. By default the output is plain text.
# Ask a questionclaude -p "what does the --dry-run flag do in rsync?"# Ask about a specific fileclaude -p "summarise the public API of src/auth/token.ts"
When stdin is not a TTY, Claude Code reads it and appends it to the prompt. This lets you pipe file contents, command output, or any text directly into a prompt.
# Explain a filecat src/utils/retry.ts | claude -p "explain this code"# Summarise a diffgit diff HEAD~1 | claude -p "write a concise commit message for this diff"# Analyse test failuresnpm test 2>&1 | claude -p "identify the root cause of these test failures"
If no stdin data arrives within 3 seconds, Claude Code proceeds without it and prints a warning to stderr. To skip stdin explicitly, redirect from /dev/null: claude -p "prompt" < /dev/null.
#!/bin/bashset -e# Generate a PR description from the current diffdescription=$(git diff main | claude -p "write a GitHub pull request description for this diff")# Create the PR using the generated descriptiongh pr create --title "automated changes" --body "$description"
Set ANTHROPIC_API_KEY (or configure another auth method) before running Claude Code in CI. The interactive OAuth flow is not available in non-interactive mode.
The Claude Code CLI can be driven programmatically from the official SDKs. The SDK launches Claude Code as a subprocess with --output-format stream-json and --input-format stream-json, exchanging structured JSON messages over stdio.
# Equivalent to what the SDK does internallyclaude -p "task description" \ --output-format stream-json \ --input-format stream-json
When using the SDK you do not need to construct these flags manually — the SDK handles the subprocess lifecycle and message parsing for you.