Product integration layer
Three integration shapes, three strengths of enforcement. `vacant run` treats "the process ends" as the delivery point; the sandbox wall gives bwrap separate namespaces; the exit separates release/publish capabilities. An agent can delete its own hooks, so hooks reinforce — they are not a root of trust.
#Three integration shapes
| Shape | Enforcement | Description |
|---|---|---|
| Library / MCP tool | Voluntary | The agent registers Vacant's MCP server in its own configuration and can call tools such as delegate. If the agent doesn't call them, Vacant has no way to step in. |
| Controller | Only for child processes it launches itself | Delegate first, check acceptance, then start the downstream agent. The guarantee only covers processes launched through this controller; the same OS user can bypass it and run the agent directly. |
| Harness that owns the loop | Fully enforced | Generation, acceptance and shipping are all controlled by it. The gain experiments' runner is of this kind. |
The controller's source-code comment states this boundary: the guarantee only covers child processes launched through this controller.
#vacant run: the end of the process as the delivery point
Added on 2026-09-18. It rests on one observation:
If all you want is to stop a delivery, the trigger point is not in the network protocol but at the moment the agent process ends.
This signal is completely reliable, needs no protocol knowledge, costs no tokens, and holds across all frameworks.
#Flow
- Start the local proxy server and set the agent's base-URL environment variables from a list; remove the real upstream address and key from the agent's environment, keeping them only in the proxy server process.
- Record the workspace's tree hash.
- Start the agent and wait for it to end; once it ends, terminate the whole process group, so that no grandchild process writes after the freeze.
- Run visible acceptance on the frozen workspace snapshot and measure the tree hash again; if they are not equal, mark it as an infrastructure failure.
- Sign every attempt and every cell's verdict, and reflect the verdict in the exit code.
| Exit code | Meaning |
|---|---|
0 | Delivered |
20 | Refused delivery |
22 | Infrastructure failure (tree hash mismatch) |
#Two hard rules
#The proxy server records and does not inject
The raw bytes of every request and response are written to disk verbatim, and the request bytes of the on and off arms are identical bit for bit.
The project deliberately injects no message into the conversation, because injecting is the same as forging what the model or the user said, which would damage the foundation the argument stands on: "the record is faithful."
#The sandbox wall, hooks and the exit
#The sandbox wall
bwrap builds separate network and mount namespaces. The only exit is a path-based Unix socket on the host, guarded by the resident proxy server, and every non-model path is refused.
Measured: bwrap blocks everything except the gate; negative controls 7/7.
#Hooks
The framework hooks of all five agents can intercept shell commands.
#The exit: capability separation
A "refuse" verdict is not the same as "impossible to publish." The exit problem is handled through capability separation:
- The
releasemodule mints a release credential only on a pass (its structure is taken from SLSA's verification summary attestation). - The
publishmodule is the only component with the ability to write outward. It verifies the credential's signature, the artifact hash, the verdict, the validity period and the scope of coverage. publishdoes not read the exit code, and deliberately has no force-publish option.
#The audit that made us change our wording
The ABPI audit of 2026-09-20 (391 cells):
| Check | Result |
|---|---|
| Any gaps in the server-side conversation | None; all 2,755 rounds match |
| Receipt chain | 195 / 195 verify |
| Receipt level | All C-level (no sandbox, no hooks) |
| Does "stopped at the exit" hold? | It does not |
This finding led directly to the rewrite of the five-level vocabulary.
#Tests on five agents
| Agent | Version | Result |
|---|---|---|
| pi | 0.85.1 | All 20 cells meet the criteria |
| OpenCode | 1.18.31 | Same |
| Claude Code | 2.1.278 | Same |
| Codex | 0.147.0 | Same |
| Hermes | 0.19.0 | Same |
In total, 20 receipt chains / 40 entries. But the three vendors do not judge the same task the same way — the public task-bank gate (10 tasks × 3 assistants × two batches) found "the three assistants agree on only 4/10 tasks."
#vacant on and agentlane
#vacant on
Lets the user type vacant in a terminal, pick from a menu the command-line agents that actually exist on the machine, and launch them under mediation. It writes the base URL into a temporary configuration directory "that belongs to this one run," and does not touch the user's persistent configuration files.
The menu marks how far each agent's channel has been verified, for example "channel verified" or "channel not measured; check requests_seen after the run."
#agentlane
A measurement tool for running vacant on over long periods. A cell passes only when three independent sources agree:
requests_seen ≥ 1- The proxy server's index line count ==
requests_seen - The agent's exit code has a value
Every round runs a negative control (upstream pointed at a closed port). In a round where the negative control doesn't pass, the positive control doesn't count either.
Whether the delivery was accepted is deliberately not a criterion, to separate the channel from model capability.
The very first smoke test caught a bug: OpenCode ignores the specified working directory and writes its delivery somewhere else, so mediation passed everywhere but every cell was refused delivery. In addition, OPENCODE_CONFIG_CONTENT wipes the user's MCP settings.
#The digital-twin exhibit
An exhibit experiment with 54 cells and 630 real model calls gives a direct comparison of "whether the interface provides the information":
| Condition | Accepted |
|---|---|
| The interface does not provide the necessary information | 0 / 27 |
| The interface provides the necessary information | 24 / 27 |
At the same time: the retry loop rescued 0 / 30. There were also 82 times when the agent declared success but the visible check failed, plus 8 timeouts that were killed.
#Next
- The full explanation of the five-level vocabulary: Receipts
- What this project does not claim: Limits and non-guarantees

