You ask the agent to bump a dependency and get the suite green. It edits the manifest, runs the tests, and one of them wants a fixture kept in another repository, so it runs a fetch. The command comes back with an error. The agent reads that error the way it reads every other error, as something that might behave differently the second time, and runs the fetch again, then against a different remote, then with a longer timeout. Nothing was ever going to change. The environment is offline on purpose, it did exactly what you configured it to do, and at no point did it say so.

The till tells you why it stopped

Stand at a self-service till with a bottle of wine and a bag of apples. Something halts the lane and a light comes on above your head. If the screen tells you only that there is an unexpected item, you lift the thing off, put it back, scan it once more, and the light stays on: you are arguing with a rule you cannot see. If the screen says the wine needs an assistant because of its age limit, you stop scanning and wait for the person with the override key. Same halt, same rule, completely different behaviour, because the second message tells you the problem is not your technique. The sign at the head of the lane, listing what these tills will not take at all, does the same job earlier.

A sandbox can be built to talk that way. One interface applies whatever the platform offers underneath, Seatbelt on macOS, Landlock and seccomp on Linux, a virtualised subsystem elsewhere, to the whole process tree the agent runs in. The description of the shell tool states which paths are writable, which Git operations are permitted and whether the network is open, so the limits arrive before the plan does. And when a command is denied, the result names the constraint that denied it and, where it makes sense, says that asking is the way through.

A denied command is not a failed task

That distinction is small and it is the entire idea. At the bottom of a shell, a permission failure and a genuine task failure look alike: non-zero, a line of text, nothing done. An agent that cannot tell them apart has one move available, which is to try again, and trying again is the right move for exactly one of the two. Repeating a blocked command is not recovery. The recovery for a refusal is to say what it needs and why, and let a person open the online path or the extra directory, which is where the human belongs in the loop anyway.

You can check whether the boundary is doing its job, and this is the part teams skip. Two numbers, taken first in offline evaluation and then during a gradual rollout: completion rate, the share of tasks the agent still finishes, and interruption rate, how often a run has to hand back to you. A boundary is validated when both move the way you intended, not when only one does. Tighten the environment without also updating the tool schema, the way errors are rendered and the evaluations, and completion drops while nobody can point at the reason.

The same no, assembled from different parts

What produces the refusal travels badly. Windows has no single primitive of that kind, so it gets composed: dedicated sandbox accounts, one online and one offline, a write-restricted token under which a write needs both the owner’s permission and a restricted identifier granted only to the workspace and the writable roots, narrow access rules on top, and a firewall rule that blocks all outbound traffic for the offline account, attached to the sandboxed process tree rather than to the binary of the harness. Privileged setup stays separate from the unprivileged run. What the agent sees is plainer: it edits the checkout and runs the tests, it cannot touch the repository’s own Git directory, and an installer reaching for the network from the offline account is simply refused.

None of that machinery is visible from inside, and none of it needs to be. What has to be the same on every platform is not the mechanism but the sentence that comes back, which is only the contract with the environment extended to the moment things go wrong. A no the agent can read is worth far more than a no it can only walk into.