Sandbox lifecycle
Workloads on this platform are not meant to run continuously. A sandbox exists while its task does; an MCP server can be started on first use and stopped once nobody is calling it. This page covers how they come up, and how they go away. Reclaim is a security property as much as a cost one. A workload that runs forever is a workload whose compromise lasts forever.The problem
Starting a container on demand is slow in a way that agents feel. Pulling an image, unpacking it, and starting a process takes seconds; an agent may make dozens of tool calls in one task, and a user is watching. Paying that on every call is not viable. Never stopping anything is the other extreme, and it is what the platform did originally. A workspace with thirty MCP connections ran thirty containers whether or not an agent had called any of them that month. The cost is continuous, the utilization is near zero, and each idle container is still a piece of third-party code with a network connection. The two workloads also differ in what stopping them costs, which is why they get different treatment.How AgentArea approaches it
The warm pool removes provisioning from the request path
Rather than creating a pod when work arrives, the platform keeps a set of pods already running and unassigned. Assigning one is a label update, so the expensive part — scheduling, image pull, container creation — happened before anyone was waiting. A pooled pod is not yet the workload it will become. It runs an activation service listening on port 8080. Activating it posts the target image, and the service fetches and extracts that image into an overlay directory, reads the image config for itsENTRYPOINT, CMD, and WORKDIR, and starts the process
under chroot into the extracted root filesystem, so relative entrypoints behave
as they would under a container runtime.
Pods move through recorded states: waiting, activating, ready, assigned,
then idle once the work is over.
Activation endpoints are authorized with scoped tokens — separate scopes for
activate, execute, writeback, and files — signed by the control plane, so
a pod’s executor cannot be driven by anything that has not been issued the right
scope.
Runtime policy is deployment-owned. The built-in Kubernetes provider may use
a warm pool, while external providers allocate their own sessions. In every
case, the Go manager chooses exactly one configured provider and runtime policy;
task payloads do not carry an image or package-install profile. If the selected
provider cannot attest the required isolation boundary, creation fails loudly.
Sandboxes are reclaimed from observed HTTP activity
The Go manager is the lifecycle authority. A command or file request provisions or reuses the task binding and renews its active lease; command heartbeats keep that lease alive. When the operation finishes, the manager moves the binding toSANDBOX_TASK_IDLE_TTL. A later request wakes or recreates it and materializes
the durable workspace. No Temporal activity names or invokes sandbox creation,
retirement, or cleanup, so switching data-plane providers does not change the
agent workflow.
MCP instances can be serverless, because stopping them costs nothing
An MCP instance is stateless with respect to startup: it is an image plus environment variables from the database. Stopping and restarting it returns the same instance, so reclaiming it is lossless. That is why serverless is available for MCP and not, currently, for sandboxes — a sandbox holds a working directory that dies with the pod. When serverless is on, an instance is started on its first call and stopped after it goes idle. Only the workload goes; the database row, the credentials, and the discovered tool list are untouched, and the next call provisions it again through the path that started it the first time. Reclaim works by sweep. EverysweepInterval (default 60s) the manager selects
instances that are lazily provisioned, currently provisioned, and have not been
called for longer than idleTimeout (default 10m). It stops each workload and
resets the instance’s verification state so the next caller provisions it rather
than dispatching into nothing. That reset is a compare-and-set against
succeeded, so a verification that started concurrently wins instead of being
overwritten.
Sweeping is serialized across manager replicas with a Postgres advisory lock. If
a manager dies mid-sweep the lock goes with its connection; there is nothing to
clear by hand.
Two categories are deliberately excluded. Remote (url-type) connections have no
container to stop. Instances that have never been called are treated as new
rather than idle — reclaiming requires evidence of disuse, not absence of
evidence of use.
The mode is recorded per instance at creation. Turning serverless on later
does not retroactively shorten the life of existing connections, and turning it
off does not strand ones created serverless.
Why not keep everything running
Always-on is predictable. No cold starts, no first-call latency, no question of whether the wake path works, and verification failures surface when a user creates the connection rather than when an agent first calls it. The platform’s position is that this does not survive multiplication. Utilization of a typical MCP connection is very low, and the resident cost is paid continuously by every workspace. The security argument is the stronger one: an idle container is still attack surface with a network path, and reclaiming it shrinks the window in which a compromised or vulnerable server is reachable. The costs are real and are not defects to be fixed. The first call after an idle period pays a cold start whose length depends entirely on the server — a small published image starts quickly, while auvx or npx server that clones and
installs on boot can take substantially longer, and the call waits rather than
failing. And because verification is what starts the container and lists its
tools, deferring the start defers the check: a bad image reference or a missing
environment variable surfaces on first use instead of in the connection form.
Serverless is off by default for these reasons.
Why not scale to zero with a queue in front
The tidier design gives each MCP server a queue and a scaler, so requests buffer while the workload comes up, and there is no user-visible failure mode at all. It adds a broker per connection and moves failure from “the call was slow” to “the call is somewhere in a queue”, which is harder to reason about and harder to attribute when an agent’s tool call hangs. It also does not remove the cold start; it hides it behind a component that now has to be operated and monitored. The current design accepts the visible wait in exchange for one fewer moving part per connection, on the reasoning that an agent tool call is already an operation where a several-second wait is normal.Limits
Reclaim does not observe agent traffic. The idle sweep selects onlast_used_at, and that column is written in exactly one place: the HTTP proxy
path used by registered CLI harnesses. The agent tool-call path resolves the
instance URL and calls the container directly, then enqueues a usage record onto
an in-process queue. The consumer of that queue,
_flush_last_dispatch_loop, has no production caller anywhere in the tree, and
it writes a different column (last_dispatch) in any case. Two consequences,
both bad:
- An instance used only by agents keeps
last_used_atas NULL, is excluded by the selection query, and is never reclaimed — the main scenario, in which nothing is freed. - An instance called once through the proxy and thereafter only by agents has a timestamp that goes stale under live traffic, so the sweep can stop an instance that is actively in use.
tools column is written only by
verification. Tool discovery has an escape hatch for exactly this case — a lazy
instance passes if it declared its tools in advance — but nothing populates
json_spec.available_tools: its only writer, set_available_tools, has no
callers. The tool list is therefore empty, the escape hatch does not trigger, the
agent is offered no tools from that instance, and it never makes the first call
that would wake it.
Stopping races with waking. The sweep selects, deletes, then resets state. A
caller that has already read the instance as provisioned can dispatch to a
Deployment deleted moments earlier and get an error with no retry. Each
reclamation under live traffic can cost a failed tool call.
The reaper does not start if the database is not configured, and says so only
at warning level. A manager without database credentials logs a warning and
continues without reclaiming anything.
A live task’s sandbox is not reclaimed when idle. Only end-of-task teardown
and lease expiry release a sandbox. An agent holding an open task that does
nothing for twenty minutes keeps its pod for up to the full lease, two hours by
default.
The warm pool is off by default. mcpManager.warmPool.enabled is false,
and the pool also requires the warm_pool feature flag. Without it, sandbox
pods are created on demand and pay full provisioning, and the sandbox
NetworkPolicies described in isolation are not
rendered.
Activation falls back to running without chroot. If chroot fails — for
example without CAP_SYS_CHROOT — the activation service logs a warning and
starts the image’s entrypoint directly in the pod’s own filesystem, rather than
inside the extracted image root. The comment describes this as expected under a
VM-isolating runtime where the VM boundary substitutes, but the fallback fires on
any chroot failure, including one where no such boundary exists.
Published activation timings are not reproducible from this repository. The
existing warm pool and serverless pages quote several different figures for
activation and cold start, none citing where they were measured, and the chart
comments give a different range again. Treat them as illustrative and measure
your own deployment.
Related
- Sessions — what a sandbox holds while it lives
- Isolation — what confines it
- MCP — what an MCP instance is
- Serverless MCP instances — enabling and verifying the mode