The agent
The process a customer runs on their own machine — what it is, what it listens on, and how the channel works.
The agent is a plain Node process that runs on a machine the platform's operators do not own. It holds one credential — its token — and listens on nothing.
Why it has no port
The product promise for cloud mode is that you open no port and write no firewall rule. A process with a bound port on your box contradicts that, quietly, in the one place the promise was supposed to be true. Everything reaches the agent through one connection it opened outwards.
It is not a NestJS application for a related reason: it runs on a machine whose memory is meant to be yours, and a framework would buy dependency injection for roughly two hundred lines.
The channel
The control plane exposes /agent/connect — a WebSocket upgrade on the API's own HTTP
listener, not an HTTP route.
| Authentication | The x-agent-token header, during the handshake. Never a user session. |
| A rejected agent | Gets a 401 and no socket. |
| Sessions | One per server. |
| Protocol | A correlated RPC with streaming and upload frames, so a socket behaves like a function call. |
| Validation | The envelope is validated with zod on arrival, because it comes from a machine the control plane does not run. A result's contents are shaped by ServerDriver and trusted exactly as far as the server they describe. |
This is the one documented exception to the platform's resource-naming rule: it is a transport channel rather than a REST resource.
Heartbeats and going offline
The agent sends a heartbeat every AGENT_HEARTBEAT_SECONDS (25 by default) — deliberately
below any sensible proxy idle timeout. A socket that only carries traffic during a deployment
is idle nearly all the time, and more reverse proxies than not close an idle WebSocket at 60
seconds.
The control plane drops an agent after AGENT_OFFLINE_AFTER_SECONDS (90) of silence even if
the TCP connection looks open, because a connection through a NAT outlives the process at
the other end.
That is a deliberate false negative. A deployment handed to a dead machine waits out its full timeout instead of failing at once, and a machine wrongly marked unreachable recovers on the next heartbeat.
Reconnection
Backoff runs from AGENT_RECONNECT_MIN_SECONDS (2) to AGENT_RECONNECT_MAX_SECONDS (60). The
ceiling means a control plane that is down for a day is retried hourly rather than hammered.
An agent refused by the control plane — because its token was rotated or its server was removed — stops retrying and says so.
Uploads
A deployment's archive reaches the agent in frames of AGENT_UPLOAD_CHUNK_BYTES (256 KB).
base64 inflates by a third, so the wire cost is that times 1.34.
The agent's own AGENT_MAX_UPLOAD_BYTES matches the control plane's upload cap. A lower value
here would fail a deployment the portal had already accepted.
Version skew
The agent reports its version in the opening frame, so the portal can name a stale one. A control plane speaking a newer protocol than the agent tells it so in the agent's log; the fix is to pull the image again and recreate the container.
Configuration
Every value is in agent configuration. The two that matter:
CONTROL_PLANE_URL=https://portal.example.com
AGENT_TOKEN=<the token the portal issued>Use wss:// — that is, an https:// control-plane URL — in anything but a
local experiment. The socket carries the token and every command the control
plane issues.