0001. Docker first, behind a backend interface¶
Status: accepted, 2026-09-30
Context¶
A sandbox server needs an isolation technology. Docker is on almost every Linux host people self-host on, needs no extra kernel setup, and pulls any OCI image. MicroVMs such as Firecracker isolate better but need KVM, root filesystem images, and an in-VM agent. gVisor sits in between and plugs into Docker as an OCI runtime.
Decision¶
Ship one backend, DockerBackend, and put it behind the abstract Backend
class in agent_sandbox.backends.base. The manager owns IDs, quotas, TTLs,
locking, path validation, and snapshot storage, so a backend only creates and
destroys environments, runs commands, moves files, and exports and imports the
workspace as tar streams. The Docker backend hardens every container: non-root
user, all capabilities dropped, no-new-privileges, read-only root filesystem,
no network unless requested, and pids, memory, and CPU limits.
Consequences¶
- The server installs with one
docker compose up, and tests run on any CI runner with Docker. - Sandboxes share the host kernel. The README and the docs state that limit plainly instead of implying VM-grade isolation.
AGENT_SANDBOX_DOCKER_RUNTIME=runsccan already pass gVisor through, and a Firecracker backend can implement the same interface later without touching the API or the manager.- An in-memory fake of the interface (
tests/fakes.py) lets the unit tests run without Docker.