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. If you want it to use unboxexec correctly — and to understand what it can and can't do — you should add a rules file.
The repo includes a ready-to-use example at rules/sandbox.md. Copy its contents into .claude/rules/sandbox.md in your project, or into ~/.claude/rules/sandbox.md to apply it globally. Adjust the contents based on which commands you've allowed.
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 (0)
Some comments may only be visible to logged-in visitors. Sign in to view all comments.