architecture

The whole deploy layer is one 8 MB process.

One static binary. No database, no message queue, no sidecars, no agent-on-every-node. Docker does the muscle work; the daemon owns the decisions.

8 MB

binary - static Go, all four platforms

8.3 MB

resident memory, measured while serving a live app

1

process: proxy + API + archivist

2

runtime dependencies: the docker and git CLIs

Measured on v0.7.1, darwin/arm64, daemon serving a FastAPI app through several push/rollback cycles. Idle CPU is effectively zero - the daemon wakes for pushes, the drift ticker, and the held-fork reaper.

One process, four jobs

The proxy is Go's standard-library reverse proxy - the hop it adds is sub-millisecond on loopback. There is no framework underneath, no embedded server runtime, nothing resident between deploys except the two listeners.

No database. Docker is the state.

The daemon's persistent state is a handful of marker files, each a few bytes: the live container's name, the next version number, the order versions served in, and one held-marker per fork under test. Everything else is read back from Docker itself - the ring of previous versions is literally docker ps filtered by label.

That's why restarts are boring: the daemon comes up, finds the container it last put live, and adopts it without touching it. Serving traffic survives daemon upgrades, crashes, and reboots, because the thing serving traffic was never inside the daemon to begin with.

Where the resources actually go

The daemon is small because the spending is deliberate - and it happens on disk, not RAM:

For scale: the layer hotlane replaces ships an always-on agent per node that idles in the hundreds of megabytes before running any of your code - plus the control plane it answers to.

The trust model is the architecture

Everything above follows from one decision: the daemon holds the Docker socket, and holding the socket is root-equivalent. So the deploy API in front of it is treated as what it is - remote code execution as a service:

01

Loopback by default

Bare hotlane serve binds the API to 127.0.0.1. Binding wider without a token is refused at startup, not warned about.

02

One token, constant-time

Set -token and the default widens for remote CI - every state-touching route behind a bearer check; only liveness and directions answer open.

03

TLS built in

-tls puts the app on https://your-domain/ with Let's Encrypt, the API tucked under /-/ - no reverse proxy to configure.

The full posture - symlink-safe snapshots, tokenized fork addresses, what stays out of logs - is in the CI & security FAQ.

Read the whole thing before lunch

The daemon is a few thousand lines of Go across ten packages - pool (forks and the ring), archive (clean builds and drift), replay, proxy, detect, and friends. No plugins, no CRDs, no operator pattern. If you're deciding whether to trust it with your box, the honest answer is: read it.