---
title: "Claude Code — commands, settings, flags"
url: "https://romankryvolapov.com/en/claude-code-commands-and-settings/"
description: "A Claude Code reference: every slash command with its arguments explained and examples, settings.json keys, permission rules, terminal subcommands, flags and environment variables. Current as of August 2026."
language: en
updated: 2026-08-31
---
**Hi!**

This is a reference. Not a story about how to work with the agent properly — I have a [separate article](/en/claude-code-best-practices/) 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.

```
/exit
```

### Context 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 repository
```

```bash
CLAUDE_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 menu
```

### Model 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 goal
```

### Code 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:

```json title=".claude/settings.json"
{
  "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:

1. `ultra` is recognized only as the first word. `/code-review ultra --fix` is a cloud review, while `/code-review --fix ultra` is an ordinary local one in which the word `ultra` is read as the target.
2. The level is the first word left once the flags are stripped out of the line. That's why `/code-review --fix high` works, and the level will be `high`.
3. 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:

```bash
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:

```bash
claude ultrareview                       # cloud review of the current branch
claude ultrareview 1234 --post           # review a PR, summary as a comment on it
claude ultrareview --json                # raw findings instead of a report
claude ultrareview dev --timeout 60      # against the dev branch, wait up to an hour
```

The 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 uncommitted
```

### Development 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 differ
```

### Subagents, 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 logic
```

### Artifacts, 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-login
```

### Configuration 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 hours
```

### MCP 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 browser
```

### Account 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 outside
```

### Usage 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 plan
```

### Remote 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 web
```

### Diagnostics 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 one
```

### Information 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 history
```

### Commands 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:

```markdown title=".claude/skills/fix-issue/SKILL.md"
---
name: fix-issue
description: Look up an issue by number, find the cause and propose a fix
argument-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 fix
and 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.

