sndbxd
One small server for two jobs: throwaway sandboxes where AI agents can run code safely, and long-lived dev boxes I can SSH into from anywhere.
- Host
- Headless Mac, macOS 26
- Runtime
- Apple Containerization
- Server
- Swift, Hummingbird 2, GRDB
- Stage
- Milestone 1
Why build it
Coding agents work best when they can install packages, run tests and break things. I don’t want them doing that on my laptop. I also wanted a persistent development machine that survives a closed lid.
Both needs come down to the same thing: start a Linux environment fast, give it the right files, and control what it can reach. So both modes share one boot path and differ only in lifetime, storage and how you connect.
Two modes, one boot path
| Property | Agent sandbox | Dev box |
|---|---|---|
| Lifetime | Minutes to hours, ends at its TTL | Weeks or months |
| Connect | Exec API, called by the agent | SSH from any editor |
| Storage | Scratch disk, deleted with the sandbox | Persistent /home and /workspace |
| Network | Outbound traffic limited to an allowlist | Configured per template |
How a request flows
- ClientsAgents call exec; people use SSH
- REST API/v1, envelope, RFC 9457 errors
- DaemonHummingbird 2 + GRDB state
- SandboxRuntimeProtocol; a fake runtime for tests
- Linux VMsContainerization, copy-on-write clones
Environments start from templates: a base image, a list of install commands and some defaults. A template is built once with an open network, cached as a root filesystem, and cloned copy-on-write for every new sandbox. At runtime the network closes down to the allowlist.
I wrote my own daemon on the Containerization Swift package instead of wrapping the container CLI. That keeps state, quotas and errors in one place.
Starting a sandbox
State changes go through one PATCH on the desired state. When the host is full, the API answers 422 with a problem document instead of queueing forever.
PATCH /v1/sandboxes/sbx_7f2c
{ "desiredState": "running" }
202 Accepted
{
"data": {
"id": "sbx_7f2c",
"template": "swift-6",
"state": "starting",
"expiresAt": "2026-11-03T04:10:00Z"
}
}Where it stands
- NowWalking skeleton: the API, state store and a fake runtime, end to end.
- NextThe real Containerization adapter and template builds.
- LaterSecrets injection, git auth and SSH access for dev boxes.
Inspired by the sandboxy example in Apple’s containerization repository.