Start
How it works
The agent runs in a sandbox on your machine. A policy decides what it can read, write, and reach. Fenzi writes that policy, starts the sandbox, and keeps the record.
The pieces
The sandbox is OpenShell, an open source runtime licensed under Apache 2.0. Fenzi does not replace any part of it. We pin a version and drive it through its own commands. The sandbox holds the agent process.
| Piece | Where it runs | What it does |
|---|---|---|
| Fenzi CLI | Your machine | Compiles the policy, checks it, starts the sandbox, copies the project in and out, files approvals, reads the log. |
| Gateway | Your machine | OpenShell's control process. Holds sandboxes, policies, and credentials for this machine. |
| Supervisor | Inside each sandbox | Applies the filesystem and process rules at start, and runs the proxy every network call goes through. |
| Agent | Inside the sandbox | Claude Code, Codex, or another agent, running as an unprivileged user. |
| Control plane | Our cloud, Team only | Holds the org policy, the approval queue, and the decision log. Never connects to your machine. |
What is inside the sandbox
- The agent's image. Built on your machine from a Dockerfile we publish, with the agent,
git, and common tools. We do not redistribute agent binaries. - A copy of your project. Uploaded at start, respecting
.gitignore. The agent edits the copy. You apply the changes when it exits. - Nothing else from your machine. Your home directory is not there, so
~/.aws,~/.ssh, and your shell history are not there either. Only what is uploaded or built into the image exists. - Placeholders instead of keys. The agent's environment holds a placeholder. The real key is added by the proxy, only on requests that the policy allows and only to the endpoints that key belongs to.
Inside, the project folder and /tmp are writable. System folders such as /usr and /etc are read-only. Anything not listed is not reachable at all.
Walls and doors
Some parts of the policy are fixed when the sandbox starts. Others change while it runs. Fenzi always tells you which kind of change you are making.
| Change | Kind | What happens |
|---|---|---|
| A host added or removed | Door | Checked with the prover, then applied to the running sandbox as a new revision: on Free with fenzi policy apply after you edit fenzi.yaml, on Team when fenzi sync or the forwarder picks up a published revision. A change the prover refuses is not loaded. The sandbox loads it on its next poll, about ten seconds later. |
| An approved request | Door | Same as above. The agent retries and the call goes through. On Team, the forwarder applies a console approval on its next pass first, so it takes about fifteen seconds. |
| A path made readable or writable | Wall | The running sandbox keeps the paths it started with, and Fenzi says so. The next run creates a new one with the new paths. |
| The user the agent runs as | Wall | Same as above. |
No running sandbox picks up a filesystem change. When a wall moves, Fenzi says the sandbox will be recreated before it does it. It never hides a restart behind a saved message.
When network rules change, open WebSocket connections in the sandbox are closed and clients must reconnect. Plain HTTP requests are not affected.
Keys
Model keys are stored by the gateway on your machine, as OpenShell providers. fenzi key set stores one, or fenzi run creates it from your environment the first time you run an agent. They are never sent to our cloud, on any plan.
Each key is bound to the endpoints it belongs to. A network rule that lets the agent reach a host does not let the key go there. If the agent sends the placeholder to a different host, the request is denied.
What reaches the model
The agent's calls to its model are allowed, because the agent cannot work without them. Whatever the agent puts in a prompt leaves the machine that way: the files it read, command output, and your instructions. The sandbox limits what the agent can read and where else it can connect. It does not read or filter prompts.
Claude Code's web search goes the same way. Anthropic runs the search, so the query travels inside a model call, and the sandbox cannot block it without blocking the model. Fetching a result page from the sandbox is still refused. See Web search.
The log
The sandbox records every network decision it makes, and the gateway on your machine keeps a stream of them in a limited buffer. Fenzi keeps what that stream still holds when it reads it. fenzi log reads the stream while a sandbox runs. When the agent exits, Fenzi saves a copy before it asks whether to delete the sandbox. The save has to come first: deleting the sandbox deletes the gateway's copy.
Each line in the stream is one decision, as text: the time, allow or deny, the program, the destination, and the rule. A deny includes the sandbox's reason. Query strings are left out. The stream does not carry the full audit file the sandbox writes for itself, and that file cannot be read from outside the sandbox. fenzi log and a Team record are both built from these lines. A blocked file write is in neither. The agent sees Permission denied.
On Team, the forwarder follows the same stream for every sandbox Fenzi started and uploads each decision once. If the gateway restarted, or its buffer dropped decisions before they were read, those decisions are gone: the machine reports a gap, and the console shows it for that sandbox and that span of time. So the guarantee is every network decision the gateway still held, with every hole reported. See What our cloud receives.
When our cloud is unreachable
The sandbox keeps enforcing the last policy it loaded. That does not depend on us. On Team, the CLI uses the last signed policy it verified, decision records wait on the machine, and requests stay pending, so the blocked call stays blocked. An enrolled machine that has never received a policy refuses to start a sandbox. Every case is in When something is down.
What a laptop cannot enforce
You own your laptop and the gateway on it. You can change the runtime directly, approve your own requests, or delete a sandbox. On a laptop the developer administers, nothing stops them running an agent outside Fenzi, and Team does not see that run.
On laptops, Team makes the org policy the default path, forwards the decisions and approvals the gateway records for sandboxes Fenzi started, and reports drift: a sandbox running something other than the published policy, or an approval that did not come from the console. Enforcing against the machine's owner needs a gateway they do not administer: the License plan, on a cluster. License is planned and not built yet.
If the sandbox has a bug
Then we have a software bug, and we say so, whichever side of the line it is on. The fix may be upstream: we pin the OpenShell version, read its release notes before every bump, and move the pin when a fix ships. We do not add a second enforcement layer of our own on top of it.