claude -p runs a prompt once with no chat window and prints only the result. Use it to put Claude into scripts, CI, and pipelines. The same capability is also available through the Agent SDK.
Basic use
Add -p (or --print) to any claude command and it runs non-interactively. It exits with code 0 on success and a non-zero value on failure, so scripts can branch on it.
It reads standard input, so you can pipe in the output of another command. Piped input can be up to 10MB.
claude -p "Explain what the auth module does" cat build-error.txt | claude -p "Briefly explain the root cause of the build error" > output.txt
Output formats
- text (default): plain text.
- json: JSON containing the result, session ID, and metadata. The text result is in the result field, and total_cost_usd gives a cost estimate (it may differ from what you are billed).
- stream-json: line-delimited JSON. For real-time processing, used together with --verbose and --include-partial-messages.
- If you also pass --json-schema, the result matching the schema goes in the structured_output field. Check that the field exists before you use it.
claude -p "Summarize this project" --output-format json | jq -r ".result"
Permissions and continuing
It is non-interactive, so no one is there to answer approval prompts. Use --allowedTools to pre-approve tools. A pattern like Bash(git diff *), with a space and * at the end, allows only commands that start with that prefix. Without the space it also matches git diff-index, so be careful.
You can also set the default mode with --permission-mode (auto, dontAsk, acceptEdits). According to the docs, from v2.1.302, when nothing is configured, -p starts in Manual mode, and calls that need approval are denied.
Continue a previous conversation with --continue, or get session_id from the JSON output and pass it to --resume.
claude -p "Run the tests and fix the failures" --allowedTools "Bash,Read,Edit" claude -p "Review this for performance problems" claude -p "Focus on the database queries" --continue
Use --bare in CI
--bare skips automatic discovery of hooks, skills, plugins, MCP servers, auto memory, and CLAUDE.md. It starts faster and makes it easier to get the same result on any machine. This mode does not use a subscription login, so it needs ANTHROPIC_API_KEY. The official docs recommend --bare for scripts and say it will become the default for -p in the future.
Without --bare, hooks from the project's .claude/settings.json and servers from .mcp.json load without a trust prompt. Be especially careful when you use it in a repository you do not know.
How it differs from /schedule and /loop
-p is a way to run once, right now. It does not decide when to run. To run at set times, call -p from cron or GitHub Actions, or use cloud scheduled tasks (/schedule). Commands meant only for the interactive terminal (such as /login) cannot be used with -p.
Real examples
You want to find only typos in your changes before a PR
git diff main | claude -p "Act as a typo linter. For each typo, print one line with file:line and one line describing the problem. Say nothing else."
It reads the piped diff and reports typos. Because the diff is piped in, you do not need to give Claude Bash permission to run git. This is the same structure as the package.json script example in the docs.
You want the result as JSON in a script for further processing
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"JSON matching the schema comes out in structured_output, and jq pulls out just that part. If there is no valid result, such as when Claude declines the request, this field may be missing.
Common mistakes and when not to use it
- If you ask for work that needs Bash or edits without --allowedTools, the calls may be denied for lack of approval and the run ends.
- Allowing all of Bash in --allowedTools lets any shell command run. Keep it narrow where you can, like Bash(git diff *).
- --bare does not use a subscription login, so without a key it ends with an authentication failure.
- Running in CI without --bare can make results differ between environments because of the host's hooks and plugins.
- Stopping it with SIGTERM gives exit code 143, and that turn's result is not recorded.
FAQ
Why is it called headless?
It means it runs with no screen (no chat UI). The official docs describe it as a way to run Claude Code programmatically (the CLI form of the Agent SDK).
Can I use plugin commands with -p?
/plugin itself does not work. Plugins you have already installed do load. Install and manage them with the claude plugin command in your shell.
Can I see the cost?
total_cost_usd in --output-format json gives an estimate. It is a client-side estimate, so it may differ from the actual bill.
Checked against the official docs on 2026-10-30. Sources: Claude Code docs: Run Claude Code programmatically, Claude Code docs: Install and manage plugins. How we write