Skip to content
View as Markdown

Architecture ​

        your agent / SDK / CLI
                 │  HTTPS
                 ▼
   ┌──────────────────────────────┐
   │  control plane (pkg/server)  │  scheduler · tunnels · policy · API
   └──────────────┬───────────────┘
                  │  reverse WebSocket + yamux   ← the worker dials out
                  ▼
   ┌──────────────────────────────┐
   │  worker (cmd/poder)          │  Docker lifecycle on one machine
   └──────────────┬───────────────┘
                  │  container network
                  ▼
   ┌──────────────────────────────┐
   │  toolbox (in the sandbox)    │  code execution · PTY · files
   └──────────────────────────────┘

The control plane ​

pkg/server is the whole API: it schedules a create onto a worker, keeps the tunnel objects, enforces auth and quotas, calls the admission gate, and emits lifecycle events. It is importable as a library — server.New(...) returns the handler the command-line binary serves — which is how a commercial build adds accounts and billing without forking anything.

Persistent state is either SQLite (one instance) or PostgreSQL (a fleet). The schema is additive: an older binary runs against a newer schema, which is what makes a rollback a tag change rather than a migration.

The worker ​

cmd/poder runs on the machine that has the Docker socket. It dials the control plane once and keeps that connection: no inbound port is opened on the worker, which is the property that makes it usable on a laptop behind NAT, a customer's VM, or an employee workstation.

Over that tunnel it receives "create this container", "delete that one", and forwards execution requests to the toolbox inside each sandbox.

The toolbox ​

cmd/toolbox runs inside every sandbox. It is the thing that runs code: language runtimes, a PTY, file operations, streaming output, and a port preview proxy. It listens on 8080 inside the container; nothing outside reaches it directly.

The agent (no Docker) ​

cmd/agent registers the local machine itself as the sandbox, embedding the toolbox. That is how SandrPod runs on a macOS laptop or a bare VM with no Docker: the machine is the sandbox. The same binary carries the permission gate, the decision audit, egress enforcement, and OS-level sandboxing (bwrap, seatbelt).

What a request actually does ​

POST /sandboxes/execute on a running sandbox:

  1. control plane authenticates, resolves the sandbox, checks ownership;
  2. finds the tunnel for the sandbox's worker — locally, or on a peer instance (it forwards, see More than one instance);
  3. opens a yamux stream to the worker and asks for the toolbox;
  4. the worker dials the container's toolbox over the container network;
  5. the toolbox runs the process and streams the result back along the same path.

Latency is dominated by the process, not the hops: the tunnel is a warm TCP connection, not a new one per request.

Eight providers, two mechanisms ​

Creating a worker in the cloud is the same shape for all eight providers, with two remote-exec mechanisms underneath:

MechanismProviders
managed run-commandAWS (SSM), Aliyun (Cloud Assistant), Azure, Tencent (TAT), Oracle
SSH with an ephemeral keyGCP, DigitalOcean, Hetzner

Either way the VM boots, Docker is installed, a worker is started with a join token, and the control plane waits for it to come online. If it never does, the VM is terminated rather than left billing — every failure path in that flow gives the machine back.

Apache 2.0 — your clouds, your machines, your rules.