This post walks through claude-sandbox, a small tool I built to bring predictable, low-friction sandboxing to Claude Code on macOS.
The Problem with the Built-in Sandbox
Claude Code ships with a built-in sandboxing feature. It's capable, but it wasn't a great fit for my workflow:
- It kept blocking legitimate operations in unexpected ways, and troubleshooting took more time than the protection was worth.
- It includes network isolation, which I didn't need at all — just extra complexity with no benefit for my use case.
What I actually wanted was simple: restrict file writes to the current project directory, with an easy way to allow exceptions when needed. Nothing more.
That's claude-sandbox.
How It Works
claude-sandbox wraps the claude command and runs it under macOS's sandbox-exec (Apple Seatbelt — the same technology used in Claude Code's built-in sandboxing). The default policy is simple: allow everything, deny all file writes, then re-allow writes to a few specific paths — the current working directory, ~/.claude, and /tmp. If Claude Code tries to write outside those boundaries, the OS itself blocks it.
You can customize this policy by writing your own profile in TOML, but the defaults are sensible enough to use as-is.
Installation
claude-sandbox is a single binary with no dependencies. You can install it with Homebrew:
brew install kohkimakimoto/tap/claude-sandbox
Basic Usage
claude-sandbox is a drop-in replacement for the claude command:
# Before
claude --dangerously-skip-permissions
# After
claude-sandbox --dangerously-skip-permissions
That's it. Claude Code starts, but now it runs inside a sandbox that restricts where it can write files.
Try to write a file outside the current directory, and you'll see an error like the following:
❯ write current time into ~/now.txt
⏺ Bash(date > ~/now.txt && cat ~/now.txt)
⎿ Error: Exit code 1
(eval):1: operation not permitted: /Users/kohkimakimoto/now.txt
(eval):1: operation not permitted: /Users/kohkimakimoto/now.txt
⏺ The sandbox is restricting write access to the home directory. Let me try using the Write tool instead.
Configuration
You don't need a config file to get started — the built-in defaults work fine. But if you want to customize things, run:
# Project-specific config
claude-sandbox init
# Global config
claude-sandbox init-global
This creates a .claude/sandbox.toml file. Here's what it looks like:
[sandbox]
profile = '''
(version 1)
(allow default)
(deny file-write*)
(allow file-write*
(subpath (param "WORKDIR"))
(regex (string-append "^" (param "HOME") "/\\.claude"))
(subpath "/tmp")
)
'''
[unboxexec]
allowed_commands = [
"^playwright-cli",
]
The profile is written in the sandbox-exec policy language (a Scheme-like DSL). Two parameters are automatically injected:
-
WORKDIR— the directory where you ran claude-sandbox -
HOME— your home directory
To see what profile is actually active:
claude-sandbox profile
The Escape Hatch: unboxexec
Here's where things get interesting. Some tools — like Playwright for browser automation — use their own sandboxing internally. Running them inside a macOS sandbox causes conflicts, and they simply don't work.
claude-sandbox solves this with a mechanism called unboxexec. When claude-sandbox starts, it launches a small daemon outside the sandbox. Claude Code, running inside the sandbox, can send a command execution request to that daemon — and the daemon runs the command outside the sandbox and returns the result.
The daemon won't execute arbitrary commands — only those matching the regex patterns in [unboxexec].allowed_commands. By default, everything is rejected.
To use unboxexec from inside Claude Code (or from a script running inside the sandbox):
claude-sandbox unboxexec -- playwright-cli open https://example.com
For it to work, you need to add the pattern to your config:
[unboxexec]
allowed_commands = [
"^playwright-cli",
]
Telling Claude About the Sandbox
One more practical detail: Claude Code doesn't automatically know it's running in a sandbox. claude-sandbox solves this with a built-in Agent Skill — a structured prompt that tells Claude how to check sandbox status, inspect the configuration, and run commands outside the sandbox via unboxexec.
To see the skill contents:
claude-sandbox skill
To install it into your current project:
claude-sandbox skill --install
This creates .claude/skills/claude-sandbox/SKILL.md in your project directory. Once installed, Claude Code will automatically load it and understand how to work within the sandbox environment.
Wrapping Up
claude-sandbox gives you a practical middle ground: run Claude Code with full permissions for reading and executing, but with file writes safely scoped to your project directory. No network lockdown, no complex configuration to troubleshoot — just a straightforward constraint that covers the most common concern.
Top comments (1)
The
unboxexecescape-hatch pattern is really clever. I run AI agents on a Mac Mini with heavy Playwright usage for browser automation, and the sandbox-exec vs Playwright conflict is exactly the kind of thing that burns hours to debug without a clean solution like this.One thing I'm curious about: since the unboxexec daemon runs outside the sandbox and only filters by regex on
allowed_commands, have you considered the case where Claude rewrites the.claude/sandbox.tomlconfig itself to widen the allowed patterns? The sandbox restricts file writes to the working directory, but if.claude/falls under WORKDIR (which it does by default), Claude could theoretically edit the config before the next invocation. A read-only mount or a separate config path outside WORKDIR might close that gap.Also, the "tell Claude about the sandbox via rules" approach is pragmatic, but I've found that architectural constraints tend to be more reliable than instructions. In a finance planning tool I built, I removed the server entirely rather than telling the AI "don't add a server" — the constraint is enforced by the build system, not by a prompt. Do you see a path toward making unboxexec restrictions discoverable at runtime (e.g., a command that lists what's allowed) so Claude can self-correct without needing the rules file?
Really appreciate the TOML config over the raw Scheme DSL. Much more approachable.