Claude Code Restricted Mode: What --restricted Blocks
--restricted is the flag you reach for when Claude Code has to run somewhere you do not fully trust: an evaluation harness on a shared machine, a CI job against a repository you did not write, a session where a checked-in .claude/settings.json should not get a vote. It shipped in Claude Code v2.1.248 on 2026-08-27 and does four things at once:
- Removes the built-in tools that run commands or code, plus
WebFetch. - Confines the built-in file tools to the session's working directories.
- Loads only managed settings and whatever you pass with
--settings, ignoring the user, project, and local settings files. - Refuses
bypassPermissions, and refuses to create cloud sessions.
The usage is unremarkable:
claude --restricted -p "Summarize what this repository does"
What is worth understanding is the third item, because it is the one that makes --restricted different in kind from every permission setting that came before it. Everything below was verified against the Claude Code CLI reference, permission-modes, and changelog documentation on 2026-08-29.
It is not a permission mode
This is the first thing to get straight, because the naming invites the mistake. Claude Code has six permission modes: default (labeled Manual), acceptEdits, plan, auto, dontAsk, and bypassPermissions. You select one with --permission-mode. --restricted is not among them. It is a separate flag that composes with whichever mode you are in.
The distinction matters because modes and --restricted operate on different questions. A permission mode answers "which actions run without asking you first". --restricted answers "which tools exist in this session at all, and whose configuration gets to influence it". A mode can be talked around by an allow rule in a settings file. --restricted removes the tool, and removes the settings file.
Two of its effects do reach into mode behavior, though:
- Claude Code refuses
bypassPermissionsin a session started with--restricted. The--dangerously-skip-permissionsflag is equivalent to that mode, so it is refused on the same grounds. - Writes to protected paths (
.git,.claude,.bashrc,.npmrc, and a long list of others) are never auto-approved by the auto-mode classifier in a restricted session. In an unrestricted auto session the classifier can approve some of them.
What gets removed, and how to hand one back
The tools reference lists Bash, PowerShell, and Monitor as the built-in tools that execute commands. Those are what "the built-in tools that run commands or code" refers to, and WebFetch goes with them even though it executes nothing: it reaches the network, which is the same trust boundary.
Read, Write, Edit, Glob, and Grep survive. They are fenced to the session's working directories: the directory you launched in, plus anything added with --add-dir or additionalDirectories. A restricted session cannot read ~/.aws/credentials by path, because that path is outside the fence, and it cannot get there through a shell either, because there is no shell.
You can give a tool back, but only by naming it:
claude --restricted --tools Read Grep Glob Bash -p "Run the test suite"
Here is the gotcha, and it is deliberate. Naming a removed tool individually in --tools restores it. Reaching for --tools default does not, because default is a preset, and --restricted only honors individual names. So this does nothing to bring Bash back:
# Bash stays gone. `default` is a preset, not a name.
claude --restricted --tools default -p "Run the test suite"
That design makes the safe outcome the accidental one. A script that half-configures --tools ends up with fewer tools than intended, never more.
The settings ladder, and which rungs survive
Claude Code reads settings from five tiers, highest precedence first:
| Tier | File | Set by |
|---|---|---|
| Managed | managed-settings.json, MDM, or the claude.ai console | Your organization |
| Command line | claude --settings | You, this session |
| Project local | .claude/settings.local.json | You, this project |
| Shared project | .claude/settings.json | Everyone in the project |
| User | ~/.claude/settings.json | You, every project |
--restricted keeps the top two and drops the bottom three. Read that against what lives in those bottom three and the point of the flag becomes obvious: permissions.allow rules, hooks, plugin configuration, and environment variables are all things a repository ships in .claude/settings.json. Clone an unfamiliar repository, run Claude Code in it normally, and that file is loaded before you have read it.
The consequence people miss: hooks are configured in settings files, so a restricted session does not run the project's hooks. That cuts both ways. It blocks a PreToolUse hook that a hostile repository added to widen its own permissions, and it also disables the PreToolUse hook you wrote to narrow them. If your safety net is a hook in ~/.claude/settings.json, it is not there under --restricted. Move it into managed settings or pass it with --settings if you need it to survive.
Worth being precise about the boundary: the documented behavior covers settings files. CLAUDE.md is memory, not settings, and the docs do not list it among the things a restricted session ignores. A repository's CLAUDE.md is still instructions written by whoever wrote the repository. --restricted narrows what Claude can do with those instructions; it is not a claim that nothing untrusted reaches the model's context.
The same scoping applies to MCP. The removal is described in terms of built-in tools, and MCP servers are configured on their own track. If a connected MCP server exposes a tool that runs commands, that is a separate lever: --strict-mcp-config with --mcp-config restricts a session to the servers you name and ignores every other MCP configuration.
Choosing between restricted, dontAsk, and read-only tools
Three mechanisms overlap here and they solve different problems.
| You want | Use | What it does |
|---|---|---|
| A session that cannot execute anything and cannot be configured by the repo | --restricted | Removes command tools, fences files, drops your settings files |
| A CI run that never blocks on input and does exactly what you pre-approved | --permission-mode dontAsk | Auto-denies anything not matching your allow rules, read-only Bash, or a PreToolUse hook |
| A session limited to reading and MCP | --tools read-only | Limits to Read, WebFetch, and MCP tools |
The most common real choice is between the first two, and it turns on one question: do you trust the settings files on that machine and in that repository?
If you do (your own CI, your own repo, your own runner image), dontAsk is the better fit. It never waits for input, and it uses your permissions.allow list, which is exactly the pre-approval mechanism you want in a pipeline. --restricted would throw away that allow list along with everything else.
If you do not (a shared box, a harness scoring arbitrary repositories, a third-party checkout), --restricted is the one that helps, because it is the only one of the three whose guarantees do not depend on the contents of files the untrusted party controls.
They compose, and for a genuinely hostile input the combination is the honest answer:
claude --restricted --permission-mode dontAsk \
--settings ./ci-settings.json \
-p "Review the diff in this checkout and list correctness bugs"
That session has no shell, no network fetch, no access outside the working directory, no ability to bypass permissions, and exactly one settings file: the one you wrote and passed on the command line.
FAQ
Does --restricted sandbox the machine?
No, and this is the important limit. It reduces what the agent can reach by removing tools and narrowing configuration inside the process. It is not an OS-level boundary, and it does not isolate the network. If you need a real boundary, run Claude Code inside a container or a VM and use --restricted in addition, not instead. Claude Code's separate Bash sandbox and credential masking settings cover a different part of the problem: what a command can read when there is a command to run at all.
Can I set it in settings.json instead of passing the flag?
The documented interfaces are the --restricted flag and the CLAUDE_CODE_RESTRICTED=1 environment variable. The environment variable is what you want in a harness or a CI image, since it applies to every claude invocation in that environment without every call site remembering the flag. Setting it in a settings file would be self-defeating in any case, given that the flag's whole purpose includes ignoring most settings files.
Why does it refuse to create cloud sessions?
Because a cloud session is an escape hatch around the restriction: the restricted local process could otherwise start an unrestricted remote one. Attempting it returns Cloud sessions cannot be created from a --restricted session. Start a separate unrestricted session if you need cloud work.
Does it work with auto mode?
Yes. --restricted composes with any permission mode except bypassPermissions, which it refuses. In a restricted auto mode session the classifier still reviews actions, with the difference that it cannot approve protected-path writes, and there are far fewer actions left for it to review once the command-running tools are gone.
What if I am on an older version?
--restricted requires v2.1.248 or later. On older versions the closest approximation is --permission-mode dontAsk combined with --tools to drop the command tools, but that combination still reads your user and project settings files, so it does not give you the untrusted-repository property. Check with claude --version before relying on either.