Claude Code · Intermediate/Lesson 04 of 08~5 min

Permissions, settings scopes, and the sandbox

Beginner kept the guardrails personal — you, answering prompts. This lesson moves them into the repository: rules everyone gets, and a sandbox the operating system enforces whether Claude asks or not.

The Third Way engineering team||Verified against Claude Code v2.1.285 (stable), October 2026

01The goal

Put a permission rule in the settings file whose scope fits it, see which files a session loaded, and turn on the sandbox so the shell commands Claude runs cannot write outside your project — with the network behind a proxy you allow hosts through.

02The idea

Claude Code reads settings from four files, and the file a rule lives in decides who it affects:

↳The four settings files
FileAffectsPut here
~/.claude/settings.jsonYou, in every projectYour own preferences
.claude/settings.json, committedEveryone in the projectTeam rules: files Claude must never read, the test command everyone runs
.claude/settings.local.json, kept out of gitYou, in this projectYour exceptions. "Yes, and don’t ask again" on a command saves here
Managed settings, deployed by your organizationEveryone they reachPolicy your files cannot override — a few security keys excepted, where the stricter value wins
The commit line between the middle two is the whole lesson: shared rules go in git, personal ones stay out of it.

When the same key is set in more than one place, the higher level wins: managed, then the command line, then local, then shared project, then user. Rule lists such as permissions.allow merge across the files instead — each file adds entries without removing another’s. Among the rules themselves, deny is checked before ask, and ask before allow; a matching deny always wins.

Permission rules govern Claude’s tools. The sandbox adds a boundary the operating system enforces around the shell commands Claude runs: by default they can write only in the project, a per-user temporary folder, and any folders you have added, and they reach the network only through a local proxy that checks each host against the domains you allow — which start empty. It is off until you turn it on. In its auto-allow mode, a command that runs inside the sandbox needs no permission prompt at all: the boundary replaces the prompting.

03The walkthrough

  1. 01Start claude and run /status. Its Setting sources line lists the settings files this session loaded — the honest inventory of who is currently constraining whom.
  2. 02Write the team’s rules into .claude/settings.json: permissions.allow holding exactly your test command — Bash(npm test) in the shape below — and permissions.deny holding Read(./.env) and Read(./.env.*). These are the docs’ own rules for keeping Claude out of secrets. Save, and the session picks the change up: settings files hot-reload while a session runs. /permissions now lists the allow and the denies.
  3. 03Ask Claude to run npm test. It runs without a prompt: the allow rule covers exactly that command, and no other.
  4. 04Turn on the sandbox: /sandbox, and on the Mode tab choose auto-allow. The choice saves to .claude/settings.local.json — your personal file, out of git — and Claude Code adds that file to your global git excludes when it creates it.
  5. 05Probe the boundary. Ask: "Run this exact command and show me its output: touch ~/sandbox-probe". It runs without a prompt and fails — Operation not permitted on macOS, Read-only file system on Linux and WSL 2. If Claude offers to retry outside the sandbox, decline; that offer is the boundary asking you to vouch.
↳.claude/settings.json — the committed half
{
"permissions": {
"allow": ["Bash(npm test)"],
"deny": [
"Read(./.env)",
"Read(./.env.*)"
]
}
}
One allow, as narrow as the truth; two denies, covering the files that must never reach the context window. The sandbox lives in settings.local.json — for now.

04Your turn

The same split in your own repository. Write .claude/settings.json with one allow — the single command that runs your tests, not a family of them: Bash(npm *) lets Claude run any npm command without asking, which is not what you reviewed. Deny reading .env and .env.*. Commit it; these are rules for everyone. Turn on the sandbox with /sandbox in auto-allow, repeat the walkthrough’s sandbox probe, and confirm with git status that .claude/settings.local.json is not listed — Claude Code keeps it out of git when it creates it; if you create it by hand, gitignore it yourself.

Respect the edges of the boundary. The sandbox wraps shell commands only — Claude’s file and web tools run outside it and follow your permission rules; hooks and local MCP servers run outside it with your full access. If the sandbox cannot start, Claude Code runs commands unsandboxed unless sandbox.failIfUnavailable is true — a key worth knowing if you rely on the boundary. On Linux and WSL 2 the sandbox needs bubblewrap and socat installed; a /sandbox panel that shows only a Dependencies tab is telling you exactly that. And a Read deny, on its own, covers Claude’s file tools and the file commands Claude Code recognizes in Bash — with the sandbox on, your Read deny paths are merged into the sandbox’s own read denials, so sandboxed commands and the processes they start cannot read those files either.

↳Check yourself
Q1

"Yes, and don’t ask again" on a Bash command saves its rule to…

  1. A.claude/settings.json, for the team
  2. B.claude/settings.local.json, for you in this project
  3. CManaged settings
→Check your answer
Answer: B

Sticky answers are personal exceptions — they land in the local file, out of git. Team rules get written into the committed file on purpose, reviewed like code.

Q2

By default, with the sandbox on, a shell command Claude runs can write to…

  1. AThe project, a per-user temp folder, and folders you have added
  2. BAnywhere in your home directory
  3. COnly files git tracks
→Check your answer
Answer: A

That is the filesystem boundary; the network side is a proxy that checks each host against your allowed domains, which start empty.

Q3

What runs outside the sandbox, with your full access?

  1. AOnly web searches
  2. BEverything Claude does
  3. CHooks and local MCP servers
→Check your answer
Answer: C

The sandbox wraps shell commands. Claude’s file and web tools follow permission rules instead — and hooks and local MCP servers run with your rights, which is why lesson 8 says to read what a plugin installs.

The Third Way engineering team
Delivery engineering
Work with us