New to Claude Skills? Learn how to install them →

Claude Code's --restricted Flag Explained

Claude Code's new --restricted flag locks a session down for evaluation harnesses and shared machines: no shell tools, no WebFetch, no user or project settings, no bypass mode.

August 28, 2026
Get Claude Skills
7 min read

A CLI flag built for the case you don't control the caller

Most Claude Code permission controls assume you trust whoever is driving the session, you're just deciding how much it should ask you before acting. --restricted, added in Claude Code v2.1.248 (27 August 2026), assumes the opposite. It's for the case where an evaluation harness, a benchmark runner, or some other automated process invokes claude on a machine you don't fully control, and you need a guarantee that the session can't run commands, can't reach the network through WebFetch, and can't pick up settings someone else planted on that machine.

That's a narrower problem than the one permission modes usually solve. Manual, auto, and bypassPermissions all answer "how much does Claude ask me before acting." --restricted answers a different question: "what can this session do at all, regardless of who's asking." The best AI coding agents increasingly ship into CI and evaluation pipelines where that distinction matters, and --restricted is Claude Code's answer to it.

What --restricted actually removes

Per Claude Code's CLI reference, starting a session with --restricted:

  • Removes the built-in tools that run commands or code, and WebFetch, unless you name them individually with --tools, not through its default preset
  • Confines the built-in file tools to the session's working directories
  • Loads only managed settings and whatever you pass with --settings, ignoring user, project, and project-local settings files
  • Refuses bypassPermissions outright, even if something tries to request it

The syntax is a single flag:

claude --restricted -p "query"

Requires Claude Code v2.1.248 or later.

Why each of those four restrictions exists

No shell or code execution tools by default. An evaluation harness that shells out to claude for a text-generation task has no reason to also grant it Bash access to the host it's running on. Removing execution tools by default, rather than trusting a harness author to remember to restrict them, closes that gap before it becomes a problem.

No WebFetch by default. The same logic applies to outbound network access. A benchmark run shouldn't be able to exfiltrate anything or fetch instructions from a remote page unless you've deliberately decided it needs to.

File tools confined to the working directory. Without this, a session invoked from one directory could still read or write files elsewhere on a shared machine, benchmark artifacts from a different tenant, credentials cached from another user's earlier run, or system files outside the intended sandbox.

No user, project, or project-local settings. This is the one that's easy to overlook. On a shared machine, a previous user, or a malicious test fixture, could have left a .claude/settings.json or ~/.claude/settings.json with permission allow rules, hooks, or MCP server definitions baked in. --restricted refuses to read any of that, loading only settings your organization controls (managed settings) or that you pass explicitly for this one run (--settings).

Re-enabling specific tools

--restricted doesn't mean the session is limited to reading files forever. If a harness genuinely needs one execution tool, name it directly:

claude --restricted --tools "Bash(npm test)" -p "run the test suite and report failures"

The key distinction from ordinary tool control is that --restricted refuses the default preset entirely. Where a normal session's --tools can widen or narrow a baseline set, under --restricted there is no baseline; every tool available to the session has to be named. That inversion, allowlist-only rather than denylist-from-default, is the point of the flag.

Where --restricted fits among Claude Code's other lockdown flags

Claude Code already has several tools for constraining a session, and it's worth being precise about how --restricted differs from the ones you might already use:

Flag or settingWhat it constrainsDirection
--permission-mode planBlocks edits until you approve a planNarrows actions, not settings sources
--allowedTools / --disallowedToolsWhich specific tools a normal session can useAdjusts the default tool set
--dangerously-skip-permissionsSkips permission prompts (bypassPermissions)Widens, the opposite direction from --restricted
--settingsOverrides specific settings keys for one runAdditive, works alongside --restricted
managed-settings.jsonOrganization-wide policy, applied above every other levelDeployed once, read by every session including restricted ones
--restrictedTool defaults, file scope, and settings sources, all at onceNarrows everything, and is the only one that refuses bypassPermissions outright

