Course/Automation for Power Users

9 min · +150 XP

Claude in scripts with claude -p

Run one task without the interactive window and use the answer in a script.

By the end of this lesson

You will be able to call Claude Code from a script, control what it may do, read its answer as JSON and cap what a run can spend.

With -p (print mode), Claude Code takes one task, does it and prints the answer, without the interactive window. That lets you call it from a shell script, a scheduled job or a build step, like any other command-line tool. It exits with code 0 on success and a non-zero code on failure, so the script can react.

💬 Let Claude write the script

“Write a script explain-build-error.sh that sends build-error.txt to claude -p, asks for the root cause in two sentences and saves the answer to output.txt. Allow only the Read tool, cap the spend at $1, run it once and show me the result.”

Claude writes the script with the right flags and runs it. The commands below are what it produces, so you can read and adjust them.

Ask about the project
claude -p "What does the auth module do?"

Run it inside the project folder. Claude reads what it needs, prints the answer and exits.

Pipe data in, write the answer out
cat build-error.txt | claude -p 'concisely explain the root cause of this build error' > output.txt

Print mode reads standard input. Piped input is capped at 10MB; for larger files, name the file in the prompt instead of piping it.

Output a script can read

Three output formats

  1. 1text, the default: plain text.
  2. 2json: one object with result, session_id, total_cost_usd with a per-model breakdown, and other metadata.
  3. 3stream-json: one JSON event per line as the work happens. Add --verbose, and --include-partial-messages for text as it is generated.
A structured answer that follows a schema
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'

The validated answer is in structured_output. If a run ends without valid structured output, for example because Claude declined, the field is missing, so check for it before using it.

Permissions without a person

In print mode nobody is there to answer a permission question, so decide in advance what Claude may do. --allowedTools lists tools that run without asking, in the same rule syntax as settings. --permission-mode sets the baseline for everything else.

Allow only specific git commands
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 * matters. Bash(git diff *) allows any command that starts with git diff; Bash(git diff*) would also match git diff-index.

Choosing the baseline

  1. 1--permission-mode dontAsk: anything not allowed in advance is refused. Suited to locked-down CI runs.
  2. 2--permission-mode acceptEdits: file writes and common file commands such as mkdir, mv and cp run; other shell commands still need an allow rule.
  3. 3--permission-mode auto: a classifier reviews actions in place of you. Add --permission-prompts none so anything that would wait for a person is denied and Claude is told not to retry it.

Scripts that behave the same everywhere

Bare mode with a spending cap
claude --bare -p "Summarize README.md" --allowedTools "Read" --max-budget-usd 1.00

--bare skips the hooks, skills, plugins, MCP servers, auto memory and CLAUDE.md found on the machine, so a teammate's setup cannot change the result. It never reads your subscription login, so set ANTHROPIC_API_KEY. --max-budget-usd stops the run when estimated spend reaches the amount; spend can pass the cap a little, so leave headroom.

Continue a specific conversation
session_id=$(claude -p "Start a review" --output-format json | jq -r '.session_id')
claude -p "Continue that review" --resume "$session_id"

--continue picks up the most recent conversation in this folder; --resume with an ID picks a particular one, from any project on this machine.

The same agent loop is available as the Agent SDK, with packages for Python and TypeScript; it used to be called the Claude Code SDK. Move to it when a script grows into a program and you want native message objects, callbacks that approve tools, and structured outputs. For most scripts, claude -p is enough.

!Print mode trusts the folder

claude -p skips the workspace trust dialog. Without --bare it runs the hooks in the project's .claude/settings.json and connects the servers in its .mcp.json, even in a folder you have never opened before. Before you script Claude over a repository you did not write, read its .claude/ folder or use --bare.

Quick check

Your CI job must give the same result on every machine and must not pick up anyone's personal hooks or CLAUDE.md. Which flag?

Quick check

You pass --json-schema and read .structured_output, but sometimes the field is missing. Why?

Facts checked against the official Claude Code docs October 24, 2026 · source

EAEvgenii Arsentev

Author

Evgenii Arsentev

PhD · Chief Executive Officer, digital health