```markdown title=".claude/skills/render/SKILL.md"
---
name: render
description: Render a diagram from its source
allowed-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:

```json title=".claude/settings.json"
{
  "$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_MODEL` from the shell overrides the `model` key from any file.
- `ANTHROPIC_DEFAULT_MODEL` only takes effect if `model` isn't set anywhere.
- `--model` and `/model` override `ANTHROPIC_MODEL`.
- And `CLAUDE_CODE_EFFORT_LEVEL` works the other way round and overrides `--effort` and `/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.

```json title=".claude/settings.json"
{
  "$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)`.

```json title=".claude/settings.json"
{
  "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:

```json title=".claude/settings.json"
{
  "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:

```bash
claude auto-mode config                       # what's in effect and where it came from
claude auto-mode defaults                     # the stock rules of all four lists
claude auto-mode defaults --label 'Git Destructive'   # the full text of a single rule
claude auto-mode critique                     # a model's critique of your rules
claude auto-mode reset --yes                  # reset to stock without asking
```

The `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](/en/claude-code-hooks/): 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.

```json title=".claude/settings.json"
{
  "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. |

```json title=".claude/settings.json"
{
  "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.

```json title=".claude/settings.json"
{
  "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.** |

```json title=".claude/settings.json"
{
  "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.

```json title=".claude/settings.json"
{
  "remote": { "defaultEnvironmentId": "env-123" },
  "sshConfigs": [
    {
      "id": "prod-box",
      "name": "Prod",
      "sshHost": "deploy@prod.example.com",
      "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. |

```json title=".claude/settings.json"
{
  "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.

```json title=".claude/settings.json"
{
  "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.

```json title=".claude/settings.json"
{
  "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.

```bash
claude                                    # interactive session
claude "fix the failing test in orders"   # a session that starts with the task
```

#### `claude -p "<prompt>"`

A non-interactive run: print the answer and exit. The main mode for scripts.

```bash
claude -p "what does this script do?"     # answer and exit
```

#### `claude auth login|logout|status`

Log in, log out, and check authorization status. Status is printed as JSON.

```bash
claude auth login --console               # log in through Console billing
claude auth logout                        # log out
claude auth status                        # authorization status as JSON
```

#### `claude setup-token`

Issue a long-lived authorization token. Requires a subscription.

```bash
claude setup-token                        # long-lived token for CI
```

#### `claude agents`

The management screen for background agents; it's also how you launch them.

```bash
claude agents                             # the background agents screen
```

#### `claude attach <id>`

Open a background session in this terminal.

```bash
claude attach a1b2c3                      # attach to a background session
```

#### `claude logs <id>`

Print the latest output of a background session.

```bash
claude logs a1b2c3                        # latest output of a background session
```

#### `claude stop <id>`

Stop a background session; the conversation is kept. Alias: `kill`.

```bash
claude stop a1b2c3                        # stop it
```

#### `claude respawn [id]`

Restart a background session, or all of them, on the current version.

```bash
claude respawn --all                      # restart them all on the new version
```

#### `claude rm <id>`

Delete a background session along with its working copy.

```bash
claude rm a1b2c3                          # delete the session and its working copy
```

#### `claude 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.

```bash
claude daemon status                      # state of the background service
claude daemon stop --any --keep-workers   # stop the service, keep the workers
```

#### `claude 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.

```bash
claude mcp add fs npx -- -y @modelcontextprotocol/server-filesystem ~/work
claude mcp add --scope project github https://api.example.com/mcp -t http
claude 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 state
claude mcp get github                    # details of a single server
claude mcp login github --no-browser     # log in without opening a browser
claude mcp remove jira --scope user      # remove it from the user scope specifically
claude mcp reset-project-choices         # ask about the project's servers again
claude mcp serve                         # expose Claude Code itself as an MCP server
```

#### `claude 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.

```bash
claude plugin install code-review@claude-plugins-official
claude plugin install formatter@acme --config style=compact -y
claude plugin list --json                # what's installed, machine-readable
claude plugin details formatter          # how much context it takes up
claude plugin init my-tools --with skills,hooks
claude plugin validate ./my-tools --strict
claude plugin eval ./my-tools            # run the check cases
claude plugin update formatter --scope project
claude plugin prune --dry-run            # what would be removed
```

#### `claude 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 |

```bash
claude auto-mode config                              # what's in effect and where from
claude auto-mode defaults                            # the stock rules
claude auto-mode defaults --label 'Git Destructive'  # the full text of one rule
claude auto-mode critique                            # the model's review of your rules
claude auto-mode reset --yes                         # reset without a confirmation
```

#### `claude project purge [path]`

Delete all the state for a project: transcripts, tasks, file history, the entry in the config.

```bash
claude project purge ~/work/repo --dry-run   # what would be deleted
```

#### `claude doctor`

Diagnostics of your installation, without starting a session and without changing anything.

```bash
claude doctor                             # diagnostics, nothing changed
```

#### `claude import [source]`

Bring your configuration over from another coding agent.

```bash
claude import codex --dry-run             # what would come over from another agent
```

#### `claude install [version]`

Install the native build: `stable`, `latest` or a specific version.

```bash
claude install stable                     # install the stable build
```

#### `claude update`

Check for updates and install them. Alias: `upgrade`.

```bash
claude update                             # update
```

#### `claude ultrareview [target]`

A cloud multi-agent review that prints its findings into the terminal.

```bash
claude ultrareview                        # findings printed right in the terminal
```

#### `claude gateway`

Run the enterprise gateway for authorization and telemetry.

```bash
claude gateway --config gateway.yaml      # the enterprise gateway
```

#### `claude remote-control`

**Hidden:** keep remote control running as a server. Alias: `rc`.

```bash
claude remote-control --continue          # back into the last control session
```

#### `claude 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.

```bash
claude self-hosted-runner setup           # prepare a machine as a runner host
```

### Installing 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.

```bash
# macOS, Linux, WSL — the native installer
curl -fsSL https://claude.ai/install.sh | bash
curl -fsSL https://claude.ai/install.sh | bash -s stable     # pin the channel
curl -fsSL https://claude.ai/install.sh | bash -s 2.1.236    # pin the version

# Windows
irm https://claude.ai/install.ps1 | iex                      # PowerShell
winget install Anthropic.ClaudeCode                          # or via a package manager

# macOS via Homebrew — two different packages
brew install --cask claude-code                              # stable, about a week behind
brew install --cask claude-code@latest                       # fresh

# npm — works, but needs Node 22+
npm install -g @anthropic-ai/claude-code
```

There 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`. |

```bash
claude -c                                # continue the last conversation
claude -r                                # pick from a list
claude -r 8f3c1d2e --fork-session        # continue as a copy, leaving the original alone
claude -n "payment refactor"             # start with a name
claude --from-pr 1234                    # session for a pull request
claude --bg "run the full test suite"    # in the background, returns an id
claude --bg --exec 'pytest -x'           # a background task with no session at all
claude -w feature-x                      # its own worktree for the session
claude -w feature-x --tmux               # the same, in tmux
claude --cloud "fix CI flakes"           # cloud session
claude --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. |

```bash
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 cap
claude -p "check the style" --max-budget-usd 0.50    # spend cap
claude -p "..." --permission-prompt-tool mcp_auth_tool
cat 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`.

```bash
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. |

```bash
claude --model haiku -p "list the changed files"
claude --effort xhigh                    # a session that reasons deeply
claude --effort ultracode                # with workflow orchestration from the start
claude --advisor opus                    # bring in the advisor
claude --permission-mode plan            # start in planning mode
claude --permission-mode acceptEdits     # accept edits automatically
claude --safe-mode                       # no hooks, skills, plugins or MCP
claude --bare -p "..."                   # minimal mode for a script
```

Three 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. |

```bash
claude --settings '{"disableAllHooks": true}' -p "..."   # run without the repo's hooks
claude --setting-sources user -p "..."                   # ignore the project settings
claude --append-system-prompt-file ./team-rules.md
claude --append-subagent-system-prompt "always give file paths"
claude --init-only                                       # warm the container up and exit
claude -d "api,hooks"                                    # debug by category
claude -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:

```json title="~/.claude/settings.json"
{
  "$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.
