Claude Code — commands, settings, flags
Hi!
This is a reference. Not a story about how to work with the agent properly — I have a separate article for that — but a list: what you can type, what you can put in the settings, what each of those does and how it looks in practice.
Current as of August 2026, Claude Code 2.1.251. For a technical article that matters more than usual: between neighbouring builds commands disappear, get renamed and swap places. If you're on a different version, /help and claude --help are always right, and I'm only right as of the day I wrote this.
The three places commands go
Before you start scrolling through the tables, it helps to know that there are three surfaces and they don't overlap.
Slash commands are typed inside a running session, with / at the start of the line. They drive the conversation: switch the model, compact the context, roll back edits, kick off a review. They don't work in the terminal.
settings.json is a file on disk. It defines how Claude Code starts up: which model, what the tools are allowed to do, which hooks, what to show in the status line. A large share of the settings exist only here and have no command equivalent.
The claude terminal commands are typed in an ordinary shell, before a session or alongside one: installation, login, MCP servers, plugins, background agents, non-interactive runs for scripts.
The split isn't decorative. Half of the "why isn't this working" questions come down to someone typing /model in the terminal or --effort in the settings file. There is one pleasant exception, though: in the non-interactive claude -p mode slash commands inside the prompt text do work — more on that below.
Slash commands
Typed inside a running session, with / at the start of the line. Each command below has everything in one place: arguments with all their values, the fine print, and examples.
Markers: [Skill] — a built-in skill, that is, a ready-made prompt scenario; [Workflow] — a built-in multi-agent workflow; [undocumented] — present in the build, not described in public sources; [disabled] — registered, but doesn't work in 2.1.251.
Sessions and the conversation
Four commands in this group do something similar, and people mix them up constantly. The difference is what gets copied and where the result shows up:
| Command | What gets copied | Where the work happens | Where the result lands |
|---|---|---|---|
/branch | the whole conversation | right here, you carry on in the branch | into the branch; the original stays untouched |
/fork | the whole conversation | in a background session, in parallel with you | into a separate session you attach to later |
/subtask | the whole context, one-off | in a subagent | back into this same conversation, as one message |
/background | nothing is copied | this very session moves to the background | the same session, when you come back to it |
/clear [name]
Start a new conversation with a clean context. Aliases: /reset, /new.
The old conversation isn't deleted — it stays on disk and opens through /resume. The optional argument labels it in the list: with no label, a week later you'll be staring at a dozen nameless rows.
If you cleared it by accident, you can undo that within the same process: the /rewind menu has an entry for the previous session, shown as /resume <id> (previous session).
The price is worth remembering too: /clear costs nothing, whereas /compact is a large request carrying the whole context. If you don't need the conversation any more, clearing is cheaper than compacting by the entire window.
/clear/clear queue experiment, didn't pan out/resume [id or search phrase]
Go back to a past conversation. Alias: /continue.
| What you passed | What happens |
|---|---|
| nothing | An interactive list of this folder's recent sessions opens |
| a session id | It opens straight away, with no list |
| arbitrary text | A search across conversation contents; you pick from the matches |
The list is tied to the working folder: a conversation from another project won't show up in it. By id, though, a session opens from any folder on the machine — before 2.1.223 the search covered only the current project and its worktrees. Handy for scripts: grab the session_id out of claude -p --output-format json and carry on from anywhere.
Transcripts are cleaned up according to cleanupPeriodDays, thirty days by default. If you expect to come back to old conversations, raise the value in advance — there's nowhere to restore a deleted one from.
Terminal forms: claude -c continues the folder's last conversation with no picker (skipping background sessions), claude -r opens that same picker before the session starts, and claude -r <id> --fork-session continues an old conversation under a new id, leaving the original untouched.
/resume/resume 8f3c1d2e-4b5a-.../resume deadlock in the pool/branch [name]
Branch the conversation off at the current point; the original is kept in full.
This is the save-before-the-boss move. You're at a point where it's unclear which of two approaches is better; you branch off, try the first one, and if it doesn't work out you go back to the original through /resume and try the second, without dragging the failed attempt along in the context. The name is optional, but with one it's easier to find the right branch in the list later.
/branch/branch try-it-through-a-queue/fork [task]
Copy the conversation into a background session that works on a task in parallel with you.
This is "let someone else deal with that while I get on with mine". The copy inherits all the accumulated context; you collect the result by attaching to it with claude attach or through the claude agents screen. Starting with 2.1.221 the copy is also told to create its own git worktree before it edits any code — so two agents don't step on each other's toes in the same tree.
Careful with other people's instructions. In versions 2.1.161 through 2.1.211 what is now called /subtask was called /fork, and the names swapped places in 2.1.212. An article or a script written before that means the exact opposite. Plus one special case: if the agents screen is turned off, /fork falls back to the old behaviour and acts as a subagent.
/fork/fork put together release notes from the commits since the last tag/fork run the whole test suite and list the failures with their causes/subtask <task>
Send off a subagent carrying your context; the result comes back into this same conversation.
This is "go take a look and come back". The difference from /fork is fundamental: the noisy part of the work — reading twenty files, walls of output — stays in the subagent's context, and only the answer reaches you. The main way to keep reconnaissance out of your main context.
Requires version 2.1.212; before that this command was called /fork. Unavailable when the agents screen is off.
/subtask find every call to this method/subtask find where the authorization header is built and describe the chain/subtask read the last month of migrations and tell me what changed in the orders schema/background [prompt]
Move the current session into the background and free up the terminal. Alias: /bg.
Nothing is copied — this very session is what goes into the background, and the work carries on. With an argument you also hand it a task for the road. To come back: claude attach or the claude agents screen; to stop it: /stop or claude stop <id>.
/background/bg catch up with the build and fix the linter/rename [name]
Rename the session. Alias: /name [undocumented].
The name shows up in the input line, in the /resume list and in the terminal tab title. With no argument it's generated from the conversation's topic.
Three things happen to a name you type in: control and invisible characters are replaced with spaces, the length is trimmed to two hundred characters, and if nothing is left after the cleanup, the name is rejected as empty. If another live session on this machine already holds that name, a variant of it is applied — not an error, the name just ends up slightly different.
The terminal title changes if terminalTitleFromRename is on (yes by default); to forbid touching the title altogether, use the CLAUDE_CODE_DISABLE_TERMINAL_TITLE variable.
/rename/rename payment refactor/cd <path>
Move the session to a different working folder.
The new folder's settings, hooks, MCP servers, skills and agents take effect immediately rather than after a restart, and the new folder's env block is layered on top of the old one. That's what makes /cd different from /add-dir, which grants access to files but not to configuration.
/cd ../backend/recap
Compress the whole session into a one-line summary — a quick way to remember what it was about.
/recap/btw [question]
Ask a short side question without cluttering the main context: the answer isn't mixed into the rest of the work.
With no question it opens your past side questions so you can page through the answers; before version 2.1.212 the question was mandatory.
/btw how is grpc-web different from grpc/btw/export [file]
Dump the conversation to a file or the clipboard.
With no argument the whole conversation goes to the clipboard, with an argument it's written to a file; ~ is expanded. The format is text with role markup: it's a transcript for a human or for handing to another tool, not a machine format for importing back.
/export/export ~/logs/session.md/export ./docs/decision.md/copy [N]
Copy a single reply to the clipboard: with no argument the last one, with a number the Nth from the end.
It counts assistant replies, not lines on screen, so /copy 2 means "the reply before last". Little known: if the reply contains code blocks, a picker opens — you can take one block instead of the whole message. And right there the w key writes the selection to a file instead of the clipboard; over SSH, where the clipboard is useless, that's the only thing that works.
/copy/copy 2/stop
Stop the current background session. The transcript and the worktree are kept.
/stop/exit
Leave the CLI. Alias: /quit. In a background session it detaches instead, and the session keeps running.
/exitContext and memory
/context [all]
Show a colored grid of what's filling the context, plus tips on what you could unload. The all argument expands the details: exactly which files, and how much each one takes.
Every cell of the grid is a chunk of the context window, colored by source. The point isn't the pretty picture: sources behave differently, and each one is cured differently.
| What it shows | Where it comes from | What shrinks it |
|---|---|---|
| System prompt | Claude Code itself | almost nothing; --bare and --restricted trim it |
| Tool descriptions | built-in ones plus MCP servers | turn off the servers you don't need |
| Skill listing | descriptions of every available skill | skillOverrides, skillListingBudgetFraction |
| Memory files | CLAUDE.md and auto-memory | shorten them, or exclude them via claudeMdExcludes |
| Conversation history | your messages and the replies | /compact, /clear |
| Files read and command output | tools | /clear, and hand the recon off to /subtask |
The practical value is in all: there's almost always a file or two, or one chatty MCP server, that has eaten more than all the useful work put together.
Then comes the fork. History has ballooned — /compact. The files you've read have ballooned — /clear and start over. Tool and skill descriptions have ballooned — that's cured by settings, not by commands: next session the context will be bloated in exactly the same way.
/context # what's taking up the context right now/context all # the same, broken down file by file/compact [instructions]
Compact the conversation history into a summary and free up room. The argument isn't a flag and isn't a filter — it's an instruction to whoever writes the summary: what to pay attention to, what must not be lost.
Compaction is loss. The summary is written by the model, it's inevitably shorter than the original, and everything that didn't make the emphasis is either reproduced approximately or gone. A meaningful argument isn't politeness, it's how you control what exactly you agree to lose.
Compaction on its own is an expensive request: the whole context goes into it. /clear costs nothing. If you no longer need the conversation, the second command is cheaper than the first by the entire size of the window.
The threshold at which the context compacts itself is controlled by /autocompact.
/compact # compact the history however it comes out/compact keep the DB schema decisions # compact, but don't lose this thread/compact keep the decisions made on the schema and why we rejected triggers/compact leave only what relates to the payments module/autocompact [auto|<tokens>]
Set how full the context has to get before it starts compacting itself. The command appeared in 2.1.221.
| Argument | What it does |
|---|---|
| no argument | Show the current value |
auto | The threshold is picked automatically |
| a number from 100000 to 1000000 | Compact once that many tokens are reached |
Values outside the range are not accepted. The permanent equivalent is the autoCompactWindow key; auto-compaction is switched off entirely with autoCompactEnabled: false, and there's a launch flag --autocompact taking the same values. A separate setting, precomputeCompactionEnabled, prepares the compaction in advance while normal work goes on — so when the threshold is reached the pause is shorter; it only works with auto-compaction enabled.
/autocompact # see the current threshold/autocompact auto # let it pick for itself/autocompact 400000 # compact on reaching 400k tokens/memory
Open the memory files for editing and manage them.
What exactly gets loaded from them is shown by /context, and /doctor knows how to put them in order: it clears out duplicates, moves the rarely needed parts into separate files loaded on demand, and cuts whatever the agent would work out from the code anyway.
/memory # open the memory files for editing/pause-memory
Pause auto-memory for the session. Aliases: /memory-pause, /toggle-memory. [disabled] — in build 2.1.251 the command is registered but does nothing.
/pause-memory/init
Create CLAUDE.md: the agent looks the repository over and describes its structure and commands. [Skill]
CLAUDE.md is an instructions file that gets mixed into the context of every session.
A little-known variable: CLAUDE_CODE_NEW_INIT=1 turns on an interactive version that walks you through not just the project instructions but the skills, hooks and personal memory files as well. And if the folder turns out to hold another coding agent's configuration that /import knows how to bring over, you'll be offered the chance to take it.
/init # generate CLAUDE.md from the repositoryCLAUDE_CODE_NEW_INIT=1 claude # interactive /init with skills and hooks/add-dir <path>
Add another working directory so the agent can see files outside the project folder.
An important subtlety: it grants access to the files, not to the configuration — that folder's hooks and settings are not picked up. The one exception is skills and commands: those are taken from the added folder. Moving the session into another folder wholesale, together with its settings and hooks, is /cd, not /add-dir.
/add-dir ../shared-protocol # let the agent into a neighbouring repository/rewind
Roll the code and/or the conversation back to a checkpoint, or compact a slice of the conversation. Aliases: /checkpoint, /undo.
The first thing to know: the command doesn't always work. Copies of files are taken before an edit only if fileCheckpointingEnabled is on. Off — and there's nothing to restore from.
The second: the menu opens from more than just the command. Double Esc on an empty input line does the same thing. If there's text on the line, double Esc clears it — so clear the line first.
The menu has six items, and half of them aren't about rolling back:
| Item | What it does |
|---|---|
| Restore code and conversation | A full return to the state at that point |
| Restore conversation | The history comes back, the files stay as they are |
| Restore code | The files come back, the conversation stays whole |
| Compact from here | Compact the conversation from the chosen point onward |
| Compact up to here | Compact everything that came before the chosen point |
| Cancel | Do nothing |
The two compaction items are essentially a targeted /compact: free up context, but a specific slice of the conversation rather than the whole thing. The line has an optional field for saying what to pay attention to while compacting, and a marker is left where the compacted part was.
Of the rollbacks, "restore code" is the one you need most often: the edits went sideways, but the discussion they grew out of is valuable and it'd be silly to lose it.
Boundaries worth knowing before you need them. The last hundred checkpoints are kept, and they're deleted along with the session after thirty days — the same cleanupPeriodDays. Not restored: whatever the shell commands you ran did, most subagent edits, changes made from outside, and everything living behind symbolic and hard links. Meaning a database wiped by a migration won't come back, a git reset won't be undone, installed packages will stay. This is an undo for recent edits, not a version control system and not a substitute for commits.
/rewind # the rollback and compaction menuModel and performance
/model [model]
Switch the model and remember the choice. With no argument, a list of what's available opens.
| What you passed | What happens |
|---|---|
| nothing | A list of available models opens |
a family alias — opus, sonnet, haiku, fable | The current model of that family is taken |
default | The default model for your plan |
best | Fable 5 where the organization has access, otherwise the newest Opus |
opusplan | Planning on Opus, execution on Sonnet |
opus[1m], sonnet[1m] | The same model with a million-token context window |
a version prefix, for example opus-5 | Resolves to a specific model |
| a full identifier | Exactly that one is taken |
The choice is remembered and survives a restart — that's how /model differs from the ANTHROPIC_DEFAULT_MODEL variable, which it overrides.
Where things stand in August 2026. The current models are Opus 5, Sonnet 5, Fable 5 and Haiku 4.5. There is no Haiku 5: the haiku alias still leads to 4.5, and that regularly misleads people reading examples with fallbackModel.
What sits behind an alias depends on the provider, and that's a non-obvious detail for anyone working through a cloud. On Anthropic's own API sonnet is Sonnet 5; on Amazon Bedrock and Google Cloud it's Sonnet 4.5; on Microsoft Foundry opus is Opus 4.6 outright. The same config on two providers gives you different models.
All of this is configured three ways. What sits behind the aliases — through ANTHROPIC_DEFAULT_OPUS_MODEL and its relatives (there's no such variable for best). The picker list itself — through the modelPicker key: you add your own entries with labels there, including Bedrock and Vertex identifiers, and replaceBuiltInOptions replaces the built-in list entirely. On top of it all, the corporate availableModels constrains everything; since version 2.1.205 a family alias isn't rejected in that case but resolves to the newest permitted model.
fallbackModel lives separately — a list of models Claude Code will switch to on its own if the main one is overloaded. That's not a change to your choice, it's insurance for the time it's unavailable.
/model # pick from the available list/model opus # by alias/model claude-opus-5 # by full identifier/model opusplan # plan on Opus, execute on Sonnet/effort [level|auto|status]
The effort level sets how much the model thinks over a turn. It isn't the same thing as choosing a model: the model decides who is thinking, the effort decides how much.
| Value | What happens | When it makes sense |
|---|---|---|
low | Minimal reasoning, an answer almost immediately | Mechanical edits, renames, questions with an obvious answer |
medium | The normal mode | Everyday work |
high | Noticeably more reasoning before acting | Tasks where a mistake costs more than the wait |
xhigh | Maximum reasoning in the normal mode | Design work, digging through a tangled defect |
max | The same, with an emphasis on thoroughness | Rarely; before irreversible changes |
ultracode | xhigh plus constant workflow orchestration | Large decomposable jobs where cost isn't the priority |
auto | The level is picked to fit the task | The default value if you haven't intervened |
status | Changes nothing, shows the current level | — |
Four things that aren't obvious.
max can't be saved in the settings. The effortLevel key only accepts values up to xhigh. The maximum is set per session — by the command or the --effort max flag — and deliberately doesn't stay switched on forever. ultracode works the same way: the command and the flag work, but it isn't among the values listed in the schema; permanently it's turned on by a separate boolean key, ultracode.
The level is remembered per model. Since version 2.1.248 every model has its own saved level: switch to another one and you get its setting, not your last one.
Other commands override it. /code-review high raises the effort for that turn, /code-review low lowers it, even if the session was running on xhigh.
The word ultracode works right inside the prompt text — by default it's enough to turn orchestration on for a single turn; workflowKeywordTriggerEnabled is what's responsible for that. If it fired by accident, it's cancelled on the spot with Alt+W (Option+W on macOS). To start with it straight away: claude --effort ultracode.
2.1.251 also fixed an edge case that's easy to run into: Opus 5 refused to work with xhigh and max when thinking was turned off. Now in that combination the effort is simply sent as high.
/effort status # what the level is right now/effort low # cheap and fast/effort xhigh # deep reasoning/effort ultracode # xhigh plus constant workflow orchestration/effort auto # back to automatic selection/fast [on|off]
Fast mode: the same model, but with accelerated output.
It's not a different model and not a different effort level — it's an output mode, and it costs more. The settings keys sit right next to each other: fastMode turns it on permanently, while fastModePerSessionOptIn makes every session start without it, even if you turned it on last time.
/fast on # accelerated output/fast off # back again/brief
"Short answers only" mode: maximally condensed replies with no expanded explanations. No arguments.
/brief # answer as briefly as possible/advisor [model|off]
An advisor: a stronger model prompts the main agent at key moments.
The second model doesn't intervene constantly, only at key points — when the main agent is making a decision where a mistake costs a lot. The argument is an alias or a full model identifier; off turns it off. With no argument a picker opens. There's also a launch flag --advisor <model> which, by the way, isn't in the output of claude --help.
/advisor opus # hints from Opus/advisor off # turn the advisor off/plan [open|share|description]
Planning mode: the agent reads, analyses and proposes a plan but changes nothing — file edits and dangerous commands are unavailable. The exit is accepting the plan; after that the session returns to the normal mode and starts carrying it out.
| Argument | What it does |
|---|---|
| nothing | Just enter planning mode |
| the task text | Enter and start planning it straight away |
open | Open the session's current plan file |
share | Publish the plan as a separate page you can share |
Plan files live in ~/.claude/plans/ unless plansDirectory is set — people point it into the project repository so the plan gets discussed and versioned along with the code.
The plan-acceptance dialog has a "clear context" option: the plan stays, and all the recon it was built on is thrown away. It's only shown with showClearContextOnPlanAccept, which is off by default, and on long tasks it's one of the most useful settings — execution starts with a clean window.
The mode is available from the very start too: claude --permission-mode plan. And it's worth knowing separately that auto mode applies by default inside planning as well; that's switched off with the useAutoModeDuringPlan key.
/plan # enter planning mode/plan move payments into its own service # enter with the task right away/plan open # open the session's current plan/plan share # share the plan/goal [condition|clear]
Set the condition under which the work counts as finished; the agent keeps going on its own until it's met, instead of stopping after every turn.
| Argument | What it does |
|---|---|
| the condition text | Set the goal |
clear, stop, off, reset, none, cancel | Drop the active goal — any of the six words |
| nothing | Show the current goal, or the last one reached |
The condition has to be checkable — a command, a file's state, a marker in the output. A vague "until it's good enough" turns into endless work, because there's nothing to check it with.
A separate cost item few people think about: while a goal is active, the agent periodically wakes up and checks on stuck background work, and every such check is a full turn with the full context. The frequency is set by CLAUDE_CODE_GOAL_CHECKIN_MINUTES, zero disables the checks entirely; since version 2.1.246 there are no more than three per goal.
/goal until all the tests are green # work until the condition is met/goal until `npm test` passes in full/goal until not a single call to the deprecated client is left in the file/goal # show the current goal/goal clear # drop the goalCode review and quality
The first three commands look at the same diff and are therefore easy to confuse; the fourth analyzes nothing at all:
| Command | What it looks at |
|---|---|
/code-review | correctness bugs and code cleanliness; only fixes with --fix |
/simplify | cleanliness only — and applies what it finds immediately |
/security-review | only vulnerabilities in the branch's changes |
/diff | looks for nothing, just shows the changes |
/code-review [level|ultra] [--fix] [--comment] [--post|--no-post] [target]
Reviews the diff for bugs and simplifications [Skill]. Alias: /review.
The most configurable of the built-in commands: an effort level, four flags, a review target and a separate cloud mode — and each of them is parsed by its own rules. The full form is /code-review [low|medium|high|xhigh|max|ultra] [--fix] [--comment] [--post|--no-post] [<PR#>|<branch>|<path>|<note>], and every part of it is optional: a bare /code-review is a valid call.
What it looks for. Two different things. Correctness bugs: an inverted condition, an off-by-one, a null dereference, a forgotten await, a check that got dropped, an error swallowed in a catch, broken callers of a changed function, the classic pitfalls of the language at hand. And cleanliness: new code that repeats something already in the repository; needless complexity and dead code; needless work such as recomputing the same thing or running independent operations one after another; the "wrong level of fix", where a patch is slapped on the spot instead of repairing the shared mechanism; outright violations of the rules in your CLAUDE.md.
Correctness bugs always outrank cleanliness findings: when there are more findings than the level's limit, the cleanliness ones are cut first. The review itself changes nothing until you pass --fix.
Where it runs. Usually in a background agent: the session isn't blocked, and the findings arrive as a separate message. In three cases the review takes over the session entirely: if you launch it again while a previous one is still running; if you're in the non-interactive -p mode or in the SDK; and if CLAUDE_CODE_DISABLE_BACKGROUND_TASKS=1 is set, which disables background tasks altogether.
Who can launch it. Not just you. Ask "take a look at my changes" in plain prose and the agent will start the review itself, and a scheduled task with /code-review in its prompt will fire too. If that gets in the way, keep the command typable but forbid the agent and the scheduler from launching it:
{ "skillOverrides": { "code-review": "user-invocable-only" }}The cloud mode is the exception: the agent never launches ultra, neither on its own nor on a schedule.
Argument order. Three rules that make a call behave differently than you expected:
ultrais recognized only as the first word./code-review ultra --fixis a cloud review, while/code-review --fix ultrais an ordinary local one in which the wordultrais read as the target.- The level is the first word left once the flags are stripped out of the line. That's why
/code-review --fix highworks, and the level will behigh. - Flags can go anywhere: at the start, at the end, between the level and the target. The only exception is rule 1.
And a fourth one, separate: this command "eats" the command typed after it. Normally several skills stack in one message, and /write-tests /fix-issue 123 loads both. But since version 2.1.218 /code-review /fix-issue 123 reads /fix-issue 123 as target text, not as a second command. Before 2.1.218 it was the other way around.
Effort levels.
| Level | How it searches | Findings | When to use it |
|---|---|---|---|
low | One pass over the diff: no subagents, no reading whole files, no re-verifying findings; test files are skipped | up to 4, up to 8 on some models | A quick, cheap read-through before a commit |
medium | Eight independent search angles — three on correctness, three on cleanliness, one each on the level of fix and on the CLAUDE.md rules — then verification of every finding | up to 8 | An ordinary review |
high | The same eight angles, but verification leans toward completeness: a finding survives unless it can be disproved | up to 10 | When a missed bug costs more than extra noise |
xhigh | Ten angles at eight candidates each, verification, and a separate final "what did we miss" pass | up to 15 | A large or risky diff |
max | The same as xhigh, pushed as far toward completeness as it goes | up to 15 | Before a release or a migration — anything hard to roll back |
ultra | Not a level but a separate mode: a multi-agent review in the cloud | — | A whole pull request you'd like a second pair of eyes on |
The numbers in this table were read off the binary: the official documentation describes the levels qualitatively — "lower levels return the most confident findings, higher ones broaden coverage and may include less confident ones" — and nowhere publishes how many search angles there are or what the ceiling on findings is.
The exact pipeline depends on the session's model, so the table is about what the levels mean, not about a guaranteed number of agents. On Opus 5, medium and high currently collapse into a single careful pass with a limit of fifteen findings, and the differences begin at xhigh; on Sonnet 5, at high, xhigh and max the number of search agents is chosen by the size of the diff — from two to eight.
Remembering the level. If you don't name a level, it takes the one you typed last time: it lives across sessions, and the top of the report says so with a line like "using high, the level from last time". Two exceptions: a level passed in a non-interactive -p run remembers nothing, and ultra neither reads the remembered level nor changes it. If you've never typed one, it takes the current session's effort level. The level you type also sets the model's effort for that turn, including downward: /code-review low in an xhigh session lowers it.
A typo doesn't break the call: /code-review higher gets you a warning that the value wasn't recognized, plus the previous or the default level. The abbreviation med is accepted as medium.
Flags.
| Flag | Where it works | What it does |
|---|---|---|
--fix | locally and with ultra | After the report, apply the findings to the working tree |
--comment | locally, if the target is a pull request on GitHub | Post every finding as a separate line comment |
--post | ultra only, repository on github.com | Post the summary as one ordinary comment from your account |
--no-post | ultra only | Remove the offer to post from the launch dialog — which is the default behavior anyway |
--fix repairs what it found right in the working tree, both bugs and cleanliness. A finding is skipped if the fix would change intended behavior, would require changes far outside the diff under review, or looks like a false positive; at the end you're told what was skipped and why. With ultra, the fixes are applied locally the moment the cloud returns its result.
--comment requires the target to be a pull request. If it isn't, the flag is ignored, the findings are simply printed, and the agent says so. Comments go out through the GitHub integration, or through gh api if the session doesn't have one.
--post isn't the same as --comment: one shared comment instead of per-line remarks, and only for the cloud review. In an interactive session the launch dialog still asks for confirmation; in non-interactive mode it posts on the flag alone. Passed to an ordinary local review, it's ignored — you'll be reminded that posting there is --comment's job.
--no-post is there so you don't see the offer to post at all. Passing both at once is pointless: the command only reads --post, so --post --no-post still offers to post.
The review target. With no target, it reviews the current work: the branch's commits above its upstream plus the uncommitted changes. That's why the command makes sense before a commit too.
In a local review the target is handed to the model as a string, and the model decides for itself what it is: a pull request number, a branch name, a path to a file or a folder — or just a hint about where to look first. In ultra the target is parsed strictly:
| What you passed | What happens |
|---|---|
| nothing | The current branch is reviewed against the base one |
1234, #1234, PR 1234, a link to /pull/1234 | That pull request is fetched and reviewed |
| the name of an existing branch | Taken as the base, the diff computed against it |
| anything else | Recorded as a note for the review: the cloud agent never sees it and reviews the branch diff anyway, but when the findings come back they're tied to what you asked for |
Reviewing in the cloud: what it needs, what it costs and where the ceiling is. ultra launches a background agent in Claude Code on the web: it clones the repository into a cloud sandbox, runs a multi-agent search over the diff and sends the findings to your session as a notification. It takes minutes, and you can keep working the whole time.
It needs a git repository with a GitHub remote, a claude.ai account with GitHub connected, and, for a private repository, the Claude app installed on the owner. It's unavailable on third-party providers, with optional requests turned off, in zero-data-retention organizations and when the organization forbids it. An important detail: when the mode is unavailable, /code-review ultra doesn't fail — it quietly runs an ordinary local review — so if you were expecting the cloud one, it's worth making sure it actually started.
The diff ceiling is up to five hundred changed files and eight thousand changed lines. A pull request that's too big is rejected, and the refusal names the limits in force, the size of your diff and the largest files; an empty diff is rejected too.
The price: three free runs on Pro and Max, then it comes out of credits, usually five to twenty-five dollars per review depending on the size of the changes. A run counts from the moment the cloud session starts: a review you stop or one that crashes still spends a free run, while a paid one is billed only for the part it worked through. If credits aren't connected, a paid run is simply blocked.
From CI. Since version 2.1.218 the cloud review can be launched non-interactively:
claude -p '/code-review ultra'The command starts the review, prints a link for tracking it and doesn't wait for the result. But if the review would have to spend credits, the run stops: confirming payment requires an interactive session. For that case there's a separate subcommand, and the very act of launching it counts as your consent to be billed:
claude ultrareview # cloud review of the current branchclaude ultrareview 1234 --post # review a PR, summary as a comment on itclaude ultrareview --json # raw findings instead of a reportclaude ultrareview dev --timeout 60 # against the dev branch, wait up to an hourThe exit code is 0 if the review finished (with findings or without), and 1 if it couldn't be started. --timeout defaults to thirty minutes.
The canonical form is /code-review ultra; /ultrareview is its alias, available not to every account, and the whole capability is marked as research. Articles often say the opposite, as if /ultrareview were the main command.
In GitHub Actions. The review has a separate life in CI, and there it's configured by a file rather than by flags. You put a REVIEW.md in the repository root that sets the rules: which paths and branches to skip, which categories of findings to hide, what counts as important, how to behave when the same pull request is reviewed again.
Findings come in three tiers: important ones, nitpicks, and ones that were already in the code before these changes. Violations of your CLAUDE.md rules land among the nitpicks. The check always ends with a neutral status and therefore never blocks a merge by itself — but its last line prints a finding counter as JSON like {"normal": 2, "nit": 1, "pre_existing": 0}, which you can use to put up your own gate in your own pipeline.
/code-review # the current changes, level as last time/code-review low # a quick read-through before a commit/code-review high # and remember high as the default level/code-review --fix # find it and fix it right away/code-review high --fix # deeper, and fix what it finds/code-review medium --comment 1234 # review PR 1234 with comments right in it/code-review xhigh applications/backend/src # this folder only, as thorough as it gets/code-review max dev # the current branch's diff against dev/code-review higher # typo: warns and takes the previous level/code-review ultra # cloud review of the current branch/code-review ultra 1234 --fix # cloud review of a PR, findings applied locally/code-review ultra 1234 --post # cloud review of a PR, summary as a comment/code-review ultra look at the error handling # the branch plus a note on where to look/simplify [target]
Find simplifications in the changed code and apply them right away [Skill].
It looks at the same diff as /code-review, but hunts only for cleanliness, and does it with four parallel agents: reuse of helpers already written, simplifications, efficiency, and whether this is the right level of abstraction. It doesn't look for bugs as a matter of principle — that's a division of labor, not an oversight. And unlike the review, it applies what it finds right away. The argument is an optional target: a path, a folder or a pull request number.
A historical trap: before version 2.1.147, /simplify was the name of today's /code-review, and it applied fixes by default. An old script that called /simplify to hunt for bugs does something entirely different today.
/simplify # all the changed code/simplify src/payments # this folder only/simplify src/api/handlers # or this one/simplify 1234 # simplifications in this pull request/security-review
Check the branch's changes for vulnerabilities. Takes no arguments.
It looks for injections, authorization and authentication problems, data leaks, and unsafe handling of secrets and input.
The one requirement people trip over: you need a remote named origin — the diff is computed against its main branch. Without it the command dies with a git error about an ambiguous argument, and it looks mysterious.
/security-review # vulnerabilities in the branch's changes/diff
Browse the uncommitted changes interactively. Takes no arguments.
It analyzes nothing, it's a viewer: the uncommitted changes and, more usefully, the diff of each agent turn separately. Something worth using before /rewind, not after.
/diff # look at what's uncommittedDevelopment and workflows
/run and /verify get mixed up constantly: both are about "check it live", but they answer different questions.
| Command | The question it answers |
|---|---|
/verify | Does this particular change do what it was meant to do |
/run | How the whole app behaves when you bring it up the normal way |
/run
Launch the project's app and check a change live, not just with tests. [Skill]
This is about the app as a whole: bring it up the way it comes up in this project, and let you look at it. For it to know how exactly, it needs a launch skill — /run-skill-generator creates one, once per project. Without it /run will try to guess from the project type, and on a non-standard build it will guess badly.
/run # launch the app and look at it with your own eyes/verify
Confirm a change works: build it, run it, watch the behavior. [Skill]
The logic is simple: review checks that the diff reads right, /verify — that it works right.
Since version 2.1.200 the command can write the verification recipe it found into its own skill, .claude/skills/verify/SKILL.md, and then at the repository root it replaces the built-in one — meaning you work out once how to verify this project, and after that it works for everyone.
An important change: since version 2.1.215 /verify is launched only by you. The agent used to be able to call it itself. The same happened to /deep-research in 2.1.218. If you've read an article saying the agent will verify itself, it's out of date.
/verify # build, run, make sure it works/run-skill-generator
Create a skill that knows how to launch this project's app — /run then runs on top of it. [Skill]
Done once per project.
/run-skill-generator # teach the project the /run command/batch <instruction>
Plan a large-scale edit and carry it out in parallel across 5–30 isolated working copies, each opening its own pull request. [Skill]
The heaviest of the built-in commands, and the only one that spawns dozens of agents by default. The instruction first turns into a plan — a list of the concrete places that need editing — and then each place gets its own agent in its own isolated git working copy, and each one opens a separate pull request.
The key thing here is isolation. The agents edit files in parallel, and without separate working copies they'd be stepping on each other's toes. Hence the requirements: a git repository, a clean tree and a configured gh, otherwise there's nothing to open a pull request with.
The number of agents is five to thirty, and it's derived from the plan rather than set by you: as many agents as there are places found, up to the ceiling. If the plan comes out to two places, no fan-out is needed, and the command will say so.
A good instruction is one where the boundaries of each place are obvious and the edits aren't tied to one another. A bad one is "refactor the project": the plan comes out of vague items, and thirty agents independently invent thirty different architectures.
The fan-out's behavior is shaped by the worktree settings: symlinkDirectories saves disk space if the project has heavy dependencies, sparsePaths speeds up the checkout in large monorepos, baseRef decides whether to branch off the remote main branch or off your current local state.
/batch move all the controllers to the new client # a fan-out of isolated agents, each with its own PR/batch move every use of the deprecated http client to the new one/batch add the missing indexes from the planner's report/batch split the shared DTOs out into the modules that use them/debug [description]
Turn on debug logs for the session and help work through a problem. [Skill]
The description is optional — with it you say up front what exactly you're chasing.
/debug # turn on debug logs/debug fails only on CI, green locally # the same plus a description of the problem/fewer-permission-prompts
Go through the transcripts, find the frequent safe calls and build a permission list out of them. [Skill]
/fewer-permission-prompts # build a permission list from history/commit [preferences]
Put a commit together: look at the status and the diff, write a message in the accepted format. [Skill]
The argument isn't flags, it's your preferences in plain text; the same goes for /pr. Preferences affect what lands in the commit and how the message gets written. The message format is derived from this repository's commit history, not from general rules.
What goes into the commit message as attribution is set by the attribution object with its commit and pr fields, where an empty string removes it entirely. You can switch off the built-in commit instructions altogether with includeGitInstructions: false — then the agent goes by your rules only.
/commit # a commit with a message in the project's format/commit only the schema changes, leave the rest alone/commit as a single commit, without mentioning the test refactor/commit split it in two: schema first, then the code/pr [preferences]
Open a pull request: create a branch, push, write the description through gh. [Skill]
A branch is created if you're still on the main one. Preferences set the draft flag, the reviewers, the shape of the description.
/pr # branch, push, pull request with a description/pr as a draft, don't assign reviewers/pr in the description, list in a separate section what was left out/commit-push-pr
All three steps in one go: commit, push, pull request. [Skill]
It has one quirk: dangerous git and gh flags are not auto-approved. --force, --amend, --no-verify will still ask for confirmation, even if your permissions are generous. That's deliberate: a chain of three steps runs fast, and a human doesn't get the chance to notice that history is being rewritten somewhere in the middle.
/commit-push-pr # all three steps at once/update-config
Change the settings: hooks, permissions, environment variables — editing settings.json for you. [Skill]
/update-config add a hook that runs the formatter after edits/claude-code-docs [question]
Answers about Claude Code itself: features, settings, the SDK, the Claude API, the Slack app. [Skill]
/claude-code-docs how do I limit the agent's access to a folder/claude-in-chrome
Allow work inside your Chrome: clicking, filling in forms, reading the console. [Skill]
/claude-in-chrome # allow work in the browser/plugin-types [folder]
Generate the input types for the connected MCP tools.
/plugin-types ./my-plugin # MCP tool types for the plugin/workflow-authoring
A reference for writing workflow scripts. [Skill]
It doesn't authorize running a workflow itself.
/workflow-authoring # how to write workflow scripts/claude-api [migrate|upgrade|prompt-audit|managed-agents-onboard|cost-optimize]
Help with the Claude API and the SDK. [Skill] The only command in this group with a fixed set of arguments.
| Argument | What it does |
|---|---|
| no argument | General help with the Claude API and SDK: parameters, streaming, tool calls, caching |
migrate | Migrating code to a new model: what to change in identifiers, parameters and expectations |
upgrade | Moving to a new major version of the client library; since 2.1.236 |
prompt-audit | Find instructions written for older models in prompts, skills and tool descriptions, and propose the fix as a diff; since 2.1.221 |
managed-agents-onboard | Onboarding onto server-side agents with a managed sandbox |
cost-optimize | A breakdown of your API spend and what to do about it; since 2.1.247 |
The skill also switches on by itself, without the command: if the project's code imports the official Anthropic library, it activates on tasks that touch it.
/claude-api migrate # migrating to a new model/claude-api prompt-audit # find instructions written for older models in prompts/deep-research <question>
A fan-out of web searches across many sources, fact-checking, and a report with links. [Workflow]
Since version 2.1.218 it's launched only by you — the agent used to be able to call it itself.
/deep-research how do approaches to idempotency in queues differSubagents, background tasks, automation
/list-agents
A list of the subagents, teammates and other sessions you can write to. Alias: /peers.
/list-agents/agents
Gone. Now it just replies that subagents are created as files in .claude/agents/.
/agents/tasks
Listing and managing background tasks and running processes. Alias: /bashes.
/tasks/daemon
Managing background services: assistants, scheduled tasks, remote control.
/daemon/workflows
The history of workflows, running and finished: progress, pause, resume.
/workflows/loop [interval] [prompt]
Repeat a prompt or a command on an interval; with no interval the pace picks itself. Alias: /proactive. [Skill]
The command takes two things in a row: an optional interval and the thing to repeat. What you repeat can be a plain prompt or a slash command.
| What you passed | What happens |
|---|---|
<interval> <prompt> | The prompt runs on a schedule at that interval |
<interval> /command | The same, but a slash command is repeated |
<prompt> | No interval given: the agent decides for itself when to wake up next |
| nothing | An autonomous loop: the agent picks both the task and the pace |
The interval is written as a human shorthand: 5m, 30m, 1h. The mode without an interval should be taken literally: the agent picks the pause based on what it's waiting for. A build that takes eight minutes it will wait out in a single pause, not in eight one-minute checks.
There's exactly one trap, and it's an expensive one: a loop that wakes up every minute to check on a background task is almost always pointless. You'll be told when background work finishes anyway, and every wake-up is a full request carrying the whole context.
The list of what's already running is managed by /loops — but in this build that one is disabled.
/loop 5m /code-review low # every five minutes — a quick review pass/loop 10m /code-review low/loop 1h check whether new failing tests have shown up, and fix the obvious ones/loop check if the build broke # no interval: the pace picks itself/loop watch the deploy and tell me when it's done/loops
Viewing and deleting recurring tasks. [disabled] — doesn't work in build 2.1.251.
While it's disabled, /usage is what shows you what is running and how often.
/loops/schedule [description]
Create, update or run a scheduled remote agent. Alias: /routines. [Skill]
The difference from /loop is where it runs. /loop works in your session, on your machine, for as long as it's open. /schedule files the task in the cloud: it runs on schedule whether or not your laptop is on.
The argument is a description in words, and the schedule, the task and the intent are all derived from it: the command can not only create, but also update, show, run out of turn and delete.
The requirements are the same as for everything cloud-based: a claude.ai account, a connected GitHub, no block from your organization. The default environment comes from the remote setting.
About the cost, remember one thing: a scheduled task wakes up and sends the full context even while you're at the computer busy with your own work. It's the least visible line item of them all.
/schedule every morning at 9 put together a report on failing tests/schedule on Mondays check for outdated dependencies and file a task/schedule show my scheduled tasks/schedule run the morning summary right now/schedule delete the task about dependencies/autofix-pr [prompt]
A web session watches the pull request of the current branch and pushes fixes itself.
/autofix-pr # watch the PR and fix CI failures/autofix-pr only fix the linter, don't touch the logicArtifacts, documents and design
An artifact is a page published on claude.ai that you can open, click through and hand to colleagues to look at. Almost everything below is a built-in skill, and the set depends on your account: some of it only switches on for certain subscriptions and organizations.
The official command reference lists only /artifacts, /design, /design-login and /design-sync from this group; the other dozen and a half are [not in the documentation] — not in the changelog, not in search — so what follows is what's actually in the build, not what's been promised somewhere.
/artifacts
A list of the artifacts you've published and the ones shared with you.
/artifacts/prototype
Turn an idea into a working prototype: one self-contained page you can click through.
/prototype/doc
Publish a working document that's edited right on the page.
/doc/plan-artifact
Publish a plan as its own shareable page.
/plan-artifact/artifact-pr-review [number or link]
A pull request review as its own page: the conclusion, the recommendation, the contentious spots, the blind spots.
/artifact-pr-review 1234/artifact-dashboard
A dashboard from a ready-made template.
/artifact-dashboard/artifact-report
A report from a ready-made template.
/artifact-report/artifact-data-table
A data table from a ready-made template.
/artifact-data-table/artifact-explainer
An explainer page from a ready-made template.
/artifact-explainer/artifact-components
Drop ready-made reusable components into an artifact.
/artifact-components/artifact-design
The rules for styling artifacts: layout, typography, dark theme.
/artifact-design/artifact-diagramming
How to draw diagrams that show the real mechanism.
/artifact-diagramming/artifact-capabilities
What a published page can do at runtime: read your data, remember what visitors did, ask Claude.
/artifact-capabilities/dataviz
The rules for styling charts and dashboards: palettes, axes, labels, accessibility.
/dataviz/whiteboard
A shared board: you draw, and the answers come back right on it.
/whiteboard/whiteboard-mp
The same, but a live board the agent draws on as well — the two of you draw together.
/whiteboard-mp/workshop
Build a design together, one decision at a time.
/workshop/design [sync|login|consent|revoke|import|export|status|description]
The Claude Design hub.
Officially this is a single command "with a design description", and /design-login and /design-sync are two separate ones. In the binary, /design additionally understands the seven subcommands listed in the heading, and that's documented nowhere. The whole thing appeared in version 2.1.234 and is marked experimental — meaning it will change.
/design status # the state of the connection to Claude Design/design login # log in/design import # pull the design system from there/design export # push yours to it/design revoke # revoke access/design-sync [hint]
Push a React project's design system to claude.ai/design.
/design-sync Acme DS/design-login
Authorize access to the design system — the very access the push needs.
/design-loginConfiguration and interface
/config [key=value]
The settings panel: with no argument it opens a panel with every setting you can change from the interface. Alias: /settings.
With an argument the setting is applied immediately, without the panel: /config theme=dark. The full list of accepted keys is printed by /config --help — don't guess, it's shorter than the list of keys in the settings file.
The direct form appeared in 2.1.181, named shortcuts like theme and model — in 2.1.182. It works in non-interactive mode too, and from a phone over remote control, which makes it the main way to change a setting from a script.
There's exactly one limitation, and it isn't obvious: the key=value form can't turn on a setting that requires your confirmation in the panel. It can turn autoContinueAtUsageLimit off, for instance, but not on — turning it on brings up a dialog, and this form has nowhere to show one.
/config # open the settings panel/config --help # which keys the key=value form accepts/config theme=dark # set it immediately, no panel/config model=sonnet # the same for the model/config thinking=false # turn thinking off/permissions
Tool allow and deny rules, plus the auto-mode tab. Alias: /allowed-tools.
/permissions # access permission rules/theme
Change the interface color theme.
Besides light and dark there are colorblind variants, ANSI variants for terminals with their own palette, and auto, which adapts to the terminal background. Your own themes go into ~/.claude/themes/ or come from plugins; the picker itself has an entry for creating a new one.
/theme # pick a theme/keybindings
Open or create the keyboard shortcuts file.
/keybindings # your own keyboard shortcuts/terminal-setup
Set up terminal key combinations — Shift+Enter for a line break, for example.
/terminal-setup # Shift+Enter and other terminal key combinations/statusline
Configure the status line: with your own script, or generated from your shell prompt.
/statusline # configure the status line/voice [hold|tap|off]
Voice input.
| What you pass | What happens |
|---|---|
hold | Talk while holding a key down |
tap | Press, talk, press again to send |
off | Turn voice input off |
/voice hold # talk while holding a key down/voice tap # press, talk, press again to send/voice off # turn voice input off/tui [default|fullscreen]
The interface renderer: fullscreen is full-screen and flicker-free, default puts it back to normal.
/tui fullscreen # full-screen renderer without flicker/tui default # back to normal/color [color|default]
The prompt line color for the current session. It's not a theme, it's specifically the color of the input line; handy when you have four terminals open and don't want to mix them up.
| What you pass | What happens |
|---|---|
| a color from the palette | The prompt line takes it for the rest of the session |
| nothing | A color is picked at random — that's not a bug, it's deliberate |
default | Back to the normal color |
The palette is fixed: red, blue, green, yellow, purple, orange, pink, cyan, plus default to reset. If remote control is connected, the color syncs to the web interface as well.
/color purple # prompt line color/color # random color/color default # reset/scroll-speed
Mouse wheel scrolling speed.
/scroll-speed # mouse wheel scrolling speed/focus
Focus view: only your prompt, the tool summary and the final answer stay on screen.
/focus # keep only the essentials on screen/hooks
A view of the hooks configured for each event.
/hooks # which hooks are configured/auto-mode-setup
Tell auto-mode about your environment and adjust its rules.
/auto-mode-setup # tell auto-mode about your environment/sandbox [exclude "pattern"|install]
Configure the sandbox for commands. The command is only visible where the sandbox is supported.
| What you pass | What happens |
|---|---|
| nothing | The sandbox panel opens, with dependencies and overrides |
exclude "pattern" | A command matching the pattern is taken out of the sandbox |
install | Install the sandbox itself (Windows) |
exclude is for the case where a build or a container command doesn't work inside the isolation and you deliberately pull it out; the list accumulates in the sandbox.excludedCommands key.
/sandbox exclude "docker *" # take a command out of the sandbox/sandbox install # install the sandbox (Windows)/import [codex|gemini] [--dry-run] [--yes]
Bring configuration over from another coding agent: instruction files, MCP servers, commands, subagents and skills. codex and gemini are supported.
| Argument | What it does |
|---|---|
codex or gemini | Where to import from; without it you'll be asked |
--dry-run | Show what would be imported without changing anything |
--yes | Import without the interactive picker |
In non-interactive mode the command prints what it found and suggests the line to run to confirm the import. Not available on third-party providers, or when fetching server flags is turned off. Requires 2.1.213 or newer.
What /import does not do matters too: Claude Code doesn't read the AGENTS.md file some other agents use — but /import can carry the configuration from there into a form it does understand.
/import codex # pull in another agent's configuration/import gemini --dry-run # see what would be imported/import codex --yes # import without questions/cloud-plugins
Whether cloud sessions should use the plugins enabled on this machine.
/cloud-plugins # plugins in cloud sessions/skills
The list of skills, with control over their visibility.
The descriptions of every available skill sit in the context permanently, every session, whether you use them or not. With a large set of plugins that's a noticeable share of the window — which is exactly what the /skills screen is for.
Type and the list filters by name, description and source. The t key sorts by token count, and that's usually where you discover that half the window is taken up by three skills you've never used once. Space or Enter toggles a skill's visibility for the model and for the menu, Esc saves and closes.
Not everything can be toggled: plugin skills, skills with disable-model-invocation: true in the frontmatter, and ones whose visibility is set in enterprise settings or via --settings won't budge. The permanent equivalent is the skillOverrides key, and /skill-doctor helps find the ones that simply go unused.
/skills # the list of skills and their visibility/plugin
Managing plugins and marketplaces. Aliases: /plugins, /marketplace.
/plugin # plugins and marketplaces/reload-skills
Pick up skills and commands changed on disk without restarting the session. You need it when you're writing your own skill and don't want to restart on every edit.
/reload-skills # pick up skill changes from disk/reload-plugins [--force]
Apply pending plugin changes — the same as /reload-skills, only for plugins.
The meaning of --force here is the opposite of the intuitive one: it does not mean "reload harder". If the reload would change the set of loaded MCP tools, it invalidates the prompt cache, so the command warns you and refuses to do it — and --force makes it go ahead anyway. The flag overrides a refusal rather than deepening the work.
/reload-plugins # apply pending plugin changes/reload-plugins --force # do it even if it drops the prompt cache/wellbeing
Break reminders and quiet hours. Aliases: /breaks, /break-reminder, /downtime. [disabled] — in build 2.1.251 the command doesn't work, but the break settings themselves do apply.
/wellbeing # break reminders and quiet hoursMCP and integrations
/mcp [reconnect|enable|disable [<server>|all]]
Managing MCP servers and their OAuth authorization.
| What you passed | What happens |
|---|---|
| nothing | A list of servers and their state |
reconnect <server> | Bring a dead server back up |
reconnect all | Reconnect all of them |
disable <server> | Turn a server off temporarily |
enable <server> | Turn it back on |
Servers expose their own prompts as commands. They show up in the menu as /server-name:prompt-name — and that's the form worth remembering, because the second one, /mcp__server__prompt, works too but only turns up in older articles. Arguments are passed after a space and split on spaces: each argument is one token, and there's no way to pass a quoted phrase as a single argument.
Server resources are pulled in with @. The form is @server:protocol://path, and it's a mechanism separate from tools: not "call a tool", but "put this content into the context".
/mcp # list of servers and their state/mcp reconnect github # bring a dead server back up/mcp reconnect all # reconnect all of them/mcp disable jira # turn a server off temporarily/mcp enable jira # turn it back on/jira:create_issue login-bug high # a server prompt, current form/mcp__jira__create_issue login-bug high # the same one, old form/ide [open]
IDE integrations and their status. With no argument it shows the status of the editor integration; with open it opens the file in the connected IDE.
/ide # editor integration status/ide open # open the file in the connected IDE/chrome
Claude in Chrome settings.
/chrome # settings for working in the browserAccount and authorization
/login
Log in to an Anthropic account or switch accounts.
/login # log in or switch accounts/logout
Log out of the account.
/logout # log out/setup-bedrock
Set up Amazon Bedrock: authorization, region, model pins. Visible when Bedrock is enabled.
Together with /setup-vertex this is an example of commands hidden by state: they appear only once the matching provider environment variable is set. Until it is, they're not in /help either.
/setup-bedrock # set up Amazon Bedrock/setup-vertex
Set up Google Cloud: authorization, project, region, model pins. Like /setup-bedrock, it's visible only when the provider environment variable is set.
/setup-vertex # set up Google Cloud/install-github-app
Install Claude GitHub Actions for a repository.
/install-github-app # put review in CI on the repository/install-slack-app
Install the Slack app.
/install-slack-app # install the app into Slack/privacy-settings
View and change privacy settings.
/privacy-settings # what goes outsideUsage and cost
/usage
Session cost, plan limit usage and activity statistics. Aliases: /cost, /stats.
The screen shows three things: how much this session has spent, how full the plan limits are, and where the tokens go — broken down by skills, subagents, plugins and individual MCP servers, plus notes about any behavior accounting for more than ten percent of the spend. The d and w keys switch the window between a day and a week, and since 2.1.242 scheduled tasks get their own rows.
Next come four things worth understanding, and not one of them is obvious.
The breakdown is computed from the local session history. That is, from the transcripts on this machine. Work done from another computer or from the web interface doesn't make it in — even though the limits themselves are shared across the account. The gap between "I've barely spent anything" and "the limit is nearly gone" usually comes down to exactly this.
There are several limits, and switching models only helps against one of them. The messages "you've run out of session limit" and "you've run out of weekly limit" refer to windows shared by every model — /model won't save you there. Only after "you've run out of Opus limit" or "Sonnet limit" will moving to a model from another family get you working again. Since version 2.1.234 Claude Code can wait for the reset and resume the interrupted task on its own; you turn that on through /rate-limit-options and the autoContinueAtUsageLimit key.
The prompt cache lives an hour only on a subscription. The moment you start spending credits beyond the plan, cache lifetime drops from an hour to five minutes — and the same lunch break that cost nothing yesterday means reprocessing the entire context from scratch today. On an API key and with cloud providers it's five minutes by default.
The session counter resets on /clear. Before version 2.1.211 it accumulated across clears, so the numbers in older articles don't match today's.
If the limits server is unavailable, the screen shows the last loaded data with a note and offers to retry with the r key.
Invisible spending that doesn't show up in the breakdown but really does burn the limit while you're doing nothing: scheduled tasks wake up and go off with a full context; a message from another of your sessions arrives as a new turn (cured by crossSessionInbound: "hold"); active-goal checks start turns while background work is running; every live teammate spends until it finishes. And /compact is itself a large request, whereas /clear costs nothing.
/usage # limits, spend, breakdown/stats # the same, straight to the stats tab/cost # the same, in the usual view/usage-credits
Set up credits so you can keep working once you hit the plan limit. Remember the side effect described above: as soon as you spend beyond the plan, the prompt cache lives five minutes instead of an hour.
/usage-credits # enable credits beyond the planRemote work and environments
/desktop
Continue the current session in the desktop app. Alias: /app.
/desktop # continue in the app/teleport
Pull a web session into this terminal. Alias: /tp.
/teleport # bring the web session into the terminal/remote-control
Open the session for control from a phone or the web. Alias: /rc.
/remote-control # open the session up to a phone/session
Show the remote session's address and a QR code for it. Alias: /remote.
/session # session address and QR code/remote-env
The default environment for web sessions and teleport.
/remote-env # default environment for the web/web-setup
Connect GitHub to Claude Code on the web through your local gh.
/web-setup # connect GitHub to the webDiagnostics and help
/help
Help and the list of available commands.
/help # what's available at all/status
Version, model, account, API connectivity and tool statuses. Works even while a response is streaming.
Opens the settings panel on the status tab. Besides version, model, account and connectivity, there's a line for the kind of session: interactive for a normal one, background job · attached or background job · unattended for a background one — depending on whether a terminal is attached to it. The line appeared in 2.1.221.
Plus, since 2.1.243, a line right there about skipped sources of enterprise settings: if an admin dropped in a policy file but a different, higher-priority one is in effect, you'll see here exactly which one was ignored. It's the first thing to look at when "the admin's setting didn't arrive".
/status # version, model, account, connectivity/doctor
Diagnose the installation and put the configuration in order. Alias: /checkup.
Since version 2.1.205 this isn't a report screen but a full skill that edits your configuration. What it does: clears out duplication between the local and the committed CLAUDE.md; trims the committed one, throwing out whatever the agent would infer from the code anyway; moves permanently loaded instructions into skills and nested files loaded on demand; offers to make auto mode the default and to pre-approve the safe commands you've denied most often. It shows the findings first, then makes the changes.
The terminal claude doctor is still diagnostics with no edits and no session start; it reads the settings files in the current folder without asking whether you trust it.
The command stays available even when bundled skills are switched off entirely: it's specially marked as surviving disableBundledSkills. You can hide it with the DISABLE_DOCTOR_COMMAND variable or a "doctor": "off" entry in skillOverrides.
/doctor # check and fix the configuration/feedback [report]
Send feedback about Claude Code.
/feedback # send feedback/feedback edits get applied but don't show up in the diff/bug [report]
Report a bug or share the conversation. Alias: /share.
/bug # report a bug/heapdump
Take a memory dump — for diagnosing high memory usage. Hidden.
Writes a memory snapshot and a usage breakdown to the desktop (to the home folder on Linux without a desktop). The command is hidden not by a server flag but by not being shown in the menu: type it out in full and it works. An important warning: when you contact support, attach only the breakdown file — the snapshot itself holds your entire conversation and your credentials, and must not be shared.
/heapdump # memory dump to the desktop/insights
An analytical report on your sessions: areas of the project, work patterns, points of friction.
/insights # an analysis of my sessions/skill-doctor
Which loaded skills go unused and take up context for nothing.
/skill-doctor # which skills hang in context for nothing/explain-usage
Where this session's tokens went, in plain language. [Skill]
/explain-usage # where the tokens went/version
[disabled] Doesn't work in build 2.1.251. /status shows the session's version.
/version # disabled, /status will show the version/update
[disabled] In build 2.1.251 it doesn't work and is hidden. Updating is done with the terminal claude update. Alias: /restart.
/update # disabled, update via claude update/install [version] [--force]
Install a native build straight from the session. The argument is the version: stable or a specific number; --force installs it over the current one.
/install stable # install the stable build/install 2.1.236 --force # a specific version, over the current oneInformation and documentation
/release-notes
A list of changes by version.
A nice detail: the notes are printed into the transcript but don't get into the model's context. That wasn't always so, and showing all the changes used to mix the whole changelog into every subsequent request.
/release-notes # what changed, by version/powerup
Short interactive lessons on features.
/powerup # a short lesson on features/mobile
A QR code for installing the mobile app. Aliases: /ios, /android.
/mobile # QR code for the mobile app/radio
Claude FM lo-fi radio in the browser.
/radio # background music/passes
Share a free week with friends and get credits.
/passes # share a free week/upgrade
Move to Max: higher limits, more Opus.
/upgrade # move to Max/stickers
Order stickers.
/stickers # order stickers/team-onboarding
Generate a team onboarding guide from your usage history.
/team-onboarding # a team guide from my historyCommands that no longer exist
A table of its own, because half the articles on the internet still recommend them.
| Command | What happened to it |
|---|---|
/vim | Removed in 2.1.92. The key mode is switched in /config via the "Editor mode" field or the editorMode setting. |
/pr-comments | Removed in 2.1.91. Just ask the agent to show you the pull request comments. |
/output-style | Deprecated in 2.1.73 and removed in 2.1.91. |
/ultraplan | Removed. Use plan mode instead. |
/agents | Formally still there, but all it does is tell you that subagents are defined by files in .claude/agents/. |
/extra-usage | Renamed to /usage-credits in 2.1.144. |
/init-verifiers | Never existed — if you've run into it, somebody made it up. |
--enable-auto-mode | Flag removed in 2.1.111. Use --permission-mode auto instead. |
Disabled specifically in build 2.1.251: /version, /update, /loops, /wellbeing, /pause-memory. They're registered, but they don't work and don't show up.
There are also commands that appear on state and that you won't see until that state arrives: /limit-reset and /low-priority — when you've hit the session limit, /rate-limit-options, /pro-trial-expired, /design-consent and /design-revoke, and /setup-cowork lives only in Cowork mode. Plus two entirely internal entry points, __remote-workflow and workflow-launch-exec, through which the server hands the session a ready-made workflow.
And a category of its own — model-only skills: keybindings-help, memory-types, cowork-plugin. The agent pulls them in itself; you can't type them. The mechanism is generic and available to you too — it's the user-invocable: false field in a skill's frontmatter.
Two stubborn myths to finish with. There is no /alias command: what sits under that name in the binary is a description of the system alias utility, used for autocompleting the commands you type through !. And there's no .claudeignore file either — to make the agent ignore files, use .gitignore, which is honored by default, or .ignore.
How the menu matches a command
A small thing that saves your nerves. Since 2.1.236 the menu highlights a command when the letters after / match its name or one of its aliases — from the start of the name or from the start of a word inside it, with the separators :, _ and - ignored during the comparison. So /adddir highlights /add-dir, and /new highlights /clear through its alias.
What changed at the same time and matters more: a typo is no longer guessed. Enter on a non-existent command used to run the closest one. Now a typo leaves nothing highlighted, near matches stay in the list and you pick one with the arrows or Tab, but Enter sends your text as-is and reports an unknown command.
Unavailable commands simply vanish from the menu — you'll see "no commands match your query". Some answer with their own unavailability message instead: /schedule on an API key, for instance, will tell you it needs an account. And a partial name won't pull a hidden command out — you have to type it in full.
Your own commands
Your own slash command is a SKILL.md file in a skill folder. There used to be a separate entity for this in .claude/commands/; commands and skills are now merged into one, and the old files keep working and give you exactly the same command.
Where to look and where to put things:
| Location | Scope | Command name |
|---|---|---|
~/.claude/skills/<name>/SKILL.md | personal, across all projects | /<folder name> |
<project>/.claude/skills/<name>/SKILL.md | project-level, committed | /<folder name> |
.claude/commands/<name>.md | the old form, still works | /<file name> |
| plugin | wherever it was installed from | /<plugin>:<name> |
The command name comes from the folder name, not from the name field. For personal and project skills, name is only the label in the list. For plugin skills it's the other way round: name replaces the last segment, so my-plugin/skills/review/ with name: fancy gives you /my-plugin:fancy. The short form /fancy works too, as long as nobody else has taken that name.
The simplest example:
---name: fix-issuedescription: Look up an issue by number, find the cause and propose a fixargument-hint: <issue number>allowed-tools: Bash(gh issue view:*), Bash(gh pr create:*)---
Take issue number $0 from this repository.
Current state of the branch:
!`git status --short`
Read the description, find the cause in the code, propose the smallest fixand explain why it is the smallest one.You call it as /fix-issue 4821. Here $0 is the first argument, that is 4821, and the line with ! runs before the text ever reaches the model and is replaced by its output. Both in detail below.
Frontmatter fields
There are twenty of them. It's worth knowing they exist at all — half of them solve problems people otherwise solve with hacks.
| Field | What it sets |
|---|---|
name | The name; for personal and project skills, only a label |
description | The description the model uses to decide whether the skill fits |
when_to_use | A clarification of when to reach for it |
argument-hint | The argument hint shown in the menu |
arguments | A list of named arguments mapped positionally onto $name |
disable-model-invocation | Forbid the model from invoking the skill on its own |
user-invocable | false — a model-only skill, you can't type it |
allowed-tools | What to pre-approve for this turn |
disallowed-tools | What to forbid |
model | The model for the rest of the turn; accepts inherit |
effort | Effort level: from low to max |
context | fork — run the skill in a subagent |
agent | Which agent type to use with context: fork |
background | false — wait for the forked skill's result |
hooks | Hooks that live together with the skill |
paths | Restrict automatic activation to these paths |
shell | What runs the embedded commands: bash or powershell |
metadata | Arbitrary data |
license | License |
compatibility | Compatibility requirements |
Three limitations people trip over. The frontmatter is read only if the opening --- is the very first line of the file. In the listing, description and when_to_use are truncated at fifteen hundred characters — anything longer is invisible to the model when it picks a skill. And the old files in .claude/commands/ support the same frontmatter, except name and paths — those are ignored there.
A word on allowed-tools specifically: it's a pre-approval for one turn, not a restriction. The permission drops with your next message, though the skill's content stays in the context. And it has an unpleasant property worth knowing about for anyone who runs the agent in someone else's repository: folder trust does not hold it back. A project skill applies its allowed-tools even in a folder you never marked as trusted, including a non-interactive run. Which means a skill sitting in a repository can grant itself broad rights — read that field in other people's repositories before you launch.
Arguments: numbering starts at zero
The most surprising spot in the whole topic, and one worth memorizing word for word.
| Substitution | What gets substituted |
|---|---|
$ARGUMENTS | The whole argument string exactly as you typed it |
$ARGUMENTS[N] | The argument at that index, zero-based |
$N | The short form: $0 is the first argument, $1 the second |
$name | An argument from the arguments list in the frontmatter, by position |
Yes, $0 is the first argument, not the command name as it is in a shell. The off-by-one here is the most common mistake of all.
Indexed arguments are parsed with quoting in mind: in /my-skill "hello world" second the value of $0 is hello world as a whole. An indexed substitution that ran out of arguments stays in the text as-is; a named one turns into an empty string. An argument whose own value happens to contain $1 or $ARGUMENTS is inserted literally and not expanded a second time. Escaping is a single backslash: \$1.00. And if no substitution in the body received any arguments, the line ARGUMENTS: <value> is simply appended at the end.
Embedded shell commands
The form !`command` runs before the content reaches the model and is replaced by its output. That's how you feed a skill the current state: the branch, the diff, the list of failing tests. What actually runs it — bash or powershell — is set by the shell field in the frontmatter.
There are two rules that save you half an hour of bafflement. The form is recognized only if the ! sits at the start of a line or right after a space — in KEY=!`cmd` it stays text and never runs. And substitution passes over the file once: command output isn't rescanned, so a command can't print another substitution counting on a second pass.
For a multi-line script you open a code block with an exclamation mark after the three backticks.
All of it is switched off by the disableSkillShellExecution setting: every command is replaced with a stub saying policy forbids it. It applies to personal, project and plugin skills and to skills from added folders; built-in and enterprise ones are left alone. Skills synced from claude.ai never run such commands locally, whatever the setting says.
Path variables
Inside the skill body and inside allowed-tools rules you get ${CLAUDE_SKILL_DIR} — the skill's own folder, ${CLAUDE_PROJECT_DIR} — the project root, ${CLAUDE_SESSION_ID}, and in plugin skills also ${CLAUDE_PLUGIN_ROOT} and ${CLAUDE_PLUGIN_DATA}.
That they work in both places isn't a detail, it's a working technique: that's how a skill runs its own script without a single question about permissions.
---name: renderdescription: Render a diagram from its sourceallowed-tools: Bash(${CLAUDE_SKILL_DIR}/scripts/render.sh *)---
Run `${CLAUDE_SKILL_DIR}/scripts/render.sh $0` and show the result.The rule allows exactly the command the body tells it to run — no wider, no narrower.
Small things worth knowing
Skills stack. You can put up to six commands at the start of one message: /write-tests /fix-issue 123 loads both skills and passes 123 to both as arguments. Before 2.1.199 only the first one loaded and the rest counted as text. The exception is /code-review, which takes the rest of the line for itself.
ultrathink in a skill body asks the model to think harder when the skill fires. It works as the bare word in the text.
Built-in command names are reserved, even when they're unavailable in your session: a skill arriving from sync with a colliding name will be skipped.
You can validate a skill without a plugin: claude plugin validate <path> works on a plain folder of skills and agents too. And to turn a folder of skills into a plugin, all you need is to drop a .claude-plugin/plugin.json into it.
Settings: settings.json
Next up are the keys of the settings file, including the experimental and enterprise ones, with types and examples. The list is merged from two sources: the official settings reference, which currently holds about two hundred and twenty entries, and the validation schema inside the CLI itself. They don't agree: the schema has keys the documentation doesn't, and the documentation has keys the schema knows nothing about, because those live in a different file. More on that separately below.
Notation: [exp] — an experimental or internal key, may change or disappear; [admin] — only takes effect from an enterprise source; [deprecated] — deprecated; [global] — lives not in settings.json but in ~/.claude.json.
Where the file lives
There aren't four levels, or five, but more than people usually write about. Let's start with the ordinary ones:
| Level | File | Purpose |
|---|---|---|
| User | ~/.claude/settings.json | Personal settings across all projects |
| Project | <project>/.claude/settings.json | Team settings, committed to the repository |
| Local | <project>/.claude/settings.local.json | Personal, for one project, in .gitignore |
| Command line | --settings <file or JSON> | For a single run only |
| Policy | depends on the system | Enterprise policy |
| Global config | ~/.claude.json | Settings that are ignored in settings.json |
That last row is the one you'll find almost nowhere. Some settings live only in ~/.claude.json, and if you write them into settings.json they're silently ignored. That's also where Claude Code keeps your login session, the MCP server configuration and your folder trust decisions. The file normally writes itself and you rarely go in by hand — but you need to know it's there, because "I set the key and nothing happened" is most often explained by exactly this.
Enterprise policy isn't a single thing either. There are four sources, and they're ranked:
| Rank | Source |
|---|---|
| 1 | Server-side settings from claude.ai or an enterprise gateway |
| 2 | Operating system policy: the managed settings domain on macOS, the registry key HKLM\SOFTWARE\Policies\ClaudeCode on Windows |
| 3 | The managed settings file: /Library/Application Support/ClaudeCode/managed-settings.json, /etc/claude-code/managed-settings.json, C:\Program Files\ClaudeCode\managed-settings.json |
| 4 | The same registry key, but under HKCU — writable by the user themselves, and therefore not counted as administrative and applied only where nothing above it exists |
The OS policy and HKCU are re-read every half hour, the server-side settings once an hour. By default the sources don't add up: the highest-ranked one applies and the rest are discarded. You can change that with managedSourcesBehavior: "merge", but you have to set it in the highest of the deployed sources — a lower one can't invite itself into the merge, and HKCU never merges at all.
If an admin put something in and it "didn't arrive" — look at /status: since 2.1.243 there's a line about skipped sources that says outright which file was ignored.
Format: strict JSON
Here I have to correct myself, because I used to think otherwise and the internet repeats it often.
Settings files are strict JSON. A // comment or a trailing comma is a syntax error, and on the next launch the file is marked bad as a whole. No JSONC. (The confusion comes from JSONC genuinely existing elsewhere in the product — /terminal-setup, for instance, parses editor configuration with comments in it.)
The easiest way to check your file is to launch: settings errors are printed at startup. claude doctor will show them broken down.
A useful habit is the $schema line:
{ "$schema": "https://json.schemastore.org/claude-code-settings.json"}Your editor will start suggesting key names and underlining typos, and a typo in a key name is the most common reason a setting "doesn't work": unknown keys are silently ignored. One caveat: the schema sometimes lags behind the product. teammateDefaultModel is still in it, for instance, while Claude Code removed it in 2.1.234 and it affects nothing.
Who overrides whom
The order of levels is the one in the table above. But "overrides" isn't true for everything, and here are three exceptions that break your intuition.
Lists add up, they don't replace. If permissions.allow is set in both the user file and the project file, you get the union of the two. A higher level cannot remove an entry from a lower one — the only thing that can is the enterprise allowManagedPermissionRulesOnly. Any priority table that says "each level overrides the previous one" is wrong about lists.
Four lists behave differently: fallbackModel is taken whole from the highest file that defines it (it's an ordered chain, and mixing it makes no sense); modelPicker — whole from the highest among the enterprise source, --settings and the user file, and ignored in the project and local ones; availableModels from an admin applies as-is, without picking up your additions; modelSettings is resolved separately for each model.
For seven keys, a stricter value from below beats the enterprise one. Policy is normally absolute — not even --settings overrides it. But for these keys the stricter variant from any level wins, because nobody is going to stop you from forbidding yourself something extra: disableClaudeAiConnectors set to true, enableArtifact set to false (and disableArtifact: true), isolatePeerMachines set to true, remoteControlAtStartup set to false from a project or local file, crossSessionInbound with a stricter value on the accept — hold — reject scale, and useAutoModeDuringPlan and syncClaudeAiSkills set to false.
Project permissions wait for folder trust. permissions.allow and permissions.additionalDirectories from the project file only start working once you've confirmed trust in that folder. deny and ask take effect right away — they only restrict.
And what comes next is the important part, worth reading for anyone who runs claude -p in someone else's repository. In non-interactive mode the trust dialog is never shown, so the project's allow rules are discarded with a warning on stderr — but that repository's hooks do run, its env block does apply, its auth helper scripts do launch, the allowed-tools field of its skills does take effect, and the servers from its .mcp.json connect without a question. What gets discarded is the permissions, not the executable parts.
A safe launch in an unvetted folder means --setting-sources user, --bare, --restricted or --settings '{"disableAllHooks": true}'. Simply setting disableAllHooks in your own user file is not enough: the project file outranks it and will bring hooks back.
Environment variables aren't a level
Another thing usually drawn wrong. Environment variables don't sit "between" the settings levels: who overrides whom is decided separately for each variable-and-key pair.
ANTHROPIC_MODELfrom the shell overrides themodelkey from any file.ANTHROPIC_DEFAULT_MODELonly takes effect ifmodelisn't set anywhere.--modeland/modeloverrideANTHROPIC_MODEL.- And
CLAUDE_CODE_EFFORT_LEVELworks the other way round and overrides--effortand/effort.
And separately: a value from the env block in the settings beats an export from the shell, not the other way round as people tend to assume. Claude Code writes every entry of the block into the process environment on top of the inherited value. You can't delete a variable from a settings file — you can set it to an empty string, which counts as "not set" when a provider is picked (though child processes will get the empty value). Shell variables are read once at startup, while values from env are re-read when the file changes — except for subsystems that are configured only at launch, like telemetry.
The skeleton of the file
Scalars like model, theme, numbers and flags go at the top level. Grouped settings — permissions, env, hooks, statusLine, worktree, voice, sandbox, sshConfigs — are nested objects.
{ "$schema": "https://json.schemastore.org/claude-code-settings.json", "model": "opus", "outputStyle": "default", "theme": "dark", "autoCompactEnabled": true, "cleanupPeriodDays": 30, "includeCoAuthoredBy": false, "env": { "CLAUDE_CODE_USE_POWERSHELL_TOOL": "1", "DISABLE_TELEMETRY": "1" }, "permissions": { "allow": ["Bash(npm run build)", "Edit(src/**)"], "ask": ["Bash(git push:*)"], "deny": ["Read(./.env)"], "defaultMode": "acceptEdits", "additionalDirectories": ["../shared-lib"] }, "hooks": { "PostToolUse": [ { "matcher": "Edit|Write", "hooks": [{ "type": "command", "command": "npm run lint" }] } ] }, "statusLine": { "type": "command", "command": "~/.claude/statusline.sh", "padding": 1 }, "worktree": { "symlinkDirectories": ["node_modules"], "baseRef": "fresh" }, "enabledPlugins": { "formatter@anthropic-tools": true }}Authentication and providers
| Parameter | Type | What it does |
|---|---|---|
apiKeyHelper | string, path to a script | A script that prints an authorization value to standard output. Handy for temporary and rotating keys. |
proxyAuthHelper | string, command | [exp] A command that prints the proxy authorization header value. |
awsCredentialExport | string, path | A script that exports AWS credentials for Bedrock. |
awsAuthRefresh | string, path | A script that refreshes AWS authentication before it expires. |
gcpAuthRefresh | string, command | A command that refreshes Google Cloud authentication. |
otelHeadersHelper | string, path | A script that prints HTTP headers for telemetry export. |
policyHelper | object | [admin] An executable that computes policy settings at startup: path, timeoutMs, refreshIntervalMs. |
policyHelpers | object keyed by OS | [admin] The same, but separately for macOS, Linux, Windows and WSL. |
forceLoginMethod | claudeai, console, gateway | Pin the login method: subscription, billing through the Console, or a corporate gateway. |
forceLoginOrgUUID | string or array | [admin] Allow login only into the named organization, or into any one from the list. |
forceLoginGatewayUrl | string, URL | [admin] The mandatory corporate gateway address for login. |
forceRemoteSettingsRefresh | boolean | [admin] Block startup until fresh policy settings have been pulled. |
parentSettingsBehavior | first-wins, merge | [admin] How the parent layer from the SDK combines with the managed one. |
xaaIdp | object | [exp] Hooking up an external identity provider: issuer, clientId, callbackPort. |
The gateway value of forceLoginMethod is honored only from a source that lives on the machine itself: the policy file, the macOS settings domain, or the HKLM branch. In user, project and local settings, and in HKCU, it counts as unset — otherwise corporate login could be redirected from a repository.
Model, thinking, effort
| Parameter | Type | What it does |
|---|---|---|
model | string | The default model: an alias or a full identifier. |
availableModels | array of strings | [admin] An allowlist of models. An empty array means the default model only. |
enforceAvailableModels | boolean | [admin] Extend the allowlist to the "default" entry in the model picker as well. |
modelOverrides | object | [admin] A mapping from Anthropic identifiers to provider identifiers. |
modelPicker | object | Your own list in /model: entries of {model, label, description}; replaceBuiltInOptions replaces the built-in one. |
modelSettings | object | Settings bound to a specific model — currently the effort level. |
modelPricing | object | [admin] Your organization's rates instead of the price list: a discount multiplier and per-unit prices. |
advisorModel | string | The model for the advisor. |
agent | string | The agent name for the main thread: its system prompt, its restrictions and its model. |
alwaysThinkingEnabled | boolean | false turns thinking off. |
showThinkingSummaries | boolean | Show thinking summaries in the conversation and in the transcript. |
effortLevel | low, medium, high, xhigh | The saved effort level. The schema does not accept max. |
ultracode | boolean | [exp] xhigh plus permanent workflow orchestration. |
fastMode | boolean | Whether fast output mode is on. |
fastModePerSessionOptIn | boolean | Don't carry fast mode over between sessions. |
autoCompactEnabled | boolean | Compact the conversation automatically as the context fills up. |
autoCompactWindow | number, 100000–1000000 | The size of the auto-compaction window in tokens. |
precomputeCompactionEnabled | boolean | Prepare the compaction ahead of time, while work is still going on. |
switchModelsOnFlag | boolean | Switch to another model when the safety filter fires. Defaults to true. |
fallbackModel | array of strings | Models to fall back to when the main one is overloaded; tried in order. |
promptCacheTtl | 5m, 1h | The prompt cache lifetime for the main conversation. |
subagentPromptCacheTtl | 5m, 1h | The same for subagents; five minutes by default. |
Three defaults that change behavior and that hardly anyone writes about.
switchModelsOnFlag is on. Which means that when the safety filter fires, the model is swapped silently so the conversation isn't interrupted. Turn it off and an interactive session will stop and ask you, while a non-interactive run will fail the request with an error — for scripts that's often the better behavior, because a silent model swap in CI looks like an unexplained change of behavior.
promptCacheTtl picks itself: an hour on a subscription, five minutes otherwise. The environment variable overrides it.
effortLevel refuses max on purpose, so the top level doesn't stay switched on forever; you set it for a session with a command or a flag.
Tool permissions
The most practically important part of the file — and the most underrated for the number of pitfalls it holds. The nested permissions object:
| Field | Type | What it does |
|---|---|---|
allow | array of rules | What's allowed without asking. |
deny | array of rules | What's forbidden always. |
ask | array of rules | What always requires confirmation. |
defaultMode | see below | The default mode. |
disableBypassPermissionsMode | "disable" | Forbid the permission-bypass mode. |
additionalDirectories | array of paths | Extra directories inside the access scope. |
Alongside them sit top-level keys: skipDangerousModePermissionPrompt and skipAutoPermissionPrompt remember that you've already accepted the corresponding warning; allowManagedPermissionRulesOnly [admin] says to honor only the lists coming from policy; disableAutoMode turns auto mode off; useAutoModeDuringPlan allows using it in plan mode, and defaults to yes.
Modes
| Mode | What it does |
|---|---|
default | The normal one: ask when it needs to. The alias is manual, accepted in settings too since 2.1.200 |
acceptEdits | Accept file edits automatically |
plan | Analysis only, change nothing |
auto | The classifier makes the call |
dontAsk | Automatically deny anything that would have required a question |
bypassPermissions | Accept everything |
dontAsk doesn't mean "don't bother me with the small stuff". This is the most dangerous misunderstanding in the whole permissions topic, and I've repeated it myself. The mode doesn't loosen anything, it tightens it: everything that would raise a question in normal mode is denied automatically. Only what made it into allow, the built-in set of safe read commands, and whatever a hook approved will work. Your own ask rules don't ask in this mode, they refuse; a question from the agent to you is rejected too, even when it's allowed.
One more subtlety: the auto value has no effect from project and local settings — it has to be set in the user file. And sessions launched from the VS Code extension read only the user file, the managed one and --settings.
The shape of a rule
A rule is written as Tool(specifier): Bash(npm run build), Edit(src/**), Read(~/.zshrc).
{ "permissions": { "allow": ["Bash(npm run:*)", "Edit(src/**)", "Read(~/.config/**)"], "ask": ["Bash(git push:*)"], "deny": ["Read(./secrets/**)", "Read(./.env)"], "defaultMode": "acceptEdits", "additionalDirectories": ["../shared", "/tmp/workspace"] }}Looks simple. What comes next is twelve behavioral rules, each of which explains some popular "why doesn't my rule work" question.
Evaluation order: deny first, then ask, then allow
Rules are checked in a fixed order — deny, then ask, then allow — and the first match wins, not the most precise one. Two consequences follow, and both break expectations.
A broad deny overrides a narrow allow: a deny of Bash(aws *) will block an allow of Bash(aws s3 ls). There are no exceptions to a deny — there's no "forbid everything except" mechanism here.
A matching ask asks even when a more precise allow exists. That's not a bug, it's the way to say "this command I always confirm by hand", and it works on top of any permission.
Between settings layers it's the same story: a deny from the user file beats an allow from the project file and vice versa, because every deny from every layer is checked before any allow.
One more small thing with large consequences: a bare tool name in deny removes the tool from the context entirely. An entry of "Bash" in the deny list means the agent never learns the tool exists at all. Whereas Bash(rm *) leaves the tool visible and forbids only the calls that match.
Protected paths are checked before your rules
There's a list of paths whose modification is checked before anything looks at allow. Which is why Edit(.claude/**) in any settings file buys you precisely nothing — and it's the most common source of "why is my permission being ignored" questions.
The protected directories: .git, .config/git, .vscode, .idea, .husky, .cargo, .devcontainer, .yarn, .mvn and all of .claude except .claude/worktrees. Among files: .gitconfig, .gitmodules, every shell profile and startup file, .envrc, .npmrc, .yarnrc*, .pnp.cjs, bunfig.toml, .bazelrc, .pre-commit-config.yaml, lefthook.*, gradle-wrapper.properties, .ripgreprc, pyrightconfig.json, .mcp.json and .claude.json.
The logic is clear: these are all files whose editing changes how your own machine behaves on the very next command, up to and including what gets executed instead of git commit. What happens when something tries depends on the mode: normal and acceptEdits ask, plan allows it only if a bypass is available, auto hands it to the classifier, dontAsk refuses, bypassPermissions allows. The dialog also carries a separate option — allow editing your own settings for this session.
The deletion safety catch
rm and rmdir aimed at critical paths are approved by nothing: not by a rule in allow, not by a hook that returned an approval.
Critical paths are the filesystem root and any of its immediate children, the home folder, drive roots on Windows and their first-level directories, the current working folder and its parents, plus patterns inside added directories.
The most interesting bit is the table by mode, because it isn't built the way everyone expects:
| Mode | What happens |
|---|---|
normal, acceptEdits, plan | Asks |
auto | Hands it to the classifier |
dontAsk | Refuses |
bypassPermissions | Asks |
So the "skip every confirmation" mode is stricter here than auto mode: --dangerously-skip-permissions will still stop on a deletion like that.
Things that look harmless count too: rm -rf "$DIR"/* falls under the safety catch, because an empty variable turns it into a deletion starting at the root. Hiding the command inside a substitution, backticks or a process substitution won't help — the check sees through them.
The four path anchors
Read and Edit rules use .gitignore syntax, and it has four different ways to anchor a path. People mix them up constantly.
| Notation | What it's anchored to |
|---|---|
//path | The filesystem root |
~/path | The home folder |
/path | The settings source, not the drive root |
path or ./path | The current working folder |
The third row is the trap. A single leading slash does not mean an absolute path: it anchors the rule to the settings file it's written in. A Read(/secrets/**) rule in ~/.claude/settings.json means ~/.claude/secrets/**, and not secrets in your project at all. In project settings the same slash counts from the main working folder, in --settings from the folder of the named file, and rules from local settings have since 2.1.211 been anchored to the session's working folder rather than the repository root — so in a separate working copy Edit(/src/**) lands in that copy's own src.
A bare file name behaves the way it does in .gitignore and matches at any depth: Read(.env) is the same thing as Read(**/.env). But Read(//**/.env) is anchored to the filesystem root.
On Windows paths are converted to POSIX form before comparison: C:\Users\alice becomes /c/Users/alice. So a rule covering every drive is written as //**/.env, and one for a specific drive as //c/**/.env.
The same rule catches different depths in allow and in deny
A single-segment relative folder pattern behaves asymmetrically, and that's deliberate.
Edit(src/**) in allow matches only the src folder at the root of the working directory. The very same rule in deny or ask matches a src folder at any depth — so it'll catch vendor/pkg/src/lib.js too.
The intent is clear: a permission should be narrow, a prohibition broad. Every other form behaves identically in any type of rule: Edit(/src/**) and Edit(src/components/**) match only where they're written, Edit(**/src/**) matches everywhere. The behavior changed in 2.1.214: before that, Edit(src/**) caught any depth in permissions as well.
A colon only at the end, and the space before the asterisk matters
The form Bash(ls:*) is exactly the same thing as Bash(ls *). But it's recognized only at the end of a pattern: in Bash(git:* push) the colon is an ordinary character, and the rule won't match anything at all.
The space before the asterisk is part of the rule. Bash(ls *) requires a space and therefore doesn't match lsof; Bash(ls*) does. A trailing asterisk also catches the bare command with no arguments, but only if it's the only one in the rule: Bash(ls *) will match ls, while Bash(* --help *) will match npm --help x and won't match npm --help.
Everything before the first asterisk is compared literally. Hence an unpleasant surprise: Bash(git * main) permits any git subcommand, including -c with arbitrary configuration. Since 2.1.246, allow rules with an asterisk before the subcommand print a warning at startup.
Compound commands
The separators Claude Code understands: &&, ||, ;, |, |&, & and a newline. Each part has to match a rule on its own — there's no blanket permission for the whole line.
A special case: if an operator ends up at the end with nothing after it — npm test &&, say — the command counts as unparseable and isn't split at all. At which point even Bash(npm *) won't approve it.
When you answer "yes, and don't ask again" to a compound command, a separate rule is saved for every part that needed one. A change into a subfolder will produce its own read rule. No more than five rules will be saved out of a single command.
Output redirections >, >>, 2> are checked as a write to a file — against your Edit rules, the protected-path list and the working directories. /dev/null is excluded from the check; a target starting with ~ or containing a pattern always requires confirmation.
Which wrappers get stripped and which don't
Before matching against rules, these are removed from the command: timeout, time, nice, nohup, stdbuf, the built-ins command and builtin, zsh's noglob and a bare xargs — that last one only without flags, since xargs -n1 grep is parsed as the command xargs.
A leading assignment to a known safe variable is stripped too, so Bash(npm test *) will match NODE_ENV=test npm test. An allow rule won't get past an assignment to any other variable, while a deny rule gets past all of them.
The list is fixed and not configurable. And there isn't a single environment launcher in it: npx, docker exec, direnv exec, devbox run, mise exec are not stripped. The practical conclusion: Bash(devbox run *) is a permission for devbox run rm -rf ., because as far as the check is concerned this is the command devbox, not rm.
Separately, there are commands that a prefix rule can never approve: watch, setsid, ionice, flock, and find with -exec or -delete. In normal mode they'll always ask.
Rules for Write, Glob, NotebookEdit and MultiEdit are accepted and don't work
File permissions are checked only against Edit(...) and Read(...) rules. A rule like Write(docs/**) or Glob(docs/**) will be parsed, saved, shown in /permissions — and never used. Since 2.1.210 that prints a warning at startup.
Write Edit(...) instead of Write, NotebookEdit and MultiEdit, and Read(...) instead of Glob. A bare tool name with no path does work, though: you can forbid Write outright.
A useful consequence: a Read deny rule on a path blocks editing and writing there as well — but not NotebookEdit.
Symbolic links
Every access to a file is checked against two paths at once: the link itself and wherever it leads. And the rules are asymmetric about it.
A permission applies only if both paths matched. Which is why a link inside an allowed folder that leads outside it will still ask.
A prohibition applies if at least one matched. Which is why a link to a forbidden file is forbidden itself.
In practice: if Read(./project/**) is allowed and Read(~/.ssh/**) is denied, then ./project/key pointing at ~/.ssh/id_rsa will be blocked.
Rules on tool parameters
A little-known family. Deny and ask rules can match on a scalar field of the tool's input:
{ "permissions": { "deny": ["Agent(model:opus)", "Agent(isolation:worktree)", "Bash(run_in_background:true)"] }}One parameter per rule, nested fields aren't supported, * stands in for the value. A parameter the model didn't pass never matches — that is, Agent(model:opus) won't catch a call where no model was specified at all. The value is compared against what actually arrived, before normalization: the alias opus will match, the full identifier of the same model won't.
The tool's main field deliberately can't be matched this way: command, file_path, path, notebook_path, url are excluded. The rule Bash(command:rm *) is ignored with a warning — it would be far too easy to slip past with a compound command.
For MCP tools, parameter rules work only through the --disallowedTools flag: any rule with mcp__ and parentheses in a settings file is skipped and lands in the list of invalid settings and in the claude doctor output.
Patterns in the tool name
In deny and ask rules the tool name can be given as a pattern, and it has to cover the whole name: "*" is every tool, "mcp__*" is every MCP tool.
In allow rules a pattern is permitted only after the literal prefix mcp__<server>__, and the server name itself must contain no patterns. So mcp__github__get_* works, while "*", "B*" and "mcp__*" in allow are skipped with a warning and permit nothing.
And one more trap: the tool name on screen can differ from the canonical one. What's shown as "Stop Task" is canonically called TaskStop, and only the canonical name works in rules and in hook filters.
WebFetch — two different rules that look alike
A bare WebFetch and WebFetch(domain:*) are not the same thing, because the second form also edits the sandbox's domain list.
| Rule | What it does |
|---|---|
allow: WebFetch | Fetches pages without asking, but doesn't widen the sandbox — curl from the sandbox to the same host will still ask |
allow: WebFetch(domain:*) | Plus grants the sandbox network access |
deny: WebFetch | Removes the tool entirely |
deny: WebFetch(domain:*) | The tool stays, every fetch is rejected, the sandbox network is closed |
Patterns in a domain: *.example.com catches subdomains at any depth, but not example.com itself. In any other position an asterisk matches only the text between two dots — example.* will catch example.org and won't catch example.evil.com.
And a sober note: as long as the agent has shell access, WebFetch permissions don't restrict network access in any way whatsoever.
The built-in set of safe commands
Some commands run without a question in any mode, and that list is hard-wired: ls, cat, echo, pwd, head, tail, grep, find, wc, which, diff, stat, du, cd and read-only forms of git. You can't extend it, only override it with your own ask or deny rule.
But even it will ask if: an unquoted pattern shows up in a command that has write or execute flags (find, sort, sed, git — the pattern could expand into -delete); docker has -H, --context, --url or --connection; file has -m, --magic-file, -f or --files-from; the arguments contain a Windows network path; the command is longer than ten thousand characters or doesn't parse. Plus cd together with git will ask if the folder really does change — the new folder may have git hooks of its own.
PowerShell
Rules for PowerShell are built the same way, are compared case-insensitively and normalize the popular aliases: PowerShell(Get-ChildItem *) will match gci, ls and dir alike. The command is parsed into a syntax tree and split on |, ;, and on version seven also on && and ||; each part is checked separately.
Remove-Item has a check of its own, stricter than the one for rm: system paths and targets with a pattern — a bare *, anything ending in /* or \*, $dir/* included — are forbidden in every mode without asking, before the classifier even gets a look. Only the "working folder or its parent, recursively" case goes through the mode's normal rules, and that one is lifted by bypassing confirmations.
And separately about Windows: any command with a network path of the form \\server\share\file among its arguments will ask for confirmation even if it's harmless in every other respect — a path like that can steal Windows credentials.
Auto mode
Since 14 August 2026 this is the default mode for new sessions on Pro, Max and Team. Every action is decided by a classifier rather than by a list of rules, and it's configured through a separate autoMode object.
| Field | Type | What it does |
|---|---|---|
autoMode.environment | array of strings | What the classifier should know about your environment. This is what /auto-mode-setup fills in. |
autoMode.allow | array of strings | What it lets through. |
autoMode.soft_deny | array of strings | What it asks you about. |
autoMode.hard_deny | array of strings | What it refuses without asking. |
autoMode.classifyAllShell | boolean | Whether to run every single shell command through the classifier. Off by default. |
Three things here matter more than the table itself.
The string "$defaults" is required almost always. In any of the four lists it mixes in the stock set of rules. Leave it out and the entire built-in list for that section silently disappears — along with the soft blocks on force-push, on curl | bash, on deploying to production and on bypassing auto mode itself, and with the hard block on data exfiltration. Your rules are meant to extend the set, not replace it.
Narrow permissions bypass the classifier. A rule like Bash(npm test) keeps working in auto mode and is resolved before the classifier. Only broad permissions for arbitrary execution get suspended — Bash(*), interpreters with a wildcard — along with every rule that names a monitoring tool. Which means a narrow rule can let through a destructive argument nobody ever looked at. The fix is classifyAllShell: true, which disables every shell-allow rule for the duration of auto mode.
The classifier doesn't read project settings. It takes autoMode only from the user file, the enterprise one and --settings. Otherwise a repository could hand itself permissions; local settings were read up to version 2.1.207, but not any more.
You can inspect and pick apart the configuration from the terminal:
claude auto-mode config # what's in effect and where it came fromclaude auto-mode defaults # the stock rules of all four listsclaude auto-mode defaults --label 'Git Destructive' # the full text of a single ruleclaude auto-mode critique # a model's critique of your rulesclaude auto-mode reset --yes # reset to stock without askingThe critique subcommand is underrated: it asks the model to go through your own rules and point out the ones that are ambiguous, redundant, or bound to fire falsely.
The mode is turned off with the disableAutoMode key, and there's a trap here: the value has to be the string "disable". An array or true passes the schema without an error, but the code compares against exactly that string, and the mode quietly stays on. You can hide the setup wizard with "auto-mode-setup": "off" in skillOverrides; disableBundledSkills doesn't turn it off, because it's a built-in command, not a skill.
MCP servers
| Setting | Type | What it does |
|---|---|---|
enableAllProjectMcpServers | boolean | Auto-approve every server from the project's .mcp.json. |
enabledMcpjsonServers | array of names | Explicitly approved servers from .mcp.json. |
disabledMcpjsonServers | array of names | Explicitly rejected servers. |
allowedMcpServers | array of objects | [admin] Allowlist: by name, by command or by address. An empty array means none are allowed. |
deniedMcpServers | array of objects | [admin] Denylist. Takes precedence over the allowlist. |
allowManagedMcpServersOnly | boolean | [admin] The allowlist is read from policy only. |
allowAllClaudeAiMcps | boolean | [admin] Load the cloud connectors alongside the managed list. |
managedMcpServers | array of objects | [admin] The servers themselves, pushed out by an administrator: transport, connection and the map of allowed tools. |
That last row corrects a widespread claim I used to repeat myself: "servers are defined only in .mcp.json, and settings only carry the permissions for them". True for you, but not for an administrator: managedMcpServers in enterprise settings holds actual server configurations and is rolled out to everyone through the policy file or a device management system.
Ordinary servers, meanwhile, are defined in .mcp.json or through claude mcp add.
Hooks
Hooks deserve an article of their own, and I have one: it goes through every event, the exchange formats and working examples. Here — the settings keys and the things that break most often.
hooks is an object of the shape "event → array of matchers". A matcher has a matcher filter and a list of handlers.
{ "hooks": { "PostToolUse": [ { "matcher": "Edit|Write", "hooks": [ { "type": "command", "command": "npm run lint" }, { "type": "command", "command": "echo", "args": ["done"] } ] } ] }}There are thirty-three events. For tools: PreToolUse, PostToolUse, PostToolUseFailure, PostToolBatch. For the conversation: UserPromptSubmit, UserPromptExpansion, Stop, StopFailure, Notification, MessageDisplay. For the session: SessionStart, SessionEnd, Setup, InstructionsLoaded, ConfigChange. For compaction and model switching: PreCompact, PostCompact, PreModelSwitch, PostModelSwitch. For permissions: PermissionRequest, PermissionDenied. For subagents and tasks: SubagentStart, SubagentStop, TeammateIdle, TaskCreated, TaskCompleted. For files and directories: FileChanged, CwdChanged, DirectoryAdded, WorktreeCreate, WorktreeRemove. And two for MCP forms: Elicitation, ElicitationResult.
A handler comes in five kinds, set by the type field: command runs a program or a shell string, prompt asks a small fast model, agent dispatches a full-blown agent, http hits a URL, mcp_tool calls a tool on an MCP server. The shared optional fields are if with a condition, timeout, statusMessage for the spinner, once for a single run per session, and async with its relative asyncRewake.
| Setting | Type | What it does |
|---|---|---|
hooks | object | The hooks themselves. |
disableAllHooks | boolean | Turn off all hooks and status line execution. |
allowManagedHooksOnly | boolean | [admin] Run only the hooks that come from policy. |
allowedHttpHookUrls | array of strings | [admin] Allowlist of addresses for HTTP hooks. |
httpHookAllowedEnvVars | array of strings | Which environment variables HTTP hooks may interpolate into headers. |
disableSkillShellExecution | boolean | Forbid inline shell calls in skills and in your own commands. |
Three reasons a hook "runs but does nothing"
Exit code 1 blocks nothing. Only code 2 blocks, and only on about a third of the events. A 1, or any other non-zero code, is on most events just a non-blocking error in the log. And a 2 outranks your own JSON: even if you returned an "allow" decision, the 2 denies.
Where a 2 blocks: PreToolUse, UserPromptSubmit (erasing the prompt), UserPromptExpansion, Stop, SubagentStop, TeammateIdle, TaskCreated, TaskCompleted, ConfigChange, PostToolBatch, PreModelSwitch. Where it's ignored: PermissionRequest and PermissionDenied — there the JSON fields decide — and StopFailure. On PostToolUse a 2 doesn't block, it gets shown to the model. On WorktreeCreate any non-zero code aborts. And one more asymmetry: a timeout on PreToolUse doesn't block, while on PreModelSwitch it does.
The model almost never sees a hook's output. Plain text on standard output with exit code 0 lands in the debug log, not in the conversation. It's shown to the model on exactly four events: UserPromptSubmit, UserPromptExpansion, SessionStart and PostModelSwitch. The error stream is never shown anywhere, ever. On the other events the only way to get something to the model is a structured response — the additional-context field or a system message. And the JSON is parsed only if the output starts with { and ends with }.
The filter is sometimes ignored entirely, and sometimes a regular expression. "*", an empty string, or a missing field all mean "everything". A filter made up only of letters, digits, _, -, spaces, commas and | is an exact match or a list of alternatives. Any other character turns it into a regular expression, which is matched unanchored unless you write the anchors yourself. Case matters.
And the filter isn't always about a tool name. On SessionStart it's compared against how the session started, on SessionEnd against the reason it ended, on compaction against manual or auto, on ConfigChange against which settings file changed, on FileChanged against the file name, on a model switch against the canonical model name. While UserPromptSubmit, PostToolBatch, Stop, CwdChanged, TeammateIdle, the task events, the worktree ones and MessageDisplay take no filter at all and silently ignore whatever you wrote.
The default timeouts aren't uniform: command, http and mcp_tool get ten minutes, except thirty seconds on UserPromptSubmit and on the model-switch events, and ten on MessageDisplay; prompt gets thirty seconds, agent gets a minute; all the SessionEnd hooks together get a second and a half. Async ones aren't limited at all.
On Windows it's worth remembering the form with a separate argument list: it runs without a shell and needs a real executable — .cmd and .bat wrappers require either the string form or launching through an interpreter.
Git: commits, pull requests, attribution
| Setting | Type | What it does |
|---|---|---|
attribution | object | Attribution text in commits and descriptions; an empty string hides it. The sessionUrl field controls the link to the session. |
includeCoAuthoredBy | boolean | [deprecated] Add co-authorship. Better to use attribution. |
includeGitInstructions | boolean | Include the built-in commit instructions in the system prompt. On by default. |
prUrlTemplate | string | Template for a pull request link: {host}, {owner}, {repo}, {number}, {url}. |
doneMeansMerged | boolean | [experimental] "Done means merged": the agent keeps going until the pull request is ready to merge. |
{ "attribution": { "commit": "", "pr": "" }, "includeGitInstructions": true}Interface and terminal
| Setting | Type | What it does |
|---|---|---|
theme | see below | Color theme. |
editorMode | normal, vim | Key mode in the input box. Replaced the removed /vim command. |
keybindingFlavor | classic, readline | How the word-wise keys behave. readline is the Bash way: delete back to a space, jump by words, punctuation separates words. |
vimInsertModeRemaps | object | Your own escapes from insert mode, for example {"jj": "<Esc>"}. |
emojiCompletionEnabled | boolean | Emoji autocomplete in the input box. On by default. |
wheelScrollAccelerationEnabled | boolean | Accelerated scrolling with the wheel. Fullscreen mode only. |
defaultView | chat, transcript | Which view a session opens in. |
axScreenReader | boolean | Flat output for screen readers. |
tui | default, fullscreen | The interface renderer. |
viewMode | default, verbose, focus | Transcript view mode at startup. |
verbose | boolean | Full tool output instead of shortened summaries. |
autoScrollEnabled | boolean | Auto-scroll the conversation to the bottom. Fullscreen mode only. |
syntaxHighlightingDisabled | boolean | Turn off syntax highlighting in diffs. |
prefersReducedMotion | boolean | Reduce or remove animations. |
showTurnDuration | boolean | Show how long each turn took. |
showMessageTimestamps | boolean | Stamp messages with the time they arrived. |
terminalProgressBarEnabled | boolean | Report the progress of long operations through terminal escape sequences. |
terminalTitleFromRename | boolean | Let /rename change the tab title. On by default. |
spinnerTipsEnabled | boolean | Show tips in the waiting spinner. |
spinnerVerbs | object | Your own spinner verbs: add them to the stock ones or replace them. |
spinnerTipsOverride | object | Your own tips: as a list, from a file, or with your own heading instead of "Tip". |
footerLinksRegexes | array of objects | Your own link badges in the footer, matched by regular expression. Five at most. |
spellcheck | object | Underline typos in the input box. Needs a checker installed: aspell, hunspell or ispell. |
companyAnnouncements | array of strings | Announcements at startup; if there are several, a random one is shown. |
todoFeatureEnabled | boolean | Turn on the task tracking panel. |
Values for theme: auto (from the terminal background), dark, light, light-daltonized, dark-daltonized, light-ansi, dark-ansi, plus custom:<name> for a theme from ~/.claude/themes/ and custom:<plugin>:<name> for one from a plugin.
Some keys are read only from the user file, --settings and policy: spinnerTipsOverride with a tips file, footerLinksRegexes and spellcheck. A project file can't override them — otherwise a repository could paint an arbitrary link into your interface.
Settings that live in ~/.claude.json
These keys are silently ignored in settings.json. Usually Claude Code or /config writes them itself, but they're worth knowing about.
| Setting | Type | What it does |
|---|---|---|
permissionExplainerEnabled | boolean | [global] Ctrl+E on a permission dialog shows a breakdown of the command: what it does, why, and what could go wrong, with a risk rating. On by default. |
diffTool | auto, terminal | [global] Where to show the diff of an edit when an IDE is connected. In the IDE by default. |
autoConnectIde | boolean | [global] Connect to a running IDE automatically when started from an external terminal. Off by default. |
autoInstallIdeExtension | boolean | [global] Install the extension automatically when launched from the VS Code terminal. On by default. |
externalEditorContext | boolean | [global] When editing a prompt in an external editor via Ctrl+G, show the previous answer as comments at the top of the buffer. |
skippedMarketplaces | array of strings | [global] Marketplaces whose installation you declined. |
skippedPlugins | array of strings | [global] Plugins whose installation you declined. |
The first key is worth learning about: Ctrl+E on a prompt asking whether to run a command gives you a human explanation of what that command does — without running it. On an unfamiliar command from someone else's repository that's exactly the button you've been missing.
Status line
| Setting | Type | What it does |
|---|---|---|
statusLine | object | Your own status line at the bottom, drawn by an external script. |
subagentStatusLine | object | A status line for each subagent in the agents panel. |
Fields of statusLine: type with the value "command", command with the script, padding, refreshInterval — recompute once every so many seconds — and hideVimModeIndicator if the script draws the vim mode itself.
{ "statusLine": { "type": "command", "command": "~/.claude/statusline.sh", "padding": 1, "refreshInterval": 5 }}The script receives JSON on its input with the session context: model, directory, cost, context fill. It prints one line. This is probably the most underrated setting of the lot: permanently visible spend figures change behavior far more than any instruction about being frugal. Just keep in mind that disableAllHooks turns it off too.
Context, memory, sessions
| Setting | Type | What it does |
|---|---|---|
cleanupPeriodDays | number from 1 | How many days to keep transcripts. Thirty by default. It also sets the lifetime of checkpoints. |
desktopSessionCleanupPeriodDays | number from 0 | A cap on the exception that lets desktop app sessions survive the usual cleanup. |
crossSessionInbound | accept, hold, refuse | What to do with messages from your other sessions. |
dialogExpiry | 60s, 5m, 10m, never | How long before an unanswered dialog goes stale. Five minutes by default. |
askUserQuestionTimeout | same values | The same for the agent's questions to you. They don't expire by default. |
autoContinueAtUsageLimit | boolean | Continue the session once the plan limit resets. On by default. |
autoMemoryEnabled | boolean | Automatic project memory. |
autoMemoryDirectory | string, path | The storage directory for auto memory. Read from any settings level. |
autoDreamEnabled | boolean | Background memory consolidation. |
fileCheckpointingEnabled | boolean | Snapshot files before edits so /rewind can restore them. |
outputStyle | string | The assistant's answering style. |
language | string | Preferred language for answers and voice input, for example "russian". |
promptSuggestionEnabled | boolean | Show suggestions for prompts. |
awaySummaryEnabled | boolean | [experimental] A session summary when you come back after being away for more than five minutes. |
showClearContextOnPlanAccept | boolean | Offer to clear the context when a plan is accepted. Off by default. |
plansDirectory | string, path | Directory for plan files, relative to the project root. |
claudeMd | string | [admin] CLAUDE.md-style instructions as organizational memory. |
claudeMdExcludes | array of patterns | Which CLAUDE.md files not to load. The policy file can't be excluded. |
respectGitignore | boolean | The file picker honors .gitignore. On by default; .ignore is always honored. |
fileSuggestion | object | Your own source of file suggestions for @ mentions. |
Two things are worth knowing about autoContinueAtUsageLimit: it's on by default, and it's read only from the user file, --settings and policy — meaning a project or local file that sets it isn't ignored, it turns the feature off.
Skills
| Setting | Type | What it does |
|---|---|---|
skillOverrides | object | Skill visibility: on, name-only — the name only, without the description, user-invocable-only — hide it from the model but keep invocation by name, off — hide it completely. |
skillListingMaxDescChars | number | Character limit on a skill's description in the listing. 1536 by default. |
skillListingBudgetFraction | number 0–1 | Share of the context for the whole skill listing. One percent by default. |
disableSkillShellExecution | boolean | Forbid inline shell calls in skills and in your own commands. |
disableBundledSkills | boolean | Don't load the bundled skills. /doctor is the exception. |
syncClaudeAiSkills | boolean | Whether to pull skills synced with claude.ai. Only the value false is honored. |
syncClaudeAiPlugins | boolean | The same for plugins. |
skillOverrides is worth knowing for anyone with a lot of skills: their descriptions sit in the context permanently, and name-only on the rarely needed ones frees up a noticeable chunk. That same key is also how you stop the agent from running a particular command on its own while keeping it available to you: the value user-invocable-only.
Plugins and marketplaces
| Setting | Type | What it does |
|---|---|---|
enabledPlugins | object | Which plugins are enabled; the key is plugin@marketplace. |
pluginConfigs | object | The configuration of each plugin. Ignored in project settings. |
extraKnownMarketplaces | object | Extra marketplaces for this repository. |
strictKnownMarketplaces | array of sources | [admin] Only these sources may be added. Supports owner/* — a whole organization. |
blockedMarketplaces | array of sources | [admin] Blocked sources. |
pluginSuggestionMarketplaces | array of strings | [admin] Whose plugins may show up in install suggestions. |
strictPluginOnlyCustomization | boolean or array | [admin] Forbid customization outside plugins for skills, agents, hooks, mcp. |
pluginTrustMessage | string | [admin] Extra text for the warning shown before installation. |
disableCommandPluginSources | boolean | [admin] Forbid marketplaces of the "a local command prints the path to a plugin" kind. |
disableSideloadFlags | boolean | [admin] Forbid slipping plugins in through flags. |
Workflows, agents, teammates
| Setting | Type | What it does |
|---|---|---|
enableWorkflows | boolean | Turn workflows on or off. |
disableWorkflows | boolean | Turn workflows off. |
workflowKeywordTriggerEnabled | boolean | The word "ultracode" in a prompt turns workflows on for that turn. On by default. |
skipWorkflowUsageWarning | boolean | [experimental] The warning about the cost of multi-agent workflows has been acknowledged. |
workflowSizeGuideline | unrestricted, small, medium, large | A guideline for fan-out size: fewer than five agents, fewer than fifteen, fewer than fifty, or no hint at all. |
disableAgentView | boolean | [admin] Turn off the agents screen, background launches and the background service. |
disableAutoMode | "disable" | Turn off auto mode. As a string only. |
teammateMode | in-process, tmux, iterm2, auto | How teammates are displayed. in-process by default. |
The auto value of teammateMode is precisely defined: split panes if the session is running inside tmux, or inside iTerm2 with its command line utility available, or if tmux is installed; otherwise everything runs inside the process. The iterm2 value means iTerm2's native split panes, and it arrived in 2.1.186.
The teammateDefaultModel key is still in the schema, but it was removed from the product in 2.1.234 and affects nothing.
Worktrees
The nested worktree object controls how separate working copies are created for sessions and background agents.
| Field | Type | What it does |
|---|---|---|
symlinkDirectories | array of strings | What to symlink from the main repository so the disk doesn't balloon. Nothing by default. |
sparsePaths | array of strings | Which paths to include through a sparse checkout. A big speed-up in monorepos. |
baseRef | fresh, head | What new copies branch from: the remote main branch or your local state. |
bgIsolation | worktree, none | Isolation for background sessions. By default a background agent doesn't touch the main tree. |
location | string, path | Where the desktop app creates copies for sessions over SSH. The CLI doesn't read it yet. |
{ "worktree": { "symlinkDirectories": ["node_modules", ".cache"], "sparsePaths": ["packages/app", "packages/shared"], "baseRef": "fresh", "bgIsolation": "worktree" }}Remote control, SSH, environments
| Setting | Type | What it does |
|---|---|---|
disableRemoteControl | boolean | [admin] Turn remote control off entirely. |
remoteControlAtStartup | boolean | Bring up the remote control bridge in every session. |
isolatePeerMachines | boolean | Require confirmation before a message goes out to a session on another machine. |
autoUploadSessions | boolean | Mirror local sessions to the web for viewing only. |
daemonColdStart | transient, ask | When there's no background service: bring one up for the session, or offer to install it permanently. |
remote | object | The default environment for remote sessions. |
sshConfigs | array of objects | [admin] Preconfigured SSH connections: id, name, sshHost, sshPort, sshIdentityFile, startDirectory. |
sshHostAllowlist | array of patterns | [admin] Restrict the app's SSH sessions to these hosts. * is any, *.example.com is the domain and its subdomains. |
disableDesktopLocalSessions | boolean | [admin] Forbid sessions on the machine itself in the desktop app: work over SSH only. |
browserExternalPageTools | "disabled" | [admin] Forbid the agent from reading or touching external pages in the app's browser. Local previews still work. |
disableBrowserExternalNavigation | boolean | [admin] Forbid external navigation in the app's browser, for the agent and the human alike. |
disableMobileSimulatorTools | boolean | [admin] Take the iOS simulator tools away from the agent; the human keeps the panel. |
requireCoworkFullVmSandbox | boolean | [admin] Run tools inside an isolated virtual machine. |
channelsEnabled | boolean | [admin] Allow channel notifications. |
allowedChannelPlugins | array of objects | [admin] Allowlist of channel plugins. |
Three of these keys accept only a real boolean true: the string "true" or a 1 will be ignored, with a warning in the log. They are disableDesktopLocalSessions, disableBrowserExternalNavigation and disableMobileSimulatorTools. The terminal CLI doesn't read them at all — they're about the desktop app.
requireCoworkFullVmSandbox has an important side effect: inside a full virtual machine there is neither a device policy nor an enterprise settings file — you'll have to deliver those some other way.
{ "remote": { "defaultEnvironmentId": "env-123" }, "sshConfigs": [ { "id": "prod-box", "name": "Prod", "sshPort": 22, "startDirectory": "~/app" } ]}Notifications, voice, breaks
| Setting | Type | What it does |
|---|---|---|
preferredNotifChannel | auto, iterm2, terminal_bell, iterm2_with_bell, kitty, ghostty, notifications_disabled | Which channel to send system notifications through. |
inputNeededNotifEnabled | boolean | A push to your phone when a confirmation or a question is waiting. |
agentPushNotifEnabled | boolean | Let the agent send proactive mobile pushes. |
voice | object | Voice input: enabled, mode with the value hold or tap, autoSubmit. |
voiceEnabled | boolean | Dictation when signed in through claude.ai, if the organization's policy allows it. Not the same thing as voice.enabled, which overrides it. |
breakReminder | object | [experimental] A reminder to take a break after a long uninterrupted stretch. Never blocks. |
quietHours | object | [experimental] Quiet hours: one gentle nudge per session inside the given window of local time. |
{ "voice": { "enabled": true, "mode": "hold", "autoSubmit": true }, "breakReminder": { "enabled": true, "intervalMinutes": 120 }, "quietHours": { "enabled": true, "start": "22:00", "end": "07:00" }}Sandbox and network
The sandbox object controls what processes inside the isolation are allowed to do. It's the longest section of the schema and the least used one — but if you let the agent run in a mode where it doesn't ask for permissions, this is exactly the section to read.
Let me correct a common structural mistake right away: read and write paths live not directly in sandbox, but in sandbox.filesystem. A rule like "sandbox": {"denyRead": [...]} won't do anything.
| Field | Type | What it does |
|---|---|---|
enabled | boolean | Turn the sandbox on. |
enabledPlatforms | array of macos, linux, wsl, windows | [admin] Limit the entire configuration to these systems. On the rest it's inert as a whole. |
autoAllowBashIfSandboxed | boolean | Automatically allow commands when they run inside the sandbox. |
allowUnsandboxedCommands | boolean | Allow a blocked command to be retried outside the sandbox. Defaults to true. |
failIfUnavailable | boolean | Fail if the sandbox couldn't be brought up, instead of quietly starting without it. |
excludedCommands | array of strings | Commands taken out of the sandbox; set by /sandbox exclude. |
ignoreViolations | object | Which violations not to show. |
filesystem.allowWrite | array of paths | Additional paths that are writable. |
filesystem.denyWrite | array of paths | Paths forbidden for writing, including ones inside an allowed folder. |
filesystem.denyRead | array of paths | Paths forbidden for reading. |
filesystem.allowRead | array of paths | Exceptions that re-allow reading inside forbidden areas. |
filesystem.allowManagedReadPathsOnly | boolean | [admin] Read paths come from policy only. |
filesystem.disabled | boolean | Turn off the filesystem half of the sandbox. Not from project settings. |
network.allowedDomains | array of strings | Allowed domains. |
network.deniedDomains | array of strings | Domains that are always blocked. |
network.allowManagedDomainsOnly | boolean | [admin] Allow only domains from policy. |
network.strictAllowlist | boolean | Allow only explicitly listed domains. |
network.allowUnixSockets | array of strings | Allowed Unix sockets. macOS only. |
network.allowAllUnixSockets | boolean | Allow all Unix sockets. |
network.allowLocalBinding | boolean | Allow binding to local ports. |
network.allowMachLookup | array of strings | Allowed Mach services. macOS only, and a wildcard is permitted only at the end. |
network.httpProxyPort | number | Port of the sandbox's internal HTTP proxy. |
network.socksProxyPort | number | Port of the internal SOCKS proxy. |
network.tlsTerminate | object | [exp] Terminate TLS with your own certificate authority — needed to mask secrets. |
credentials.envVars | array of objects | What to do with secrets in variables: deny or mask, plus extraction and parsing. |
credentials.files | array of objects | The same for files holding secrets. |
credentials.awsPairs | array of objects | Pairs of AWS variables that the sandbox re-signs. |
credentials.sigv4 | object | What to do with AWS request shapes that can't be re-signed: streaming upload, a presigned URL, and asymmetric signing. Each field is deny or passthrough; everything is denied by default. |
credentials.allowPlaintextInject | boolean | Allow injecting secrets in plaintext. Off by default. |
allowAppleEvents | boolean | Allow Apple Events. macOS only. |
enableWeakerNetworkIsolation | boolean | Weakens protection. Weaker network isolation on macOS. |
enableWeakerNestedSandbox | boolean | Weakens protection. Allow a weaker nested sandbox. |
bwrapPath | string, absolute path | [admin] Your own bubblewrap binary on Linux. |
socatPath | string, absolute path | [admin] Your own socat binary. |
ripgrep | object | Your own ripgrep for the sandbox. Project settings don't override it. |
Three things are worth calling out.
allowUnsandboxedCommands is on by default. Meaning the agent can retry a sandbox-blocked command outside the sandbox through a special parameter. If you turned the sandbox on for isolation, that's most likely not what you wanted — switch it off with an explicit false.
enabledPlatforms makes the configuration inert as a whole. On a system that isn't in the list there is no sandbox, no automatic permissions, no warning at startup, and no failure from failIfUnavailable. Silently, as if the section weren't there.
Secret masking doesn't work everywhere. On macOS and Windows the mask mode degrades into deny: there's nothing there to substitute the value on the fly. Masking entries also have an onExtractNoMatch field — what to do when the regular expression found nothing: warn (the default) lets the variable through unmasked, deny strips it inside the sandbox, error stops the run.
{ "sandbox": { "enabled": true, "autoAllowBashIfSandboxed": true, "allowUnsandboxedCommands": false, "network": { "allowedDomains": ["api.example.com", "*.githubusercontent.com"], "deniedDomains": ["telemetry.example.com"] }, "filesystem": { "denyRead": ["~/.ssh", "~/.aws"], "denyWrite": ["~/.config"] } }}Updates and everything else
| Setting | Type | What it does |
|---|---|---|
autoUpdatesChannel | latest, stable, rc | Auto-update channel. |
minimumVersion | string | Prevents a downgrade below the given version when switching channels. |
requiredMinimumVersion | string | [admin] Below this version the organization won't let it run. |
requiredMaximumVersion | string | [admin] Version ceiling for the organization. |
managedSourcesBehavior | first-wins, merge | [admin] How several policy sources add up. |
wslInheritsWindowsSettings | boolean | [admin, Windows] WSL reads policy from the full Windows policy chain. |
processWrapper | string | [admin] What to wrap spawned processes in. |
allowManagedPermissionRulesOnly | boolean | [admin] Honor permission rules from policy only. |
defaultShell | bash, powershell | Shell for commands typed with !. Defaults to bash on every platform. |
respondToBashCommands | boolean | Respond to commands typed with !. On by default. |
feedbackSurveyRate | number 0–1 | Probability of showing a session-quality survey. |
feedbackDrafts | notify, quiet, off | Whether the agent may draft feedback on its own. You still send it yourself. |
enableArtifact | boolean | Artifact publishing. Turning it off in any layer wins. |
disableArtifact | boolean | [deprecated] Its inverted predecessor: true turns it off, false is ignored. |
disableClaudeAiConnectors | boolean | Don't load cloud connectors. |
skipWebFetchPreflight | boolean | Skip the blocked-address check in strict corporate environments. |
$schema | string | Link to the settings schema: autocomplete and validation in the editor. |
The schema accepts a few more housekeeping keys: modelProposedGoals, totalTokensReminder with its relatives, and disableDeepLinkRegistration. They're internal, never surface in the interface, and aren't documented anywhere.
Environment variables
The env block in the settings is a "name → value" object. Every value is a string: numbers and flags go in quotes, "PORT": "3000", a flag is "1".
An honest caveat about completeness: the official documentation lists three hundred and forty-nine variables by name, including per-region ones for every model at every provider plus the whole telemetry set. Retelling them here would be pointless. Below are the ones actually used, plus the behavior of the env block, which isn't collected in one place anywhere.
{ "env": { "CLAUDE_CODE_USE_POWERSHELL_TOOL": "1", "ANTHROPIC_MODEL": "claude-opus-5", "BASH_DEFAULT_TIMEOUT_MS": "120000", "DISABLE_TELEMETRY": "1" }}How the env block behaves
It beats an export from the shell. The value from the settings file is written into the process environment on top of the inherited one. That's exactly the opposite of what people usually expect.
A variable can't be deleted — only set to an empty string. When a provider is picked an empty value counts as unset, but child processes get exactly that empty string.
Values are re-read on the fly when the file changes — except for subsystems configured only at startup, such as telemetry. And since 2.1.246, /cd layers the new folder's env over the old one.
Project and local settings aren't allowed everything. Three groups are dropped: variables that set file locations (CLAUDE_CONFIG_DIR, CLAUDE_CODE_TMPDIR, HOME, TMPDIR, TMP, TEMP, XDG_*); variables that turn on dumping session contents (OTEL_LOG_RAW_API_BODIES, ENABLE_BETA_TRACING_DETAILED, BETA_TRACING_ENDPOINT); and variables affecting startup and syncing (CLAUDE_CODE_PROCESS_WRAPPER, CLAUDE_CODE_SYNC_SKILLS, CLAUDE_CODE_SYNC_PLUGINS, the plugin cache and seed folder). The list grew in 2.1.251, as it happens. The warning about it is only visible under debug.
A few more variables are ignored in any file and read only from the launch environment: CLAUDE_CODE_REMOTE, CLAUDE_CODE_ACCOUNT_UUID, the cross-session exchange socket and token, CLAUDE_CODE_PROJECT_DIR_NAME and CLAUDE_CODE_RESTRICTED.
And the other direction, which hardly anyone writes about: Claude Code sets variables for child processes itself. They're visible from hooks and from any script it launches: CLAUDECODE=1, CLAUDE_CODE_CHILD_SESSION=1, CLAUDE_CODE_SESSION_ID, CLAUDE_PID — its own process id, CLAUDE_EFFORT with the current effort level (the ultracode mode shows up as xhigh), and in cloud sessions CLAUDE_CODE_REMOTE=true plus the remote session id. A hook that needs the effort level, or needs to tell a child session from the main one, takes it from here instead of guessing.
Providers and authentication
| Variable | What it does |
|---|---|
ANTHROPIC_API_KEY, ANTHROPIC_AUTH_TOKEN | Anthropic API key and token. |
CLAUDE_CODE_OAUTH_TOKEN | Subscription token — signing in without an interactive login. |
ANTHROPIC_BASE_URL | Your own API base URL: a proxy or a gateway. |
ANTHROPIC_CUSTOM_HEADERS | Extra HTTP headers on API requests. |
ANTHROPIC_BETAS | Beta headers in requests. |
CLAUDE_CODE_USE_BEDROCK, CLAUDE_CODE_USE_VERTEX | Use Amazon Bedrock or Google Cloud as the provider. |
ANTHROPIC_BEDROCK_REGION_PREFIX | Which cross-region profile to prefer over the one derived from the AWS region. |
ANTHROPIC_BEDROCK_BASE_URL, ANTHROPIC_VERTEX_BASE_URL | Your own provider URLs. |
AWS_BEARER_TOKEN_BEDROCK, ANTHROPIC_VERTEX_PROJECT_ID | Bedrock credentials and the Google Cloud project. |
CLAUDE_CODE_SKIP_BEDROCK_AUTH, CLAUDE_CODE_SKIP_VERTEX_AUTH | Skip provider authentication when a gateway handles it. |
HTTPS_PROXY, HTTP_PROXY, NO_PROXY | Proxy for outgoing traffic. |
NODE_EXTRA_CA_CERTS | Your own root certificate for a corporate proxy. |
There are more than two or three providers, by the way: besides the Anthropic API, Amazon Bedrock and Google Cloud, there's support for Microsoft Foundry and Claude Platform on AWS, and each has its own set of variables and its own mapping of aliases to models.
Models, context, limits
| Variable | What it does |
|---|---|
ANTHROPIC_MODEL | The main model. Overrides the model key from the files. |
ANTHROPIC_DEFAULT_MODEL | Model for new sessions; applies only when model isn't set anywhere. |
ANTHROPIC_DEFAULT_OPUS_MODEL and the same for sonnet, haiku and fable | What the aliases actually point at. |
ANTHROPIC_SMALL_FAST_MODEL | [deprecated] The small fast model. Replaced by ANTHROPIC_DEFAULT_HAIKU_MODEL. |
CLAUDE_CODE_SUBAGENT_MODEL | Model for subagents. |
CLAUDE_CODE_EFFORT_LEVEL | Effort level. Overrides --effort and /effort. |
MAX_THINKING_TOKENS | Token budget for thinking. |
CLAUDE_CODE_MAX_OUTPUT_TOKENS, MAX_MCP_OUTPUT_TOKENS | Limit on output tokens and on MCP output. |
CLAUDE_CODE_DISABLE_1M_CONTEXT | Don't use the million-token window. |
CLAUDE_CODE_MAX_CONTEXT_TOKENS | Your own ceiling for the context window. |
CLAUDE_CODE_AUTO_COMPACT_WINDOW, CLAUDE_AUTOCOMPACT_PCT_OVERRIDE | Auto-compaction window, in tokens and in percent. |
DISABLE_AUTO_COMPACT | Turn auto-compaction off. |
DISABLE_PROMPT_CACHING | Turn prompt caching off. |
API_TIMEOUT_MS, CLAUDE_CODE_MAX_RETRIES | API request timeout and the number of retries. |
Behavior and environment
| Variable | What it does |
|---|---|
CLAUDE_CONFIG_DIR | A different configuration folder entirely. |
CLAUDE_CODE_PROJECT_DIR_NAME | Short name of the folder holding the project's transcripts and auto-memory. Only set together with CLAUDE_CONFIG_DIR and only from the launch environment. |
CLAUDE_CODE_TMPDIR | Directory for temporary files. |
CLAUDE_CODE_USE_POWERSHELL_TOOL | Use the PowerShell tool instead of bash. |
CLAUDE_CODE_GIT_BASH_PATH | Path to Git Bash on Windows. |
CLAUDE_CODE_SHELL, CLAUDE_CODE_SHELL_PREFIX | The shell and a prefix for shell commands. |
CLAUDE_ENV_FILE | A script run before every shell command in the same process — which is how virtualenv activation calls survive. |
CLAUDE_BASH_MAINTAIN_PROJECT_WORKING_DIR | Return to the original folder after every command: a cd inside a call isn't kept. |
BASH_DEFAULT_TIMEOUT_MS, BASH_MAX_TIMEOUT_MS | Default and maximum command timeout. |
BASH_MAX_OUTPUT_LENGTH | Limit on command output length. |
CLAUDE_CODE_TOOL_MEMORY_LIMIT | Memory limit for commands via control groups. Linux only. |
MCP_TIMEOUT, MCP_TOOL_TIMEOUT | Server startup timeout and tool call timeout. |
CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS | How many subagents run at once. Twenty by default. |
CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH | Nesting depth for subagents. Three by default; one disables nesting. |
CLAUDE_CODE_MAX_TOOL_USE_CONCURRENCY | How many parallel read-only calls. Ten by default. |
TASK_MAX_OUTPUT_LENGTH | Ceiling on subagent output in characters: 32000 by default, 160000 maximum. |
CLAUDE_CODE_ENABLE_TASKS | Which task tools to expose: the new ones by default, zero brings back the old single tool. |
CLAUDE_CODE_ENABLE_TODO_TOOLS | Bring the task tools back on models where they were removed. |
USE_BUILTIN_RIPGREP | Use the bundled ripgrep. |
CLAUDE_CODE_WEBFETCH_CACHE_TTL_MS | How long fetched pages stay cached. Fifteen minutes by default. |
CLAUDE_CODE_DISABLE_BACKGROUND_TASKS | Turn background tasks off. |
CLAUDE_CODE_DISABLE_CLAUDE_MDS | Don't load CLAUDE.md files. |
CLAUDE_CODE_SAFE_MODE, CLAUDE_CODE_RESTRICTED, CLAUDE_CODE_SIMPLE | Same as the launch flags of the same names. |
Three traps in this table are worth spelling out.
MCP timeouts differ by five orders of magnitude. Server startup is thirty seconds. But a tool call defaults to roughly twenty-eight hours — effectively no limit at all. On top of that, HTTP servers and cloud connectors cap every request at a minute, and that's a separate limit.
CLAUDE_CODE_PROJECT_DIR_NAME does nothing on its own — only together with CLAUDE_CONFIG_DIR, and only from the environment, not from a settings file.
Safe mode takes away more than it looks like. CLAUDE_CODE_SAFE_MODE isn't just instructions and skills: it also skips plugins, hooks, MCP servers, your own commands and agents, output styles, workflows, themes, keybindings, the status line, the file suggestion source, language servers and auto-memory. All that's left is corporate policy, including the hooks and status line it defines. It's a "turn off everything I configured" debugging mode, and for tracking down a broken configuration it's perfect.
Rendering and accessibility
In one line, because there are many variables and you need them rarely. The classic renderer comes back with CLAUDE_CODE_DISABLE_ALTERNATE_SCREEN, and it's stronger than both CLAUDE_CODE_NO_FLICKER and the tui setting. There are separate switches for the mouse and clicks, scroll speed, virtual scrolling, full redraw, the native cursor, syntax highlighting, hyperlinks and truecolor in tmux. For accessibility there's CLAUDE_AX_SCREEN_READER and its relatives.
Privacy, telemetry, updates
| Variable | What it does |
|---|---|
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC | A single switch for all non-essential outgoing traffic. |
DISABLE_TELEMETRY, CLAUDE_CODE_ENABLE_TELEMETRY | Turn telemetry off and on. |
DO_NOT_TRACK | The widely accepted variable with the same meaning. |
DISABLE_GROWTHBOOK | Don't pull server-side feature flags. |
DISABLE_ERROR_REPORTING | Don't send error reports. |
DISABLE_AUTOUPDATER, DISABLE_UPDATES | Turn auto-updates off. |
DISABLE_COST_WARNINGS | Hide cost warnings. |
DISABLE_FEEDBACK_COMMAND | Hide feedback submission. The old name DISABLE_BUG_COMMAND is accepted too. |
DISABLE_DOCTOR_COMMAND | Hide /doctor. |
The OTEL_* family | Export of metrics, logs and traces. |
Three things here catch people out.
DISABLE_BUG_COMMAND isn't a separate switch. It's the old name of DISABLE_FEEDBACK_COMMAND, and the one variable turns off /feedback, the feedback drafts, and /bug with /share as well, because they all go through the same channel.
A value of 0 doesn't turn it back on. For CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC any presence of the variable, including 0 and false, disables the traffic. To get it back you have to remove the variable entirely.
Turning telemetry off also turns features off. Along with the feature flags, these stop working: auto mode by default, /auto-mode-setup, remote control, /import, /schedule, the advisor, artifact comments, the new MCP client and the PowerShell tool being the default on Windows. It's a deliberate trade-off rather than a side-effect bug, but it's worth knowing before you spend half an hour hunting for where remote control went.
Here's what "all non-essential traffic" actually covers: auto-updates, telemetry, error reports, feedback submission, release notes, refreshing the model list from a gateway, and availability checks. Plus — unexpectedly — background execution of local plugin source commands, because those can drag a dependency install along with them. What it doesn't cover is the auto-install of the official marketplace; that has its own variable.
Terminal commands and flags
Everything you type outside a session, in your regular shell. Each subcommand below gathers everything in one place: its own subcommands and flags, the quirks and the examples.
First things first, and this is the official wording, not my own observation: claude --help does not list every flag. A flag missing from the help doesn't mean it doesn't exist. Below I mark what the help leaves out — there are at least a dozen such flags, and among them perfectly usable things like capping the number of turns.
Get a subcommand name wrong and you'll be offered the closest match and dropped out without a session starting: claude udpate gets you a question about whether you meant claude update.
Subcommands
claude [prompt]
Start an interactive session. With a prompt — start straight from it.
claude # interactive sessionclaude "fix the failing test in orders" # a session that starts with the taskclaude -p "<prompt>"
A non-interactive run: print the answer and exit. The main mode for scripts.
claude -p "what does this script do?" # answer and exitclaude auth login|logout|status
Log in, log out, and check authorization status. Status is printed as JSON.
claude auth login --console # log in through Console billingclaude auth logout # log outclaude auth status # authorization status as JSONclaude setup-token
Issue a long-lived authorization token. Requires a subscription.
claude setup-token # long-lived token for CIclaude agents
The management screen for background agents; it's also how you launch them.
claude agents # the background agents screenclaude attach <id>
Open a background session in this terminal.
claude attach a1b2c3 # attach to a background sessionclaude logs <id>
Print the latest output of a background session.
claude logs a1b2c3 # latest output of a background sessionclaude stop <id>
Stop a background session; the conversation is kept. Alias: kill.
claude stop a1b2c3 # stop itclaude respawn [id]
Restart a background session, or all of them, on the current version.
claude respawn --all # restart them all on the new versionclaude rm <id>
Delete a background session along with its working copy.
claude rm a1b2c3 # delete the session and its working copyclaude daemon
The background service that holds all your background sessions. A subcommand hardly anyone knows about, even though it runs for everybody: it's the supervisor that brings background sessions up and keeps them alive.
| Subcommand | What it does |
|---|---|
status | Service state: version, socket directory, number of worker processes |
run [path] | Start the service by hand |
logs | The service log |
stop | Stop it; --any — along with the sessions, --keep-workers — leaving the workers running |
uninstall | Remove the service |
The --json-path and --log-file flags change where the state file and the log live; by default that's ~/.claude/daemon.json and ~/.claude/daemon.log. In version 2.1.251 permanent installation of the service is disabled: it comes up on demand and shuts down when the last client disconnects.
A trap for scripts: claude --dangerously-skip-permissions daemon status works, but any other global flag before the word daemon will start an interactive session instead of the subcommand. Put the subcommand first.
claude daemon status # state of the background serviceclaude daemon stop --any --keep-workers # stop the service, keep the workersclaude mcp
Configuring MCP servers without starting a session.
| Subcommand | What it does |
|---|---|
add <name> <command-or-url> [args...] | Add a server. |
add-json <name> <json> | Add a server as a single line of JSON. |
add-from-claude-desktop | Import servers from Claude Desktop. macOS and WSL only. |
list, get <name> | The list and the details. |
login <name>, logout <name> | Log into a server, or clear the stored credentials. |
remove <name> | Remove a server. |
reset-project-choices | Reset the approved-or-rejected decisions on the project's servers. |
serve | Run Claude Code itself as an MCP server. |
The most important flag here is --scope, and leaving it out explains a good half of the "why does only my machine see this server" and "why does everyone suddenly have it" questions. Values: local (the default), project — into .mcp.json, which gets committed, and user — into your user settings. It's available on add, add-json, add-from-claude-desktop and remove.
There are four transports, not three: stdio, http, sse and ws. Short forms: -t for --transport, -H for --header. For OAuth there's --client-id, --client-secret (it'll prompt, or take it from an environment variable) and --callback-port; login additionally has --no-browser.
Servers from .mcp.json that haven't been approved show up in the list as pending approval and don't connect.
claude mcp add fs npx -- -y @modelcontextprotocol/server-filesystem ~/workclaude mcp add --scope project github https://api.example.com/mcp -t httpclaude mcp add --scope user jira https://jira.example.com/mcp -H "X-Team: core"claude mcp add-json local-tools '{"command":"./tools","args":["--serve"]}'claude mcp list # what's connected and in what stateclaude mcp get github # details of a single serverclaude mcp login github --no-browser # log in without opening a browserclaude mcp remove jira --scope user # remove it from the user scope specificallyclaude mcp reset-project-choices # ask about the project's servers againclaude mcp serve # expose Claude Code itself as an MCP serverclaude plugin
Plugins and marketplaces. Alias: plugins.
| Subcommand | What it does |
|---|---|
install <plugin> | Install from a marketplace. Alias i. |
uninstall <plugin> | Remove it. Aliases remove, rm. |
enable, disable | Turn an installed plugin on or off. |
list | List what's installed. Alias ls. |
details <name> | An inventory of its components and an estimate of how much context the plugin will eat. |
update <plugin> | Update it; takes effect after a restart. |
marketplace | Managing marketplaces. |
init <name> | Create a plugin skeleton. Alias new. |
validate <path> | Check the manifest, and also the skills, agents and commands in the folder. |
eval [target] | Run the check cases against the plugin and show the scores. |
tag [path] | Create a git release tag, checking the manifest against the marketplace entry. |
prune | Remove automatically installed dependencies that are no longer needed. Alias autoremove. |
Almost every subcommand takes -s, --scope with the values user (the default), project and local, and update also takes managed. On top of that: install has --config key=value (repeatable) and -y; uninstall has --keep-data, --prune, -y; disable has -a for all of them; list has --json and --available; prune has --dry-run and -y; validate has --strict, which turns warnings into errors; init has --description, --author, --author-email, -f and --with with a list of components: skills, agents, hooks, mcp, lsp, output-style, channel.
Worth knowing: validate works on an ordinary folder of skills and agents too, with no plugin involved.
claude plugin install code-review@claude-plugins-officialclaude plugin install formatter@acme --config style=compact -yclaude plugin list --json # what's installed, machine-readableclaude plugin details formatter # how much context it takes upclaude plugin init my-tools --with skills,hooksclaude plugin validate ./my-tools --strictclaude plugin eval ./my-tools # run the check casesclaude plugin update formatter --scope projectclaude plugin prune --dry-run # what would be removedclaude auto-mode
Configuration of the auto-mode classifier.
| Subcommand | What it does |
|---|---|
config | What's in effect and where it comes from |
defaults | The stock rules; with --label — the full text of one rule |
critique | The model's review of your rules |
reset | Reset; --yes — without a confirmation |
claude auto-mode config # what's in effect and where fromclaude auto-mode defaults # the stock rulesclaude auto-mode defaults --label 'Git Destructive' # the full text of one ruleclaude auto-mode critique # the model's review of your rulesclaude auto-mode reset --yes # reset without a confirmationclaude project purge [path]
Delete all the state for a project: transcripts, tasks, file history, the entry in the config.
claude project purge ~/work/repo --dry-run # what would be deletedclaude doctor
Diagnostics of your installation, without starting a session and without changing anything.
claude doctor # diagnostics, nothing changedclaude import [source]
Bring your configuration over from another coding agent.
claude import codex --dry-run # what would come over from another agentclaude install [version]
Install the native build: stable, latest or a specific version.
claude install stable # install the stable buildclaude update
Check for updates and install them. Alias: upgrade.
claude update # updateclaude ultrareview [target]
A cloud multi-agent review that prints its findings into the terminal.
claude ultrareview # findings printed right in the terminalclaude gateway
Run the enterprise gateway for authorization and telemetry.
claude gateway --config gateway.yaml # the enterprise gatewayclaude remote-control
Hidden: keep remote control running as a server. Alias: rc.
claude remote-control --continue # back into the last control sessionclaude self-hosted-runner
Hidden: turn a machine or a container into a place where web, mobile and desktop sessions run. This one is for Team and Enterprise.
It has a setup subcommand and an orchestrator of its own that brings runners up as the queue grows, plus around twenty flags: the API address, the environment secret file, the hooks folder, the health-check port, capacity, drain and shutdown timeouts, how long an idle runner lives, the client label. All of it is described in a separate reference on self-hosted environments — contrary to the widespread belief that the subcommand is undocumented.
claude self-hosted-runner setup # prepare a machine as a runner hostInstalling and updating
There are more ways than npm install, and that's worth knowing, because the native build updates itself while the npm package doesn't.
# macOS, Linux, WSL — the native installercurl -fsSL https://claude.ai/install.sh | bashcurl -fsSL https://claude.ai/install.sh | bash -s stable # pin the channelcurl -fsSL https://claude.ai/install.sh | bash -s 2.1.236 # pin the version
# Windowsirm https://claude.ai/install.ps1 | iex # PowerShellwinget install Anthropic.ClaudeCode # or via a package manager
# macOS via Homebrew — two different packagesbrew install --cask claude-code # stable, about a week behindbrew install --cask claude-code@latest # fresh
# npm — works, but needs Node 22+npm install -g @anthropic-ai/claude-codeThere are signed repositories for apt, dnf and apk as well. And claude install and claude update work once Claude Code is already installed.
Exit codes
A three-line section, but an important one for scripts.
| Code | What it means |
|---|---|
| 0 | Success |
| non-zero | The run failed |
| 143 | Interrupted by a termination signal |
| 137 | Installation killed before it finished |
A subtlety: an invalid flag is reported on the error stream before any work starts, while a failure during the work — a missing login, say — is printed as the result on standard output. So the return code alone won't let you tell "it never started" from "it started and couldn't finish".
An interrupt by signal leaves the current turn unfinished and without a result, kills the process tree of the commands it launched, runs the session-end hooks — and when you resume the session, that turn continues from where it stopped.
Launch flags
The [not in help] tag means the flag works, but claude --help in build 2.1.251 doesn't print it.
The session and continuing it
| Flag | What it does |
|---|---|
-c, --continue | Continue the last conversation in the current folder. Skips background sessions. |
-r, --resume [value] | Continue by id, or open the interactive picker. |
--fork-session | On continue, start a new id instead of reusing the old one. |
--session-id <uuid> | Set a specific session id. |
-n, --name <name> | Display name for the session. |
--from-pr [value] | Continue the session tied to a pull request. |
--no-session-persistence | Don't save the session to disk. Non-interactive mode only. |
--teleport [session] | Pull a web session into the terminal. |
--cloud [description|id|url] | Create a cloud session or attach to an existing one. |
--remote | [deprecated] The old name for --cloud. Still turns up in other people's scripts. |
--environment <id> | Create a cloud session on your own environment. |
--ref <branch> | [not in help] Which ref to bring the cloud environment up on. Works together with --environment. |
--remote-control [name], --rc | Start a session with remote control enabled. |
--remote-control-session-name-prefix <prefix> | Prefix for the auto-generated names of such sessions. |
--bg, --background | Run in the background and hand control back; prints the id. |
--exec <command> | [not in help] Run a plain command as a background task instead of a session. |
-w, --worktree [name] | Create a new git worktree for the session. |
--tmux | Bring up a tmux session for the worktree. |
--teammate-mode <mode> | [not in help] How to show teammates: in-process, auto, tmux, iterm2. |
claude -c # continue the last conversationclaude -r # pick from a listclaude -r 8f3c1d2e --fork-session # continue as a copy, leaving the original aloneclaude -n "payment refactor" # start with a nameclaude --from-pr 1234 # session for a pull requestclaude --bg "run the full test suite" # in the background, returns an idclaude --bg --exec 'pytest -x' # a background task with no session at allclaude -w feature-x # its own worktree for the sessionclaude -w feature-x --tmux # the same, in tmuxclaude --cloud "fix CI flakes" # cloud sessionclaude --environment ccpool_abc --ref main -p "run the smoke tests"--exec deserves a line of its own: it turns the CLI into a background task runner with no model involved at all. The command runs in a pseudo-terminal, you read its output with claude logs, and you stop it with claude stop. Handy when you want one uniform way to keep an eye on long-running processes.
Output and non-interactive mode
| Flag | What it does |
|---|---|
-p, --print | Print the answer and exit. The folder trust dialog is skipped. |
--output-format <format> | text by default, json or stream-json. |
--input-format <format> | text by default, or stream-json. |
--json-schema <schema> | Schema for validating a structured response. |
--include-partial-messages | Emit chunks of messages as they arrive. |
--include-hook-events | Include hook lifecycle events in the stream. |
--forward-subagent-text | Forward subagent text and thinking. |
--replay-user-messages | Echo user messages back into the output. |
--max-turns <n> | [not in help] Cap on the number of tool-using turns. The main cost-control lever in CI. |
--max-budget-usd <amount> | Cap on API spend. |
--permission-prompt-tool <tool> | [not in help] An MCP tool that answers permission requests instead of a human. |
--ax-screen-reader | Flat text, no frames and no animations. |
--verbose | Override the matching setting from the config file. |
claude -p "list the public endpoints" --output-format json | jq -r '.result'claude -p "build a report" --json-schema ./report.schema.json | jq '.structured_output'claude -p "fix the linter" --max-turns 5 # turn capclaude -p "check the style" --max-budget-usd 0.50 # spend capclaude -p "..." --permission-prompt-tool mcp_auth_toolcat diff.patch | claude -p "assess the risk of these changes"Two flags here are the most useful ones and, at the same time, missing from the help. --max-turns limits how many turns may call tools; when the cap is hit the run ends with a matching marker in the result, and it's exactly what the docs officially recommend as the main cost-control lever in CI. --permission-prompt-tool names an MCP tool that will answer permission requests instead of a human — the only way to get approval logic into a non-interactive run.
What you need to know about non-interactive mode
Slash commands work there. Your own skills and commands get inlined straight into the prompt text. The terminal built-ins like /login aren't available, but /model, /effort, /fast, /color and /rename take their value as an argument, and /mcp with no argument prints a text summary of the servers. Settings are changed with /config key=value.
claude -p "/model sonnet /code-review low"claude -p "/config thinking=false explain what this module does"The json format gives you more than text. The result field holds the answer, next to it the session id and a cost estimate broken down by model; with a schema, the structured response goes into a field of its own. You can save the session id and continue the conversation later — and, since version 2.1.223, from a different folder.
Flag conflicts. -p together with --bg is an error. --cloud with a task description together with -p is too; but --cloud <id> together with -p queues the message on that cloud session and exits.
Stream limits. Piped input is capped at ten megabytes: more than that gets a clear error and a non-zero exit code. If the input stream can't be read at all you get a warning and the run continues with the prompt from the command line.
Background tasks die with the run. A command started in the background during claude -p is torn down about five seconds after the result is printed. Background subagents and workflows are the exception — those are waited on, though never longer than ten minutes of uninterrupted idling.
--bare is the recommended mode for scripts, and in the future it will become the default behavior for -p. The difference matters: without it, a non-interactive run executes the hooks from the project's .claude/settings.json and connects the servers from its .mcp.json even in a folder you have never trusted, without asking a single question.
Model, effort, permission mode
| Flag | What it does |
|---|---|
--model <model> | An alias (fable, opus, sonnet, haiku) or a full name. |
--fallback-model <model,...> | Fallback when the main model is overloaded. Only with -p. |
--effort <level> | low, medium, high, xhigh, max, and per the docs ultracode as well. |
--advisor <model> | [not in help] Turn the advisor on and pick its model. |
--agent <agent> | The agent for the session; overrides the setting. |
--agents <json> | Declare your own agents right on the command line. Validated at startup. |
--permission-mode <mode> | default (aka manual), acceptEdits, plan, auto, dontAsk, bypassPermissions. |
--dangerously-skip-permissions | Bypass permission checks. |
--allow-dangerously-skip-permissions | Make the bypass an available option without turning it on. |
--restricted | Restricted mode. |
--safe-mode | Turn off every customization. |
--bare | Minimal mode for scripts. |
claude --model haiku -p "list the changed files"claude --effort xhigh # a session that reasons deeplyclaude --effort ultracode # with workflow orchestration from the startclaude --advisor opus # bring in the advisorclaude --permission-mode plan # start in planning modeclaude --permission-mode acceptEdits # accept edits automaticallyclaude --safe-mode # no hooks, skills, plugins or MCPclaude --bare -p "..." # minimal mode for a scriptThree warnings. --dangerously-skip-permissions doesn't work as an administrator: on Linux and macOS a run as root or through sudo is rejected, because root plus no questions asked means access to everything on the machine. Inside a recognized sandbox the check is lifted. An organization can forbid the mode entirely with the disableBypassPermissionsMode key.
The docs and the binary disagree in two places. For --permission-mode the docs list both default and manual as its alias, while the binary's help lists only manual. For --effort the docs know about ultracode, the help doesn't. In both cases the broader variant is the one that works.
--safe-mode and --bare are different things. The first turns off all customization for diagnostics. The second is a minimal execution mode for scripts, where authorization also goes strictly through a key. For debugging "something broke after my settings", you want the first.
Tools, folders, MCP
| Flag | What it does |
|---|---|
--tools <tools...> | Which built-in tools to use: an empty string turns them all off, default turns them all on, or list the names. |
--allowedTools, --allowed-tools | Allow tools by list. Both spellings work. |
--disallowedTools, --disallowed-tools | Forbid tools by list. |
--add-dir <folders...> | Extra working folders. |
--mcp-config <configs...> | Load MCP servers from files or JSON strings. |
--strict-mcp-config | Use only the servers from this flag. |
--plugin-dir <path> | Load a plugin from a folder or an archive, for this session only. |
--plugin-url <url> | The same, but the archive comes from a link. |
--channels <servers...> | [not in help] Which MCP servers to listen to for external events. |
--dangerously-load-development-channels | [not in help] Allow channels outside the approved list. |
--disable-slash-commands | Turn off all skills. |
--chrome, --no-chrome | Turn the Chrome integration on or off. |
--ide | Connect to the IDE automatically when there's exactly one suitable option. |
Both tool lists accept comma-separated and space-separated entries. With -p, the servers from --mcp-config are waited for before the first turn, but no longer than the startup timeout; a malformed entry is skipped and the run continues and finishes normally — which means in CI you should check the list of server errors in the first stream event, not the exit code.
Settings, prompt, and the rest
| Flag | What it does |
|---|---|
--settings <file-or-json> | Extra settings: a path to a file or a JSON string. |
--setting-sources <sources> | Which settings layers to load: user, project, local. |
--system-prompt <prompt> | Replace the system prompt entirely. |
--system-prompt-file <path> | [not in help] The same, but from a file. |
--append-system-prompt <prompt> | Append to the system prompt. |
--append-system-prompt-file <path> | [not in help] The same, but from a file. |
--append-subagent-system-prompt <text> | [not in help] Append to every subagent's system prompt. |
--exclude-dynamic-system-prompt-sections | Move the machine-dependent pieces into the first user message — the cache is reused better. |
--autocompact <auto|tokens> | Auto-compaction threshold. |
--betas <betas...> | Beta headers on the requests. |
--init | [not in help] Run the initialization hooks before the session. Only with -p. |
--init-only | [not in help] Run the startup hooks and exit without starting a conversation. |
--maintenance | [not in help] Run the maintenance hooks. Only with -p. |
--file <id:path ...> | Download file resources at startup. |
--prompt-suggestions [on] | Suggestions for the next prompt. |
--brief | Enable the tool the agent uses to talk to the user. |
-d, --debug [filter] | Debug mode with a category filter. |
--debug-file <path> | Write the debug log to a file. |
-v, --version | Version. |
-h, --help | Help. |
claude --settings '{"disableAllHooks": true}' -p "..." # run without the repo's hooksclaude --setting-sources user -p "..." # ignore the project settingsclaude --append-system-prompt-file ./team-rules.mdclaude --append-subagent-system-prompt "always give file paths"claude --init-only # warm the container up and exitclaude -d "api,hooks" # debug by categoryclaude -d "!1p,!file" --debug-file ./claude.log # everything except these categories--init-only is worth calling out: it's the natural way to warm up a container or a working folder in CI — the install and session-start hooks run, and then the process exits without starting a conversation.
And one discrepancy worth remembering if you write scripts from the docs: -v in build 2.1.251 is --version, even though the docs claim it's the short form of --verbose. Check it on your own version before relying on it.
What isn't in any documentation
A caveat for the future: since none of this is in the docs, nobody has promised to keep it around. Building automation on top of it is a risk you take knowingly.
A dozen and a half artifact commands. Of that whole group, the official reference lists only /artifacts, /design, /design-login and /design-sync. Everything else — /prototype, /doc, /plan-artifact, /artifact-pr-review, /artifact-dashboard, /artifact-report, /artifact-data-table, /artifact-explainer, /artifact-components, /artifact-design, /artifact-diagramming, /artifact-capabilities — isn't mentioned anywhere. Same goes for /whiteboard, /whiteboard-mp and /workshop.
Seven /design subcommands. Officially it's a single command that takes a design description. In the binary it understands sync, login, consent, revoke, import, export and status.
Diagnostics for your own spend. /skill-doctor, which shows unused skills, and /explain-usage, which explains spend in plain language, are both undocumented. So is /plugin-types, which generates types for the connected MCP tools.
Five more everyday commands. /brief — short-answer mode. /daemon — managing background services. /cloud-plugins — plugins in cloud sessions. /session (alias /remote) — the address of a remote session and a QR code for it; the reference has /remote-control and /teleport, but not this line. And /install, which installs the native build straight from the session.
Built-in skills everybody uses. /commit, /pr, /update-config, /claude-code-docs, /claude-in-chrome are described neither in the command reference nor in the section on built-in skills. The only indirect mention in the changelog is a bug fix where the agent was calling a commit skill that didn't exist.
Commands disabled in this build. /version, /update, /loops, /wellbeing with all its aliases, and /pause-memory — registered, but not working. None of them is mentioned in the changelog either as removed or as added: /version, /wellbeing and /pause-memory never appear there at all over the whole history, and the mentions of /update are bug fixes from back when it still worked.
Commands that appear based on state. /limit-reset, /low-priority, /pro-trial-expired, /design-consent, /design-revoke, and /setup-cowork, which belongs to Cowork mode. The docs acknowledge exactly one hidden command — taking a memory dump — and separately mention that provider configuration shows up along with an environment variable. About these six, nothing.
Internal entry points and model-only skills. __remote-workflow and workflow-launch-exec, which the server uses to hand a ready-made workflow to a session. Plus three skills the agent pulls in by itself and that you can't type: keybindings-help, memory-types, cowork-plugin. The mechanism — the user-invocable: false field — is documented; the skills themselves aren't.
How /code-review works inside. The docs describe the levels qualitatively. How many independent search angles there are, how many candidates per angle, and what the cap on findings is at each level — plus the fact that on Opus 5 the medium and high levels currently collapse into a single pass — is nowhere to be found. Nor are the three argument-parsing rules that make ultra work only as the first word.
The /sandbox exclude "pattern" form. The official line about this command is one sentence: toggle sandbox mode. Nothing about exempting individual commands from isolation, or about the subcommand that finishes the installation on Windows.
The /name alias for /rename. The reference entry for the command itself is unusually detailed — it covers name sanitization and the length limit — but the alias isn't in it.
The --file flag. Downloading file resources at startup is missing from the flag list.
Eight settings keys. Not a line about them in the docs, in the changelog, or in the published schema: doneMeansMerged — "done means merged"; breakReminder and quietHours — break reminders and quiet hours (searching turns up an article about the consumer Claude app, but that's a different thing and has no settings keys); precomputeCompactionEnabled; daemonColdStart; defaultView; autoUploadSessions; showMessageTimestamps. Plus xaaIdp together with the variable that enables it, syncClaudeAiPlugins — even though its sibling syncClaudeAiSkills is documented — and proxyAuthHelper.
Keys that exist only in the published schema. sandbox.enabledPlatforms, skippedMarketplaces and skippedPlugins — zero mentions in the docs and the changelog; the schema remains their only public trace.
Eight environment variables. The official page lists three hundred and forty-nine of them, and these aren't among them: CLAUDE_CODE_GOAL_CHECKIN_MINUTES, CLAUDE_CODE_WORKFLOW_PREFIX_STAGGER_MS, CLAUDE_CODE_DISABLE_AGENT_VIEW, CLAUDE_CODE_DISABLE_WORKFLOWS, CLAUDE_CODE_DISABLE_ADAPTIVE_THINKING, CLAUDE_CODE_DISABLE_CLAUDE_MDS, CLAUDE_CODE_SHELL together with CLAUDE_CODE_SHELL_PREFIX, and USE_BUILTIN_RIPGREP. Some of them have documented neighbors under different names and with a slightly different meaning — for turning off thinking, say, or for switching how files are searched — but those aren't the same variables.
The claude plugin eval subcommand. Running check cases against a plugin: the plugin reference lists ten subcommands, and this one isn't among them.
And the absence of things that don't exist. There is no /init-verifiers command, /alias isn't a slash command, and there's no .claudeignore file at all. The docs are naturally silent about things that don't exist — and so are the articles on the internet.
The number deserves a separate word. The official reference has a hundred and eleven entries, and it says honestly that not every command is available to everyone. How many are registered in total isn't published; in build 2.1.251 it comes out to around a hundred and fifty including skills. Community cheat sheets claim either two hundred and seventy-two (counting command-line flags along the way) or about seventy — and both numbers are based on nothing.
Where to start if you're seeing all this for the first time
That's a lot of tables, and the first instinct is to close the page. So here's a short practical minimum: what's worth setting up on day one, and what to come back to when the need arises.
Right away, in the user file. Tool permissions: without them you'll be asked about every build and every git status, and within an hour you'll be hitting "allow" without reading — which is exactly the habit that later gets something deleted. The status line: constantly visible spend and context fill change your behavior more than any good intentions do. And a bigger cleanupPeriodDays, if you ever plan to look up an old conversation or roll back to a checkpoint.
In the project, committed to the repo. Permissions for the commands of this particular project, hooks that hold the invariants, and a .mcp.json with the servers the whole team needs.
For later. The sandbox, self-hosted environments, enterprise keys. They solve problems you probably don't have yet; and the sandbox section is worth reading on exactly the day you first run an agent with confirmations bypassed.
A file that's a reasonable place to start:
{ "$schema": "https://json.schemastore.org/claude-code-settings.json", "cleanupPeriodDays": 365, "fileCheckpointingEnabled": true, "permissions": { "allow": [ "Bash(git status)", "Bash(git diff:*)", "Bash(git log:*)", "Bash(npm run build)", "Bash(npm test:*)" ], "ask": ["Bash(git push:*)"], "deny": ["Read(./.env)", "Read(./.secrets/**)"] }, "statusLine": { "type": "command", "command": "~/.claude/statusline.sh" }}Five permissions already mean noticeably fewer questions. One deny on the secrets file — because deny beats allow, and it's the cheapest way to make sure the contents of .env never end up in the context. Checkpointing is turned on explicitly: without it /rewind won't bring back a single file, and you usually find that out at the worst possible moment.