When you run it with claude bare (without any parameters) you open an interactive session, but if you want to use it in scripts or set up an agent fleet you'll need -p and a number of other flags. Here's a summary of all the flags that are useful in terms of headless or agentic usage — based on v2.1.274 native for Mac, we've verified all of them.
How do I run Claude Code headlessly?
--print — runs a session and returns the output; no tui interface. For --print, you can set the prompt using either positional argument or stdin; here's an example of a one-shot prompt used as a positional argument and a diff being piped for the review:
claude -p "summarise the changes in this diff"
git diff | claude -p "review this diff and list risks"By default, it outputs text but you can use --output-format flag to specify a machine-readable format:
text — standard output, which is what you get by default
json — a single result envelope at the end of the turn (the final answer plus run metadata: error status, cost, token usage, turn count, permission denials, session id) which is great if you want to call it once and get the answer as data
stream-json — newline-delimited JSON where for each line there's an event happening during the turn, perfect if you want to observe the tool calls or messages as they happen
There's also --input-format flag which accepts values text and stream-json, the latter is useful when a persistent process runs on its own and sends a JSON event on stdin for every turn — so it doesn't need to create a new process for each turn. You can only use both of these flags with --print.
And here are a few more flags that are connected with the streaming and limits: --include-partial-messages — outputs both the text and thinking snippets during the generation process; --replay-user-messages — mirrors the stdin messages to stdout. And two budget flags: --max-budget-usd / --max-turns — these are the limits so you can stop an automated run if it spends too much or goes on for too long. Very useful if you want to create some agent that operates on its own. And the last one for the headless mode — --no-session-persistence, which disables saving the session to disk so it can't be resumed afterwards. It doesn't disable the auto-memory notes and subagents metadata files.
The easiest way to capture a run is just to pipe the output to a file using tee;
claude -p "$PROMPT" --permission-mode bypassPermissions --effort high 2>&1 | tee run.logif you want it to be machine-readable you can have it output stream-json and save it to a file, then decode it line by line
claude -p "$PROMPT" --output-format stream-json --verbose > events.jsonl--output-format stream-json requires --verbose (with -p), and together they return the entire event stream including every tool input and result — which is needed to render or replay the transcript.
How do I choose the model — and a cheaper one for subagents?
Another thing that's worth setting up if you're using the headless mode is the model; there are a few ways to do it: --model sets the session's model — you can either use family aliases (opus, sonnet, fable, haiku) for the newest member of this family, or specify a full identifier like "claude-fable-5"
claude -p "..." --model sonnet--fallback-model accepts a comma-separated list of models that will be tried one by one if the main one is too busy, but it will still try the main one at the beginning of every turn.
Personally, we use env vars to pin the models as the CLI uses different tiers for different things and often we want to set all of them together. Here are the env vars connected with it:
ANTHROPIC_MODEL— the session's primary model.CLAUDE_CODE_SUBAGENT_MODEL— the model that the subagents use (those you create using Task tool); if it's not set, the subagents run on the main session's model.
These are the models behind the built-in tiers; you can point these env vars to a single model and run the CLI with all the tiers pointing there to standardise it, or point them at different ones to make the subagents cheaper: ANTHROPIC_DEFAULT_HAIKU_MODEL / _SONNET_MODEL / _OPUS_MODEL — these are the actual models behind the aliases (haiku, sonnet and opus respectively), ANTHROPIC_DEFAULT_HAIKU_MODEL also points to a small fast model which is used for small and fast background tasks — previously it was called ANTHROPIC_SMALL_FAST_MODEL. This way you can standardise the tiers by pointing them all at one model (for example for benchmarking purposes)
export ANTHROPIC_MODEL=claude-opus-5
export ANTHROPIC_DEFAULT_OPUS_MODEL=claude-opus-5
export ANTHROPIC_DEFAULT_SONNET_MODEL=claude-opus-5
export ANTHROPIC_DEFAULT_HAIKU_MODEL=claude-opus-5
export CLAUDE_CODE_SUBAGENT_MODEL=claude-opus-5
claude -p "$TASK" --permission-mode bypassPermissions --effort highor do the opposite — set a large main model and point CLAUDE_CODE_SUBAGENT_MODEL at a smaller one so you still have a cheap fan-out, which might be useful if you work on extracting things in bulk or do judge-style runs where the cost is proportional to the size. You can also point the CLI at a different backend using these env vars: ANTHROPIC_BASE_URL and ANTHROPIC_AUTH_TOKEN — for another Anthropic-compatible endpoint (for example our Kimi K3 through Claude Code) or CLAUDE_CODE_USE_BEDROCK / CLAUDE_CODE_USE_VERTEX — to make it use Amazon Bedrock or Google Vertex instead of Anthropic.
How do I set the effort level?
Another thing is the effort level — this one is connected with the turn's intensity, you can set it using --effort flag. It accepts: low, medium, high, xhigh, max
claude -p "$TASK" --effort high— the higher you go the more it thinks and gives better answers but at a higher cost, we personally use "high" for agentic runs when the quality matters. There's also MAX_THINKING_TOKENS which is a stricter limit for the thinking budget.
What do the permission modes do, and which one for headless?
The most important setting connected with the headless mode is the permission mode which is defined using --permission-mode flag. As of v2.1.274, the accepted values are:
plan— read-only mode, you can only inspect things but not modify them.acceptEdits— auto-approving file edits and some basic filesystem commands like mkdir, mv, cp within the working directories (other than that it still asks).auto— the default one for Pro, Max and Team plans is auto which means that a classifier is involved to automatically approve standard calls and ask only if it's risky.manual— the old default mode which is now called manual, prompts before any tool call unless you've pre-approved it in settings (this is what you get with an API key, or if you use it with another provider, or with-p).dontAsk— everything that would prompt gets auto-disallowed, instead of pausing; all calls that are already pre-approved and the reads that don't require approval still work.bypassPermissions— no permission checks (except the ones you explicitly define using deny rules), it's fully autonomous.
So if you run something with -p, there's nobody to answer so the prompt gets auto-disallowed and the run continues but does less than it could. To avoid this either use --permission-mode bypassPermissions (or --dangerously-skip-permissions) or pre-approve all the tools you trust in settings using --allowedTools (like git through Bash) and let it refuse the rest.
There's also another flag — --allow-dangerously-skip-permissions which just enables the --dangerously-skip-permissions but doesn't set it. If you use it with --print, the --permission-prompts flag lets you choose who answers the permission prompts — the host (SDK host or the permission-prompt tool) or nobody (in which case prompting calls are auto-disallowed just like with dontAsk while the mode still controls everything else).
You can also narrow down the scope without disabling everything: --allowedTools / --disallowedTools — comma- or space-separated lists with a syntax to specify scopes, for example you can allow git through Bash but not anything in shell; --tools — limits what built-ins the session sees (you can set it to an empty string to hide them all or "default" to show them all, or provide a specific list). And there are a few more flags which limit the scope: --add-dir — extends the file sandbox to include more directories; --restricted — removes command- and code-execution tools and WebFetch (unless you list them in --tools), limits file tools to working directories, disables bypassPermissions mode and ignores user, project and local settings.
How do I wire up MCP servers from the command line?
If you want to configure some MCP servers from the terminal, there's claude mcp which is a management surface, and add is the main subcommand which supports all three transports:
# stdio server (a local process), with an env var passed through:
claude mcp add my-server -e API_KEY=xxx -- npx my-mcp-server
# HTTP server, with a scope and a header:
claude mcp add --transport http --scope project sentry https://mcp.sentry.dev/mcp -H "Authorization: Bearer ..."Here are the flags connected with it:
--transport— stdio, sse or http (stdio by default).--scope— local, user or project (project level creates a .mcp.json file in the repository which is shared).
And then there's everything after --, which is the command itself and its arguments; you can also set up OAuth using these flags: --client-id / --client-secret / --callback-port.
These are the other subcommands:
add-json— accepts raw JSON string as an input.add-from-claude-desktop— imports existing entries from Claude Desktop.list/get/remove— self-explanatory.login/logout— sign in to an MCP server that needs OAuth, or clear its stored credentials.reset-project-choices— forgets which project-level MCP servers (from.mcp.json) you've approved or rejected, so Claude Code asks again.claude mcp serve— runs Claude Code itself as an MCP server.
There's also a session-scoped alternative: the --mcp-config flag, which lets you specify servers for the run using JSON files or strings. Adding --strict-mcp-config limits the run to only the servers specified by you in --mcp-config (ignoring all other MCP configuration), so you can set up a reproducible set of servers for scripts using it.
How do I define subagents and run background agents?
And the last thing is custom subagents and detached sessions; to define your own subagent in code you can use --agents flag which accepts inline JSON agent definitions (no files needed), and then point the session at one using --agent flag.
claude -p "review this PR" --agents '{"reviewer":{"description":"Reviews code","prompt":"You are a code reviewer"}}'The subagents use CLAUDE_CODE_SUBAGENT_MODEL for their model if it's set, otherwise they run on the main session's model; there's also --append-subagent-system-prompt flag which adds a common instruction to every subagent's system prompt.
If you want to run a detached session you can use --bg / --background which returns a short id and then:
claude attach <id>— to open it.claude logs <id>— to print its output.claude stop <id>— to stop it (but keep the conversation).claude rm <id>— to remove it.claude respawn <id>— to restart it on this version.claude agents— to list them.
If you use --json with it, it returns an array of JSON objects for all active sessions so you can run it from scripts without a tty.
How do I resume and capture a session?
Another thing connected with the continuity is session capture: -c / --continue — resumes the latest conversation in the current directory; -r / --resume — resumes a session by its id or shows a picker if you don't specify one. And there's --session-id flag which lets you choose an id at the beginning of the run; we use this approach for multi-turn runs from scripts, so we generate a UUID and then start the run with it, and resume it with the same UUID on every subsequent turn — that way the context is shared between processes
SID=$(uuidgen)
claude -p "step one" --session-id "$SID"
claude -p "step two, building on the last" --resume "$SID"There are also a few variants of it: --fork-session which resumes into a new id rather than writing back (useful if you want to explore different options from a common starting point), and --from-pr which resumes a session connected with a GitHub PR. You can also use -d / --debug to enable debug logging (with an optional category filter like api,hooks), or --debug-file to point it at a file.
How do I get structured JSON I can actually parse?
If you need a structured output, there's a very powerful flag called --json-schema which validates the output against a JSON Schema that you provide, if you use it with --output-format json it returns a single validated object which you can then parse instead of parsing some prose; here's an example usage: task from stdin, system prompt set using --system-prompt flag, and a schema with required title property
echo "$INPUT" | claude -p \
--output-format json \
--system-prompt "Extract the fields described by the schema." \
--json-schema '{"type":"object","properties":{"title":{"type":"string"}},"required":["title"]}'The power behind this is that the model is bound to the schema so anything that's going to be based on it later can assume it has the schema, which makes Claude Code a pipeline stage rather than a chat interface.
How do I pin down context, system prompts and settings?
You can also control the context using a few flags connected with system prompts and settings: --system-prompt / --append-system-prompt — override and append to the default system prompt respectively; there are also their file equivalents even though they're not mentioned in --help, very useful if your prompt is long. And --settings which accepts a settings JSON file or string, or --setting-sources flag to choose which layers load (user, project, local) with the ability to add more directories using --add-dir.
There are also three modes connected with it that you can use to reduce what gets loaded and how they differ from one another:
--bare— minimal mode, bypasses hooks, LSP, plugin sync, auto-memory and CLAUDE.md auto-discovery; requires strict API-key auth so make sure to provide context explicitly.--safe-mode— disables all customisations (CLAUDE.md, skills, plugins, hooks, MCP, custom commands, output styles) but leaves the authentication in place, the model and the built-in tools enabled; meant for debugging.--restricted— security lockdown from earlier (removes command- and code-execution tools and WebFetch, unless you list them in--tools, limits file tools to working directories, disallows bypassPermissions mode, ignores user, project and local settings).
And if you run the CLI on a fleet of machines, there's another flag which might come in handy — --exclude-dynamic-system-prompt-sections which moves the machine-specific parts of the system prompt (like cwd, environment or git status) to the first message; that way you can increase the probability that a prompt will be served from cache across different machines with the same prompt.
Which environment variables actually matter?
Apart from the hundreds of internal flags that the binary mentions, there are also a few env vars that you might find useful:
| Variable | What it controls |
|---|---|
ANTHROPIC_MODEL | Main model for the session. |
CLAUDE_CODE_SUBAGENT_MODEL | Model that spawned subagents run on. |
ANTHROPIC_SMALL_FAST_MODEL | Deprecated older name for the background model — prefer ANTHROPIC_DEFAULT_HAIKU_MODEL. |
ANTHROPIC_DEFAULT_HAIKU_MODEL / _SONNET_MODEL / _OPUS_MODEL | Concrete model each built-in tier alias resolves to. |
ANTHROPIC_API_KEY / ANTHROPIC_AUTH_TOKEN | API-key auth / bearer-token auth (the latter paired with a base URL). |
ANTHROPIC_BASE_URL | Point the CLI at a different Anthropic-compatible endpoint. |
ANTHROPIC_CUSTOM_HEADERS | Extra headers on every API request. |
CLAUDE_CODE_USE_BEDROCK / CLAUDE_CODE_USE_VERTEX | Run against Amazon Bedrock / Google Vertex. |
CLAUDE_CODE_MAX_OUTPUT_TOKENS | Cap the model's output tokens. |
MAX_THINKING_TOKENS | Ceiling on the thinking budget. |
MAX_MCP_OUTPUT_TOKENS | Cap the tokens an MCP tool result may return. |
MCP_TIMEOUT | Startup timeout for MCP servers. |
BASH_DEFAULT_TIMEOUT_MS / BASH_MAX_TIMEOUT_MS | Default and maximum timeout for Bash tool commands. |
BASH_MAX_OUTPUT_LENGTH | Truncate long Bash output at this many characters. |
ENABLE_TOOL_SEARCH | Toggle deferred tool-search (false loads all tool definitions up front — the first thing to turn off against a non-Anthropic backend). |
USE_BUILTIN_RIPGREP | Use the bundled ripgrep (0 for your system rg). |
CLAUDE_CONFIG_DIR | Where Claude Code keeps its config and state. |
DISABLE_TELEMETRY / DISABLE_ERROR_REPORTING | Opt out of telemetry / error reporting. |
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC | One switch for all the non-essential background calls. |
DISABLE_AUTOUPDATER / DISABLE_COST_WARNINGS | Stop self-updates / silence spend warnings. |
What are the management subcommands — and is claude config still one?
Apart from that there are a few subcommands: claude doctor — health check, claude update (alias upgrade) — installs an updated version, claude install [stable|latest|] — installs a native build; claude auth login — to set up either --console (API/console billing) or --claudeai (subscription, the default), with --sso and --email. And claude auth status which tells you the current state of the authentication, claude setup-token which provisions a long-lived token for you, claude plugin which is for managing plugins and marketplaces, claude import to import configuration from codex, gemini or cursor (with --dry-run if you want to preview it), claude project purge to wipe the entire project's state, and claude ultrareview to run a multi-agent review of the branch or a PR in the cloud.
Just FYI — there's no claude config subcommand as of v2.1.274; the configuration is in settings.json and under /config now, and claude config set/get/list have been removed in this version so if you see these commands used anywhere they won't work — guides showing claude config set are outdated.
The surface is bigger than the help text
And last but not least — remember that the help is curated so there are a few flags and a big part of internal env vars that aren't included in it, so you shouldn't rely on these if you want your setup to be future-proof. The official CLI reference is the best companion doc for it, and it even says that claude --help omits some flags.
We personally run a lot of headless sessions — use parallel agents, pin models per role, save transcripts as JSON; this is what we needed so we've created this consolidated list. Feel free to have a look at our open-source work at github.com/dsplce-co, and if you want to take it further we've written an article about the /goal command which can be useful in the headless mode.



