Skip to main content

The claude CLI: Flags That Change Outcomes

Intermediate

Most people learn three things about the Claude Code command line — claude, claude -c, and claude -p — and stop. That is a fair place to stop if you only ever sit in front of it. The moment you put Claude Code in a script, a CI job, a background queue, or a teammate's hands, the flags stop being conveniences and start being the difference between a run that costs a dollar and a run that hangs for an hour.

This page is not a second copy of the reference table. It is the order to learn the surface in, the flags that materially change what happens, and the four traps that cost people real time.

What you'll learn
  • The six kinds of session you can start, and which flag picks each one
  • The five-flag contract that makes an unattended run bounded, answerable, and parseable
  • Why editing --append-system-prompt and re-running --continue appears to do nothing — the recorded-prompt rule
  • How --bare, --safe-mode and --restricted differ, and which one to reach for when
  • Driving background sessions from the shell: agents, attach, logs, respawn, rm, daemon
  • The flag pairs people confuse: --tools vs --allowedTools vs --disallowedTools

Start with the question: what kind of session is this?​

Every other decision follows from this one. Claude Code can start six materially different things, and the flag that picks one is usually the first thing you type.

You wantFlagIt gives you
A conversation you watch(none)Interactive session in this terminal
One answer, then exit-p / --printNon-interactive run, output to stdout
Work that outlives this terminal--bg / --backgroundA background session; prints its ID and how to manage it
An isolated branch to experiment on-w / --worktreeA git worktree under <repo>/.claude/worktrees/<name>
Work on Anthropic's machines--cloudA cloud session, or a follow-up queued into an existing one
To pull a cloud session back here--teleportFetches its branch and loads its history into this terminal
To drive this session from your phone--rc / --remote-controlAn interactive session also controllable from claude.ai or the Claude app

Two of these can't be combined: --bg and -p are mutually exclusive, because one returns immediately and the other waits for an answer. If you want a shell command rather than a Claude session in the background, pair --bg with --exec:

Run the test suite as a background job, not a Claude session

claude --bg --exec 'pytest -x'

And --bg checks workspace trust for the directory before it starts — so a background session in an untrusted repo fails up front rather than halfway through.

The five-flag contract for unattended runs​

This is the highest-value thing on this page. An unattended claude -p run has three ways to go wrong that an interactive session simply doesn't have: it can stall on permission prompts nobody is there to answer, it can loop far longer than you expected, and it can emit prose when your script needed data. Five flags close all three.

Guided walkthrough1 of 5
  1. `claude -p "query"` prints the answer and exits. Everything below is print-mode only, so this flag is the gate for the rest.

A CI step that cannot hang, cannot loop forever, and cannot overspend

claude -p "Review the staged diff and list bugs" \
--permission-prompts none \
--allowedTools "Read" "Bash(git diff *)" \
--max-turns 6 \
--max-budget-usd 2.00 \
--output-format json
--max-budget-usd is an estimate, not your invoice
  • Claude Code checks the cap against its own client-side cost estimate, which can differ from what you are billed.
  • When you return to a conversation with --continue or --resume, totals restored from earlier runs do not count toward the cap — so three resumed runs under a $2 cap can spend more than $2 in total.
  • Treat it as a circuit breaker for one run. For a real ceiling on a whole account or project, see Hard Spend Caps.

For the full posture around letting a run proceed without a human — what to allow, what to mask, what to log — see Hardening Autonomous Runs and Headless Mode & the Agent SDK. For provider-level ceilings, Hard Spend Caps.

The system-prompt family, and the trap in it​

Five flags shape the system prompt. Four set its text; the fifth decides whether the conversation keeps the text it started with.

FlagWhat it does
--system-promptReplaces the entire default prompt with your text
--system-prompt-fileReplaces it with a file's contents
--append-system-promptAppends your text to the default prompt
--append-system-prompt-fileAppends a file's contents to the default prompt
--system-prompt-snapshotoff rebuilds the prompt on every request; on (the default) reuses the recorded one

The choice between append and replace is a choice about identity. Appending keeps Claude Code's default tool guidance, safety instructions, and coding conventions, and layers your rules on top — right for per-run instructions, output formatting, or project context. Replacing drops all of that, including the tool guidance, which makes it right only when the surface genuinely isn't a coding assistant: a non-coding agent in a pipeline nobody watches. If you replace, you own whatever the task still needs.

You can combine them. Passing an append flag together with a replace flag replaces the default and then appends your text. From v2.1.283 you can also pass a flag together with its own file form — --append-system-prompt and --append-system-prompt-file — and Claude Code uses both, with the file's contents first regardless of the order you typed them.

The trap: a resumed conversation reuses the prompt it was born with
  • Claude Code builds the system prompt once, on a conversation's first request, and records it in the session.
  • Until the conversation is compacted, every later request uses that recorded prompt — including after --resume or --continue.
  • So you edit your --append-system-prompt text, re-run claude --continue, and nothing changes. The flag is not broken; the conversation is still using the recording.
  • New text takes effect once the conversation compacts, or in a brand-new conversation.
  • To iterate on wording across --continue runs, pass --system-prompt-snapshot off and the prompt is rebuilt every request. Requires v2.1.257 or later.

