We rejected the cheaper design and gave every agent its own kernel

2026-08-05

The economical way to sell agent hosting is a shared pool. Buy a small number of large machines, run each customer as a container with a CPU and memory quota, and pack them densely. Per customer it is a fraction of the cost of a dedicated instance, a new tenant starts in seconds because there is nothing to boot, and you can oversubscribe, because customers are idle at different times and their peaks average out.

Most agent platforms are built this way. It is a good design for the thing it was designed for. We rejected it, and the reason is what the workload actually is.

The tenant is not a web app

Container multi-tenancy assumes a fairly narrow tenant. A web app receives requests, runs code its author wrote and reviewed, talks to a small set of known hosts, and stays inside a resource envelope you can predict from its traffic. That tenant is easy to fence, because almost everything it does was decided before deployment.

An AI agent breaks each of those assumptions.

It executes code that nobody reviewed. That is not a flaw, it is the product. You tell the agent to accomplish something and it writes and runs whatever it decides accomplishes that. The set of syscalls it might make is not knowable ahead of time, and it changes when the model changes, which happens on the upstream provider’s schedule rather than yours.

It initiates outbound network traffic on its own judgement. A web app talks to the hosts in its config. An agent fetches a URL it found in a document, installs a package it decided it needed, and calls an API it discovered mid-task. Egress filtering is the standard container control here, and an allowlist that actually contains what agents need is close to the open internet.

It holds long-lived secrets in resident memory. Your model keys, whatever credentials you gave it to do its job, the files it is working through. Not passed through and discarded, but held, for the duration of a task that might run for hours.

Put several of those on one kernel and the blast radius of a container escape is every tenant on the box: their keys, their files, their in-flight work. Container escapes are not theoretical, and the number of ways a workload can reach for one scales with how much arbitrary code it runs. This workload runs a lot.

Quotas are not the isolation you think they are

The second failure is quieter and happens without anyone attacking anything.

Agent workloads are bursty in a way that defeats fair-share scheduling. An agent is idle for minutes waiting on a model response, then saturates a core compiling something, then goes idle again. Multiply by a dense pack of tenants and the utilization curve is spiky, not smooth, which is precisely the case oversubscription handles worst.

Then there is the loop. An agent that misreads its own output and retries forever is a normal failure mode, not an exotic one. CPU shares will contain it, in the sense that its neighbours still get scheduled. What shares do not contain is everything that is shared but not quota’d: page cache pressure, disk queue depth, the network interface, the kernel’s own locks. Your neighbour’s runaway loop becomes your latency, and there is nothing in your dashboard to explain it, because from your side nothing you did changed.

The honest version of “isolated with quotas” is that CPU and memory are isolated and the rest is a polite agreement.

What the choice costs us

The dedicated instance is more expensive to run and we should be specific about how, because a decision with no stated price is a slogan.

The floor price is higher. A container slot can be sold for whatever a slice of a big machine costs. A dedicated instance cannot go below what one instance costs, which sets a hard minimum on the cheapest thing we can offer. There is no way around that with volume.

Provisioning takes minutes, not seconds. A container starts by unpacking an image onto a machine that is already running. We create an instance, wait for it to boot, set credentials as a separate step, verify those credentials work, and configure the agent on top. Onboarding is measurably slower than a competitor whose signup drops you into a running container.

Capacity cannot be smoothed. Every instance is provisioned for its peak and paid for continuously, including while it sits idle waiting on a model call. In a shared pool that idle time is someone else’s burst. For us it is just idle time, and we pay for it.

Those are not framing problems. They are what the design costs, permanently.

What it buys

A machine you hold the root password to.

That is one sentence and it is worth unpacking, because it is the entire return on the three costs above. You can SSH in on port 22 with a credential we verified works before we showed it to you. You can read the actual logs, not a filtered view of them. You can install something we never shipped and never anticipated, including things that need kernel modules or privileged operations that no container platform will ever hand you. You can inspect exactly what your agent did, at the process level, because you have a process level to inspect.

You can also leave. Take a snapshot, move it somewhere else, keep working. Nothing about your setup depends on our control plane at runtime. The agent runs on the box, holds its own keys, and does not phone home to us to function.

That last property is the one that matters most to us and it is not really a technical argument. A seat on a platform can be reshaped by the platform. Limits change, a runtime gets deprecated, the sandbox tightens for reasons that have nothing to do with you. A rented server is a smaller promise, and smaller promises break less. What you get is an instance, an IP, a disk, and a root password. What we can unilaterally change about it later is close to nothing, which is the point.

Where the line actually sits

I want to be careful not to overclaim. A dedicated instance is not a security guarantee. It is one boundary, at the kernel, and it removes one class of failure: the class where your neighbour’s problem becomes yours. Everything above that boundary is still your responsibility, and an agent with your keys can still do something you regret entirely within its own machine. We have not solved that and neither has anybody else.

What we have done is decline to stack a second class of failure on top of the first in order to make the unit economics easier on ourselves.

The open question I do not have a clean answer to: this reasoning holds because agents run arbitrary code and hold secrets. If a future agent runtime made those two things provably false, the case for the cheaper design would be back, and we would be the ones charging more for a boundary nobody needed.

Back to blog