---
title: "Dumb Sandbox, Smart Host"
author: "Peter Pang (@intuitiveml)"
source_url: "https://x.com/intuitiveml/status/2066982286395068540"
published_at: "2026-06-16T20:32:34.000Z"
fetched_at: "2026-06-17T15:58:37Z"
updated_at: "2026-06-17T15:58:37Z"
language: "en"
review_status: "source-checked"
---

# Dumb Sandbox, Smart Host
Most cloud agent architectures start by asking what the sandbox can do.
Can it run shell commands? Can it install packages? Can it call APIs? Can it persist files? Can it make LLM calls? Can it recover after a crash?
After building this layer for a while, I think the better question is the opposite:
What should the sandbox never be trusted to do?
A desktop agent collapses everything into one boundary. The user, machine, filesystem, credentials, runtime, and process all live together. The agent can read local files, use local environment variables, call APIs directly, and rely on the user to retry when something breaks.
A cloud agent does not get that simplicity.
It runs on shared infrastructure. It executes code written by an LLM. It may be triggered by a human, a cron schedule, an API call, or another agent. The user may not be present. The prompt may be adversarial. The code inside the execution environment may already be compromised.
That changes the architecture. The rule we landed on is simple: The host is smart. The sandbox is dumb.

The host is the trusted, long-lived control plane. It owns identity, secrets, billing, persistence, retries, policy, observability, and the truth-of-record for the run.
The sandbox is the disposable execution boundary. It runs model-chosen code and shell commands. It can create files. It can call tools through narrow channels. But it does not hold long-lived credentials, does not write business state directly, does not decide billing, and does not call internal services as itself.
This split sounds obvious after the fact. It is not obvious while building.
The tempting design is to make the sandbox smarter every time a new feature needs something. If the agent needs Slack, give the sandbox a Slack token. If it needs persistence, let it write to the database. If it needs billing, deduct credits from inside the runner. If it needs to call an internal API, give it a service URL and a secret.
Each decision feels locally convenient. Together, they turn an untrusted execution environment into the most privileged part of the system.
That is backwards.
A sandbox should be powerful in one dimension only: execution. It can run the code the model chooses. Everything else should be mediated by the host.
When the agent needs to call an authenticated service, the sandbox does not receive the OAuth token. It sends a request through a bridge. The host validates that the request belongs to the current run, checks policy, attaches the real credential server-side, forwards the call, records what happened, and returns only the response.
When the agent needs to persist output, the sandbox does not become the database client. It emits structured events or writes artifacts that the host chooses to store. If the sandbox disappears halfway through the run, the durable record still lives outside it.
When the agent needs to spend money, the sandbox does not charge itself. The host sees the call, applies rate limits, deducts credits, and logs the decision. Any accounting system that depends on untrusted code voluntarily reporting its own usage will eventually be wrong.

The same pattern applies to observability. Logs trapped inside the sandbox are useful for debugging, but they are not the system of record. The host needs to see every meaningful boundary crossing: tool calls, generated artifacts, user-visible events, credit deductions, retries, failures, and final state.
The sandbox can still have limited intelligence. It can run helper scripts, call local tools, use MCP servers, and make LLM calls when needed. But those LLM calls should go through a gateway with scoped, short-lived credentials. The sandbox should never see the real provider keys.
The boundary is the product.
A good cloud agent runtime has a narrow interface between host and sandbox. The sandbox can ask. The host decides.
That interface usually looks boring: stdout markers, bridge calls, scoped tokens, expiring credentials, structured events. Boring is good. Boring means auditable. Boring means replayable. Boring means you can reason about what happens when the sandbox is compromised.
The failure case is the design test.
If prompt injection convinces the agent to dump its environment, what leaks?
In the smart-host, dumb-sandbox model, the answer should be: no long-lived provider keys, no database credentials, no user OAuth tokens, no internal service secrets. At worst, the attacker gets scoped credentials that only work for this run, from this environment, for a short window.
If the sandbox crashes, what is lost?
Scratch files, maybe. In-progress execution, probably. But not the user’s identity, not billing state, not the durable event log, not the platform’s ability to retry or explain what happened.
That is the point of keeping the sandbox dumb. Not because it does nothing, but because it is replaceable.

A cloud agent is not a VM with some AI inside. It is a trusted host coordinating an untrusted executor.
The user’s intent belongs to the host. The execution belongs to the sandbox. Secrets, billing, persistence, and policy belong outside the blast radius. Once you draw that line, new features get easier to place.
Does it need a secret? Host.
Does it need a durable state? Host.
Does it decide whether a user is allowed to do something? Host.
Does it execute agent-written code? Sandbox.
Does it need to cross back into the product? Bridge.
The architecture becomes less about adding capabilities to the sandbox and more about designing the channels around it.
That is what makes cloud agents safe to run unattended. Not a smarter sandbox, but a dumber one with a smarter host around it.