There is one more trick worth knowing in a replacement prompt that mixes stable instructions with per-run context. Put a line containing only __SYSTEM_PROMPT_DYNAMIC_BOUNDARY__ between them: Claude Code splits at the first such line and removes it, so the part above stays cached while the part below changes. Requires v2.1.275 or later. Why that matters for your bill is the subject of Prompt Caching.

And for multi-user scripted workloads, --exclude-dynamic-system-prompt-sections moves per-user context, such as the auto-memory location, out of the system prompt and into the first user message — so the same task on different machines shares one cached prefix. It applies only to the default prompt and is ignored when you set --system-prompt or --system-prompt-file.

Three flags that turn things off, and they are not the same​

People reach for these interchangeably and then wonder why the symptom didn't move. They solve three different problems.

--bare--safe-mode--restricted
The problem it solvesStartup is too slow for a scripted callMy configuration is broken and I don't know which partAn eval harness must not touch this shared machine
CLAUDE.md, skills, commands, subagents, plugins, MCP, auto memoryNot discoveredNot loadedOnly managed settings and --settings load
Built-in toolsBash, file read, file editWork normallyCommand/code-running tools and WebFetch removed unless named individually in --tools
File accessNormalNormalConfined to the working directories
bypassPermissionsAllowedAllowedRefused
Managed policyAppliesStill applies, including policy hooks and status lineApplies
Side effectSets CLAUDE_CODE_SIMPLESets CLAUDE_CODE_SAFE_MODERefuses to create cloud sessions

Read the table as a progression of intent: --bare is about speed, --safe-mode is about diagnosis, --restricted is about containment. One useful detail: skills in a directory you pass with --add-dir still load under --bare, which is how you keep exactly one capability in an otherwise-stripped run.

--safe-mode is the one to reach for first when something is misbehaving and you can't tell whether it's Claude Code or your own configuration — including when you're trying to work out whether a customization is what's triggering automatic model fallback. Pair it with claude doctor, which prints read-only installation and settings diagnostics without starting a session at all. (The in-session /doctor command is a different thing: it can also apply fixes.) More symptom-first debugging in Troubleshooting Claude Code. --restricted requires v2.1.248 or later.

Driving background sessions from the shell​

Once you start sessions with --bg, the terminal becomes a control plane. The whole lifecycle has a command, and none of it requires opening the interactive UI.

Guided walkthrough1 of 6
  1. Opens the agent view to monitor and dispatch parallel background sessions. For scripting, `--json` prints active sessions as a JSON array, and `--json --all` includes completed ones. `--cwd <path>` narrows to sessions started under that directory. Opening the view itself needs an interactive terminal; the JSON form does not.

The counterpart to this from inside a session — how work gets backgrounded, and what carries over when it does — is Background Tasks, /loop & Scheduling.

The flag pairs people get wrong​

Six confusions worth pre-empting
  • --tools restricts which built-in tools exist. --allowedTools says which calls skip the permission prompt. --disallowedTools denies calls. They are three different jobs, and passing the wrong one is the most common cause of "why is it still asking me".
  • --tools does not affect MCP tools at all. To remove those too, add --disallowedTools "mcp__*".
  • A bare name in --disallowedTools removes the tool from Claude's context; a scoped rule like Bash(rm *) leaves the tool available and denies only matching calls.
  • --dangerously-skip-permissions starts in bypassPermissions. --allow-dangerously-skip-permissions only adds that mode to the Shift+Tab cycle, so you can start in plan mode and switch later. The second is almost always what you actually wanted.
  • --add-dir grants file access, but Claude Code does not discover most .claude/ configuration from those directories. Adding a directory is not the same as adopting its config.
  • --desktop takes no prompt and no other flags except --verbose and the --debug flags, because the Desktop app starts the session itself. Requires v2.1.285 or later.

One small quality-of-life detail: mistype a subcommand and Claude Code suggests the closest match and exits without starting a session — claude udpate prints Did you mean claude update? rather than opening a conversation you didn't want.

Check yourself​

Check yourself

0/3
  1. Your nightly job runs `claude -p` inside an Agent SDK app whose `canUseTool` callback asks a person, and at night it hangs until the timeout. Which flag is most likely missing?
  2. You tweak your --append-system-prompt text, re-run `claude --continue`, and the behavior is unchanged. Why?
  3. A customization is breaking your session and you don't know which one. Which flag isolates it while keeping your tools and permissions working normally?
Press Enter or Space to flip the card. Use the left and right arrow keys to move between cards.Term shown.
1 / 8
Key takeaways
  • Pick the session kind first — the flag that does that constrains every other flag you can pass.
  • An unattended run needs five flags, not one: -p, --permission-prompts none, --max-turns, --max-budget-usd, and a structured output format.
  • Treat --max-budget-usd as a circuit breaker for one run, not as a bill ceiling. It is a client-side estimate and resumed totals escape it.
  • Conversations record their system prompt on the first request. If a prompt edit seems ignored, that is why — use --system-prompt-snapshot off while iterating.
  • --bare is speed, --safe-mode is diagnosis, --restricted is containment. Reaching for the wrong one wastes an afternoon.
  • --help is incomplete by design. The CLI reference is the source of truth, and version floors matter — check claude -v before blaming a flag.

Next​