Skip to content
zero2vibecodelearn vibe coding
Level 3 · Autopilot 7 min Reviewed by the author · Oct 22, 2026 Verified against Claude Code v2.1.306 · Oct 22, 2026Official docs: Running from scripts (claude -p), Permission modesSomething out of date? Tell us

claude -p: Claude Code in scripts

claude -p runs one request with no interface, prints the answer and exits — this is how Claude Code fits into scripts. With --output-format json the result can be parsed, and the permission mode should always be passed.

Level 3 · 0 / 4 lessons0%
In this lesson

So far Claude Code has worked in a dialogue: you ask, it answers, you approve. But sometimes you need Claude with nobody on the other end — in a script, on a schedule, in CI. That is what is for.

One request, one run

claude -p "In one sentence: what does this repository do?"

Claude Code runs the request, prints the answer and exits: with code 0 if everything went fine, non-zero on failure. It also reads stdin, so a script can feed it, for example, a diff:

git diff | claude -p "Find obvious mistakes in this diff" --permission-mode dontAsk

An answer you can parse

With the --output-format json flag you get a single JSON object instead of text:

{"type":"result","subtype":"success","is_error":false,"num_turns":2,"result":"…","session_id":"…","permission_denials":[]}
  • result — the answer itself;
  • is_error — whether there was an error;
  • subtype — success or the reason for an early stop, such as error_max_turns;
  • num_turns — how many turns it took;
  • permission_denials — which actions were denied.

Important: if the run stopped at a limit, there is no result field at all. So check the exit code and is_error first, and only then take the answer.

Always set the mode explicitly

In a script, nobody can answer a permission prompt. So the mode is passed every time: without the flag, the run takes permissions.defaultMode from your settings files — which can be auto — and with no mode set anywhere it starts in Manual, where every call that needs approval is denied.

Three flags set the limits:

  • --permission-mode dontAsk — denies anything that would have needed a question in a session;
  • --allowedTools — lists what is allowed after all, for example "Bash(npm test *)";
  • --max-turns — caps the number of turns.
claude -p "Run the tests and tell me how many passed" \
  --output-format json --permission-mode dontAsk \
  --allowedTools "Bash(npm test *)" --max-turns 3

The space before * matters: Bash(npm test *) allows npm test with any arguments, including running it with none.

Quick check

A script calls claude -p and immediately takes the result field from the JSON. Sometimes it crashes with 'result is undefined'. Why?

Careful

Practice in the terminal

Check your understanding

Answered 0/3
Mode:

What does claude -p "request" do?

Why should you always pass --permission-mode to claude -p?

What should you check in the JSON response before using the result field?

Finish the task in the terminal and answer the questions to complete the lesson.

📝 My notes

Saved automatically in this browser · shows up on the Notes page.

Task

From a script, ask Claude what the project does: no interface, the answer as JSON, and the dontAsk mode set explicitly.

Tab complete · ↑ history · Ctrl+L clear · help commands

  • Not done: A run with no interface and a JSON answer
  • Not done: The permission mode is set explicitly
  • Not done: The run finished successfully

Lesson Q&A

What does claude -p "request" do?

Runs one request with no interface, prints the answer and exits with code 0, or non-zero on failure — -p is a non-interactive run: one request, an answer, exit. That is why you can call it from scripts and CI.

Why should you always pass --permission-mode to claude -p?

Nobody is there to answer permission prompts, and without the flag the run takes whatever mode your settings files set — In a script nobody presses "Yes". The dontAsk mode denies anything that would have needed a question. Without the flag, the run takes permissions.defaultMode from your settings files, which can be auto; with no mode set anywhere, it starts in Manual and denies those calls.

What should you check in the JSON response before using the result field?

The exit code and the is_error field — when a run stops at a limit, there is no result at all — subtype is either success or the reason for an early stop, such as error_max_turns — and then result is missing. Check the exit code and is_error first.

A script calls claude -p and immediately takes the result field from the JSON. Sometimes it crashes with 'result is undefined'. Why?

On an early stop, subtype gives the reason, such as error_max_turns, and the response has no result field. The exit code and is_error tell you sooner.

Commands in this lesson

Move between lessons with ← → · search with ⌘K

Written and reviewed by Mikhail Kuzmitskii