Installation:
go install github.com/banksean/sand/cmd/...Manual usage:
> sand new my-sandbox
container hostname: my-sandbox
⚡ ⌨️ # shell prompt, go crazy, rm -rf whateverUse with a coding agent, like claude or opencode:
> sand new -c claude
container hostname: shy-snow
▐▛███▜▌ Claude Code v2.1.71
▝▜█████▛▘ Sonnet 4.6 · API Usage Billing
▘▘ ▝▝ /app
──────────────────────────────────────────────────── ▪▪▪ ─
❯ And in another shell window from your host MacOS, use sand ls to list the sandboxes:
> sand ls
SANDBOX NAME STATUS FROM DIR FROM GIT CURRENT GIT IMAGE NAME
shy-snow running ~/code/sand *2be518ca readme *2be518ca readme claude:latest
my-sandbox running ~/code/sand *2be518ca readme *2be518ca readme default:latestUnder the hood, the sand new command:
- creates a copy-on-write clone your current working directory (traversing up to git root, if necessary)
- creates a local linux container with that cloned working directory mounted at
/app - configures the container with keys for bidirectional ssh authentication
- makes the container visible to your host OS via DNS
- ssh's you into that container
- runs your coding agent's CLI (if you specified an agent)
Aside from the basic requirements for any sandboxing tool in general, I've chosen a few more specific constraints for sand.
- Local: Works entirely on your workstation (no remote hosting dependency)
- Agnostic: use whatever coding agent you want to (including no agent at all)
- Fast, easy: Make using sandboxes as easy and lightweight as using tmux sessions or git branches
The design goals imply some obvious trade-offs. Most obvious is that by running locally on your workstation, it is limited by your workstation's hardware resources. However, this choice also makes it easy to create new sandboxes very quickly, and does not require you to trust a third party with your files.
By being agent-agnostic, sand doesn't take advantage of agent-specific features that it could if it were more tightly coupled to them. On the other hand, this agnosticism makes it possible to treat sandbox lifecycles separately from agent session lifecycles. This trade-off also makes it possible to use sandboxes for manual coding tasks, without any agent whatsoever.
Fast and easy: One way to achieve speed is by doing less, so the specific comparisons to git and tmux are intentional here. The trade-off is that you can use git and tmux with sand's resources, but sand will only do so much to simplify sandbox-related git and tmux tasks if you aren't already familiar with those tools. Also similarly to git, you should be able to create a new sandbox from an existing sandbox as easily as you can create a git branch from an existing git branch.
- Isolation Model: Apple Containerization
- hardware isolation via Apple Silicon
- low memory overhead, fast start times
- based on Kata
- supported in macOS 15 (Sonoma) and up
- Filesystem:
- Base container image: Minimal, with some dynamic provisioning based on which agent you're using
- Agent workspaces:
/appis mounted from the APFS CoW clone, must be same APFS disk as the original project dir - Host filesystem access: limited to the CoW clone directory. (Apple Containerization uses virtiofs to bridge the macOS-to-VM boundary, and then uses a bind mount inside the Linux micro-VM to present that path to the container.)
- Execution interface:
- A CLI with a fast exec path, and a session path for interactive use
- A daemon on the host OS handles sandbox lifecycle management, with the CLI just thin wrapper that makes IPC calls to the daemon
- The container environment also has a
sandCLI, which uses container-to-host networking to make IPCs to that same daemon
Implementation decisions I'm still investigating:
- Lifecycle & Pooling Strategy: Currently
sandwill just spawn containers on demand, with no pooling. It does not monitor container activity or utilization etc. You can stop and start sandbox containers manually, butsanddoes not try to do any of that automatically yet. - Network Topology: Per-container isolated network vs. shared host network vs. a managed bridge, vs ... something else perhaps? A lot of this aspect is constrained by what MacOS and Apple Containers will support.
See cmd/sand/HELP.md for a full CLI reference.
The sandbox starts out with a clone of your current directory from MacOS, mounted as /app inside the container.
This cloning operation actually uses much less disk space than a full copy of the original directory, because sand clones it using copy-on-write (via APFS's clonefile(2) call). Additional disk space is only consumed by the sandbox when the cloned files are modified.
Note: The original files on your MacOS host filesystem are not affected by changes made to the clones of those files inside the sandbox. You can rm -rf / in the sandbox container and it won't affect your original working directory at all.
You can use git commands to push changes from the container to github, or wherever your origin is.
Git ssh authentication passes from your MacOS host through sand containers, via ssh-agent. This means that if the git checkout on your MacOS host is authenticated with ssh (git remote -v origin prints something that starts with git@github.com:...), then you don't need to log in again inside the container to make git push/pull to work.
Using ssh-agent also means you don't have to leave copies of your github credentials scattered around in places where they shouldn't be.
See doc/GIT_REMOTES.md for a more detailed explanation of how sand uses git locally to link the MacOS-side clones back to your original working directory. If you are a git enthusiast, you can probably figure out how move changes around between your MacOS host and your sandbox containers without involving github at all.
$ sand --help # a much more complete list of commands and flags
$ sand ls # lists your current sandboxes
$ sand git status your-sandbox-name # prints the results of running "git status" in the sandbox's working directory
$ sand git diff your-sandbox-name # compares your working directory to the sandbox's clone of your working directory
$ sand vsc your-sandbox-name # launches a vscode window, connected "remotely" to your-sandbox-name
$ sand shell your-sandbox-name # open a new shell into the your-sandbox-name's container
$ sand stop your-sandbox-name # stops the sandbox container, but does *not* delete its filesystem
$ sand rm your-sandbox-name # stops and removes the container, and *does* remove the sandbox's filesystem.For more information about sand's subcommands and other options, see cmd/sand/HELP.md.
- Only works on Apple hardware (of course).
- Apple Silicon Mac (M1/M2/M3/M4)
- macOS 15 (Sonoma) or later
- Install
apple/containerfirst, since these helper functions just shell out to it.