--restricted is best understood as a bundle: instead of assembling --disallowedTools, a locked-down --settings file, and a working-directory check yourself for every harness invocation, one flag applies all three at once, tuned specifically for the case where you don't trust the calling environment.

A worked example: running Claude Code inside a benchmark runner

Say you maintain an internal evaluation harness that spins up claude once per benchmark task, on shared CI runners that also host other teams' jobs. Before --restricted, you'd have had to hand-assemble the protections:

claude \
  --disallowedTools "Bash" "Execute" \
  --settings '{"permissions":{"allow":[]}}' \
  -p "$(cat task-prompt.txt)"

That approach is fragile. It depends on remembering every dangerous tool to exclude, and it does nothing about a stray .claude/settings.json left in the working directory by a previous job. With --restricted:

claude --restricted -p "$(cat task-prompt.txt)"

The session starts with no execution tools, no WebFetch, file access scoped to the task's own working directory, and no risk of inheriting a previous job's local settings. If the task genuinely needs to run a fixed, known command, you add it back explicitly:

claude --restricted --tools "Bash(pytest tests/)" -p "$(cat task-prompt.txt)"

That's the difference between a denylist you maintain by hand and an allowlist the flag enforces for you.

Combining --restricted with managed settings

Because --restricted still loads managed settings, an organization running fleets of eval harnesses can layer both. A managed-settings.json deployed to /Library/Application Support/ClaudeCode/managed-settings.json on macOS, /etc/claude-code/managed-settings.json on Linux, or C:\Program Files\ClaudeCode\managed-settings.json on Windows still applies to a --restricted session, since managed settings sit above every other level regardless of flags. That means you can use managed settings to set an organization-wide baseline (deny rules on sensitive paths, for example) and rely on --restricted to strip out everything a given harness invocation shouldn't have on top of that baseline. Neither replaces the other; managed settings are the policy every session inherits, --restricted is what a specific invocation opts into beyond that.

What --restricted doesn't do

It's worth being precise about the boundary. --restricted operates at the application layer: it decides which tools Claude Code exposes and which settings it reads. It is not a sandbox, container, or VM boundary. If your evaluation harness runs on a shared machine where isolation actually matters, whether one tenant's process can read another's files at the OS level, --restricted doesn't substitute for that. It's meant to be one layer in a stack that includes real isolation, the same way Claude Code documents bypassPermissions as requiring "isolated containers and VMs only" rather than treating the permission mode alone as sufficient.

Troubleshooting

A tool I need isn't available under --restricted. Check whether it falls under the tools removed by default, execution tools and WebFetch, and add it back explicitly with --tools. Remember the default preset doesn't apply under --restricted, so listing one tool doesn't implicitly re-enable the rest.

My local .claude/settings.json changes aren't taking effect. That's expected. --restricted ignores user, project, and project-local settings files entirely. If a value needs to reach the session, pass it with --settings for that run, or have your organization set it in managed settings.

bypassPermissions won't start. --restricted refuses it unconditionally, regardless of how it's requested, --dangerously-skip-permissions, --permission-mode bypassPermissions, or a settings file value. This isn't a bug to work around; it's the flag's core guarantee. If a task genuinely needs bypass-level trust, it isn't a --restricted use case.

The flag has no effect at all. Confirm the Claude Code version with claude --version; --restricted requires v2.1.248 or later, and earlier versions silently don't recognize it as anything other than an unknown argument.

Where this fits with the rest of Claude Code's security model

--restricted joins a small set of controls purpose-built for running Claude Code somewhere you don't fully trust: managed settings for organization-wide policy, the Bash sandbox for OS-level command isolation, and now --restricted for the specific case of an automated caller on a shared machine. None of them substitute for reviewing what you're running before you run it, the same principle behind linking out to a skill's source on GitHub rather than re-hosting it, covered in the agent skills security guide. For the full permission-mode picture that --restricted sits alongside, see how auto mode's classifier rules work, and browse Claude Code's platform page for everything else it supports.

Frequently asked questions