Environment Sandboxing & Customization
8 min read
What You Will Learn
This chapter is all about locking down and personalizing your Claude Code setup. You’ll learn how the four tier configuration system controls settings across enterprise, personal, and project scopes. We’ll dig into how sandbox modes isolate Claude Code’s access to your filesystem and network. And you’ll see how to customize the terminal experience with environment variables and a status line. By the end, you’ll be able to configure Claude Code to match your team’s security requirements and your own workflow preferences.
Configuration Scopes
Claude Code organizes its settings into four tiers, each with its own purpose and priority level. When the same setting shows up at multiple tiers, higher priority tiers win.
Managed Settings
Managed settings sit at the top of the hierarchy and can’t be overridden by anything else. Enterprise admins use this file to enforce organization-wide policies, such as blocking certain commands across all developers or requiring sandbox mode.
~/.claude/managed-settings.jsonManaged settings location, controlled by enterprise admins
Most individual developers won’t ever need to create this file. It’s really there for organizations that need centralized control over Claude Code’s behavior across their engineering teams. If a managed setting denies a command, no project or personal setting can override that decision.
User Settings
User settings are your personal defaults that apply across every project on your machine. This is where you’d set things like your default model, effort level, and personal permission rules.
~/.claude/settings.jsonUser settings location, personal defaults for all projects
Project Settings
Project settings get shared with your team through version control. This is the right place for permission rules everyone on the team should follow, model preferences for the project, and any project-specific configuration.
.claude/settings.jsonProject settings location, committed to git, shared with team
Local Settings
Local settings are your personal overrides for a specific project. They don’t get committed to git and only exist on your machine. Use these for personal preferences that differ from the team defaults. For example, you might use a different model or enable auto-allow sandbox mode for a project you trust.
.claude/settings.local.jsonLocal settings location, personal project overrides, not committed to git
Precedence Order
When the same setting exists at multiple tiers, the precedence order is: managed > local > project > user. Notice that local overrides project, which lets individual developers customize their experience without touching team settings.
In practice, that means:
- A managed deny rule can’t be overridden by any other tier
- A local setting takes precedence over the project setting for the same key
- A project setting overrides your user level default
- User settings act as the fallback when nothing else is specified
Settings File Format
All four tiers use the same JSON format. Here’s a comprehensive example showing the most commonly used fields.
{ "model": "sonnet", "permissions": { "mode": "default", "allow": [ "Bash(npm run *)", "Bash(npm test *)", "Bash(git add *)", "Bash(git commit *)", "Read(*)" ], "deny": [ "Bash(curl *)", "Bash(wget *)", "Bash(rm -rf /)*" ] }, "sandbox": { "enabled": true, "autoAllowBashIfSandboxed": false, "filesystem": { "allowWrite": [ "./src/**", "./tests/**", "./docs/**" ] } }, "preferences": { "effort": "medium" }}Comprehensive project settings showing permissions, sandbox, and preferences
The permissions section controls which actions Claude can take without asking (covered in detail in Models, Cost Economics & Permissions). The sandbox section handles filesystem and network isolation (we’ll cover that below). And the preferences section sets behavioral defaults like effort level.
Environment Variables
A handful of environment variables control Claude Code’s behavior. Set them in your shell profile so they persist across sessions.
# Model selectionexport ANTHROPIC_MODEL=sonnet
# Effort level (low, medium, high)export CLAUDE_CODE_EFFORT_LEVEL=medium
# API key (for direct API usage, not needed for Claude Pro/Max subscriptions)export ANTHROPIC_API_KEY=sk-ant-...
# Custom output directory for generated filesexport CLAUDE_CODE_OUTPUT_DIR=./output
# Disable automatic updatesexport DISABLE_AUTOUPDATER=1
# Default haiku model (replaces deprecated ANTHROPIC_SMALL_FAST_MODEL)export ANTHROPIC_DEFAULT_HAIKU_MODEL=haikuKey environment variables for Claude Code configuration
These variables take effect for the current shell session and any Claude Code sessions launched from it. For permanent changes, add them to your shell profile (~/.zshrc, ~/.bashrc, or equivalent).
One thing to note: the ANTHROPIC_SMALL_FAST_MODEL environment variable is deprecated. Use ANTHROPIC_DEFAULT_HAIKU_MODEL instead when configuring the lightweight model for background tasks.
Why Sandboxing Matters
Claude Code runs real commands on your machine. It reads files, executes shell commands, and writes code. That power is exactly what makes it so effective, but it also means unexpected behavior could have real consequences.
Sandboxing constrains what Claude Code can access, even when something goes wrong. Two main risk scenarios make this important:
Accidental damage. Claude might misinterpret a request and fire off a destructive command like rm -rf on a directory outside your project. Without sandboxing, that would succeed and your data would be gone. With sandboxing, filesystem access stays restricted to authorized paths.
Prompt injection. When you’re working with untrusted codebases, malicious content hidden in files or commit messages could try to trick Claude into running harmful commands. Sandboxing limits the blast radius; even if Claude gets manipulated into running something, it can’t reach files or network resources outside the sandbox boundary.
Here’s the key detail: sandboxing works at the operating system level, not the application level. Claude Code can’t bypass it even with a bypassPermissions mode because the OS kernel enforces the restrictions.
Sandbox Modes
Claude Code offers two sandbox modes, each striking a different balance between security and convenience.
Regular Sandbox
With regular sandbox mode, Claude asks for permission before doing anything that might reach outside the sandbox boundary. This is the default behavior when sandboxing is enabled.
{ "sandbox": { "enabled": true, "autoAllowBashIfSandboxed": false }}Regular sandbox: Claude asks for permission on boundary-crossing operations
This is the safest option. You maintain full visibility into every command Claude runs while still benefiting from OS-level isolation that prevents catastrophic errors.
Auto-Allow with Sandbox
Auto-allow sandbox mode automatically approves any operation that stays within the sandbox boundary. Claude only asks for permission when something would cross that boundary.
{ "sandbox": { "enabled": true, "autoAllowBashIfSandboxed": true }}Auto-allow sandbox: operations within the boundary proceed without prompting
The autoAllowBashIfSandboxed flag is the key setting here. When it’s set to true, Claude can run any bash command that stays within the sandbox’s filesystem and network constraints without asking. You get a fast, uninterrupted workflow while keeping hard security boundaries in place.
This mode is a great fit when you trust the codebase you’re working on and want minimal interruptions, but still want OS-level guardrails preventing access outside the project.
Filesystem Isolation
Sandboxing enforces filesystem access restrictions at the operating system level, using platform-specific mechanisms under the hood.
macOS uses Seatbelt (sandbox-exec) to restrict filesystem access at the kernel level. Seatbelt profiles define which paths are readable and writable. It’s the same sandboxing technology that macOS uses for App Store applications.
Linux uses bubblewrap (bwrap) for namespace based isolation. Bubblewrap creates a restricted filesystem view where only explicitly allowed paths are visible. It relies on Linux kernel namespaces, the same technology behind container runtimes like Docker.
Neither platform depends on Claude Code to self enforce filesystem restrictions. The OS kernel prevents unauthorized access no matter what commands Claude tries to run.
Configuring Writable Paths
The sandbox.filesystem.allowWrite setting specifies which paths Claude Code can write to. Paths follow a simple prefix notation:
| Prefix | Meaning | Example |
|---|---|---|
// | Absolute path from root | //tmp/claude-output |
~ | Home directory | ~/Documents/exports |
./ | Relative to project root | ./src/** |
{ "sandbox": { "enabled": true, "filesystem": { "allowWrite": [ "./src/**", "./tests/**", "./docs/**", "//tmp/claude-*", "~/.claude/projects/**" ] } }}}Filesystem sandbox with prefix notation for writable paths
Glob patterns work here too. ./src/** allows writing to any file under the src directory tree, while //tmp/claude-* allows writing to temporary files with a claude- prefix. Any path not listed in allowWrite is read only by default when sandboxing is enabled.
Network Isolation
The sandbox also controls network access through a proxy-based architecture. All outbound network traffic gets routed through a local proxy that enforces domain restrictions.
The allowedDomains setting controls which external domains Claude Code can reach. This helps prevent data exfiltration and limits the scope of any network-related prompt injection attacks.
{ "sandbox": { "enabled": true, "network": { "allowedDomains": [ "registry.npmjs.org", "pypi.org", "api.github.com", "raw.githubusercontent.com" ] } }}Network sandbox allowing only package registries and GitHub API
Out of the box, the sandbox allows access to common package registries (npm, PyPI, crates.io) and other standard development domains. You can tighten this further for high security environments or loosen it for projects that need specific API access.
Keep the allowed domains list as small as practical. Every domain you add is a potential channel for data to leave your machine. If Claude needs to access an API that isn’t in the allowed list, you’ll be prompted to approve it.
Status Line Customization
During active sessions, Claude Code displays a status line at the bottom of your terminal. You can customize it with a shell script that receives session information and outputs whatever text you want.
Configuring the Status Line
Just point the statusLine setting to a shell script that generates your custom status text.
{ "statusLine": "~/.claude/status.sh"}Point to a custom status line script
Writing a Status Line Script
Your status line script receives session JSON on stdin and should output a single line of text to stdout. The JSON includes information about the current session like the model, cost, and token usage.
#!/bin/bash# Read session JSON from stdinSESSION=$(cat)
# Extract fields using jqMODEL=$(echo "$SESSION" | jq -r '.model // "unknown"')COST=$(echo "$SESSION" | jq -r '.cost // "0.00"')TOKENS=$(echo "$SESSION" | jq -r '.tokensUsed // 0')
# Format outputecho "Model: $MODEL | Cost: $$COST | Tokens: $TOKENS"Example status line script showing model, cost, and token count
Don’t forget to mark the script as executable:
chmod +x ~/.claude/status.shMake the status line script executable
The status line refreshes periodically during the session, so keep your script fast. It should execute in milliseconds, not seconds. Avoid network calls or expensive computations in there.
Practical Status Line Examples
Here’s a cost-focused status line for budget-conscious teams:
#!/bin/bashSESSION=$(cat)COST=$(echo "$SESSION" | jq -r '.cost // "0.00"')MODEL=$(echo "$SESSION" | jq -r '.model // "unknown"')echo "[$MODEL] $$COST spent"Minimal status line showing model and running cost
Best Practices
-
Use project settings for team conventions. Commit
.claude/settings.jsonto version control so everyone shares the same permission rules, model defaults, and sandbox configuration. That way the whole team gets consistent behavior. -
Use local settings for personal overrides. Keep
.claude/settings.local.jsonout of version control (add it to.gitignore). It’s the right place for personal preferences like a different default model or auto-allow sandbox mode for projects you trust. -
Enable sandbox for untrusted codebases. Whenever you’re working with code you didn’t write, such as open source contributions, inherited projects, or third party code reviews, turn on sandboxing to limit the blast radius of any malicious content lurking in the codebase.
-
Start with regular sandbox before auto-allow. Try regular sandbox mode first to get a feel for what commands Claude runs during your typical workflow. Once you’re confident in the patterns, flip on
autoAllowBashIfSandboxedfor a faster experience. -
Keep
allowedDomainsminimal. Only add domains your project genuinely needs. Every additional domain is a potential data exfiltration channel, so start with package registries and expand as needed. -
Use the status line to track costs. A custom status line showing the current session cost keeps spending visible without you having to run
/costmanually. This is especially handy for teams with cost targets. -
Document your settings choices. Add comments to your project’s CLAUDE.md explaining why specific permission rules exist. Future team members (and future you) will thank you for documenting the reasoning behind deny rules.
Further Reading
- Settings: Official docs on configuration scopes, file locations, and available settings
- Sandboxing: Official docs on sandbox modes, filesystem isolation, and network restrictions
- Status Line: Official docs on custom status line scripts and session JSON format
- Remote Control & Headless Automation: Running Claude Code remotely and automating with scheduled tasks (next chapter)