Three scripts land in front of your agent: one a colleague sent, one pasted into an issue by someone you have never met, one the agent wrote itself after reading both. You ask which produces the right output. The agent runs them in order, in the same box, and reports back: the third. It is probably right. It is also true that the second script started on a machine the first had already had its hands on, and whatever the first changed on the way through was sitting there waiting. Nothing in the transcript says so. Nothing in the transcript could.

You replace the cover, not the room

Watch a tattooist get ready for the person in the chair. The chair, the lamp, the machine on its stand, the bottles on the shelf were there before anyone walked in and will be there tomorrow. What happens in the two minutes before the needle touches skin is thin and fast. A film goes over the lamp handle and the cable. A needle comes out of a pouch, opened in front of you. Ink is poured from the big bottle into a small cap, and at the end that cap goes in the bin with most of it unused, along with the film and everything else near the work, including the parts that look clean.

Nobody rebuilds the room between clients, and nobody needs to. Preparing the room is the slow job, and it is shared by everyone who sits down. What belongs to one person is the thin layer over the top, and it costs almost nothing, which is why it can be per client rather than per day.

A per-action fresh virtual machine runs on the same arithmetic. The harness keeps one VM template preloaded, with the toolchain installed and the environment already shaped. When a risky call arrives, it forks that template copy-on-write: the fork shares everything with the template until it writes, which is what makes one per call practical rather than one per session. Scoped code and input go in, the declared artifacts come out — standard output, the files named in advance — and the machine is destroyed. Your three scripts get three independent forks with the network held down. A process one script left running does not exist when the next starts, because the machine it ran on does not.

Persistence between two actions is the attack

Almost everything you fear here needs a second action to be worth anything. An instruction smuggled into a web page can do little inside the call that read it; what it wants is to write a shell profile, drop a binary onto the path, leave something listening, and let the next twenty calls inherit all of it. A session-long sandbox gives it that afternoon. Moving the boundary down to the action takes the afternoon away, and not by detecting anything: there is no next call.

The quieter benefit is that effects get an address. When three scripts ran on three machines, the file that changed belongs to one of them by construction, rather than being reconstructed later from a box where everything touched everything.

Three ways this gets undone. Reusing a fork after a failure to save the setup, which spends the isolation where residue is least understood. Baking secrets into the base template, since whatever is in the room is in every cover. And treating disposal as the whole policy. Destroying a machine does not unsend what it sent, so egress limits and output filtering stay your problem. Disposal bounds what stays, not what left, which is the same bargain as putting the agent inside the sandbox, priced per action.

The agent’s shell is not your account

Some work genuinely has to touch the host, with credentials that are really yours. A split shell execution boundary keeps that from collapsing everything else. The agent lives inside the sandbox, or talks to a small service inside it over a local socket, and compiles, tests and edits with no ceremony. The rare host capability goes through a filter that grants named commands one at a time, so a coding agent that builds freely gets one authorised repository operation, not a lease on your files and tokens.

Put that filter inside the sandbox and it guards the room you already decided to trust. Expose the service on a network socket rather than a local one and the boundary is reachable by whatever can route to it. Hand host access to tool servers still being written and you skip the isolated session where you meant to edit and test them.

Shell access is useful. It is not the same as being you, and the cheapest way to stop something persisting is to leave it nowhere to persist.