Fenzi

Team

When something is down

Enforcement happens on the machine, in the sandbox, from the last policy it accepted. Nothing in our cloud is in that path. When a piece is missing, Fenzi either keeps the last good state or refuses to start. An enrolled machine never falls back to something wider on its own. A developer who signs out returns their machine to Free, and the console sees that machine stop reporting.

Fails closedFree has no dependency on us

What happens when

If this is unavailableRunning sandboxesNew sandboxes
Our control planeKeep enforcing the policy they loaded.Start from the last signed policy the machine verified. run and status say the control plane is unreachable and name the revision in use.
Our control plane, on a machine that never received a policyNone are running.Refused. An enrolled machine does not fall back to the Free default.
A valid signatureUnaffected.A bundle that fails the signature check, or is older than the one held, is ignored and reported. The machine keeps the revision it had.
The policy proverUnaffected.Refused. run exits with code 2 unless the result is within_boundary.
The sandbox runtimeWhatever the runtime does. Fenzi does not enforce anything itself.Refused. run exits with code 3 and doctor says what is missing.
The network, entirelyKeep denying what they denied before. The model call fails too, so the agent stops being useful.Start, if the image is already built and the policy is cached.

A revision the sandbox cannot load

If a running sandbox receives a policy revision it cannot load, the runtime's own setting decides what happens:

  • fail_closed, the default, blocks network traffic until a valid revision loads.
  • retain_last_valid keeps enforcing the last revision that loaded.

Both keep the sandbox inside its rules. fenzi doctor reports which one the gateway uses. Fenzi does not change it.

Decisions and requests

  • Decision records wait on the machine and upload when the control plane answers. If the local queue fills, the forwarder says how many were dropped.
  • Requests for more access stay pending. The blocked call stays blocked. In the console, no approval happens without a reviewer. An answer given on the machine still works, and the console shows it as drift once the machine reports again.
  • A review made in the console before the outage is applied on the forwarder's next pass after it.

A gateway restart

The runtime keeps a limited buffer of recent events and loses it when the gateway restarts. Decisions in that buffer that were not forwarded yet are gone. The forwarder notices, starts reading from the current position, and sends a gap record, so the console shows the span it is missing. On Free, the saved log for that sandbox holds what arrived before the restart.

On Free

On Free, nothing in enforcement depends on us. It needs the runtime, the prover, and an image builder on the machine, and nothing else. The only call to fenzi.dev is the update check, at most once a day, which you can turn off; see The update check.

Test it yourself

  1. Start an agent with fenzi run claude on an enrolled machine.

  2. Block the control plane's address on that machine.

  3. Ask the agent to fetch a host the policy does not list. fenzi log --deny shows the deny.

  4. Run fenzi status. It names the cached revision and says the control plane is unreachable.

  5. Unblock it and run fenzi forward --once. The deny reaches the console.