Kernel, Not Convention
cloister doesn't stop at keeping secrets out of a tool's hands. It confines the whole process — filesystem, network, everything — and the kernel enforces the line, not a policy the process agreed to follow.
Last time the boundary was the credential: a tool gets a call, never a key, so a compromised tool has nothing to hand over. That covers the secret. It doesn’t cover the rest of what a process can touch — the filesystem it can read, the hosts it can reach. cloister confines that too, and the way it does it is the same idea one level down.
The harness gets sandboxed, not just the tool
The most exposed process in this whole picture isn’t a tool cloister calls on your behalf. It’s the coding agent itself — Claude Code, or whatever harness you’re pointing at cloister — reading your repo, running commands, doing exactly the kind of work that makes prompt injection dangerous. cloister-harness confines that process directly, at the kernel: Seatbelt on macOS, Landlock on Linux, via a library called nono.
The policy is specific and it denies by default. $HOME is closed — ~/.ssh, ~/.aws, every dotfile — with the kernel returning EPERM, not a convention the process is trusted to respect. The workdir is read-write, because that’s the actual job. The harness’s own state directory (~/.claude) is open, because it needs to remember what it’s doing. Network is blocked outright except one allowed port: localhost, back to cloister’s own vault proxy. The model credential still never enters the harness’s environment — cloister injects it at that one open seam and receipts every call, the same discipline as the tool-calling story, now wrapping the harness that calls the tools.
A denial that isn’t allowed to be silent
The test suite behind this is worth a look for what it refuses to accept as proof. A row in the confinement table only counts as verified when a real process gets a nonzero exit and the kernel’s own EPERM/EACCES message — empty output doesn’t pass, and neither does ENOENT, because a target that doesn’t exist can’t tell you whether access to it was denied. The decoy secret the tests plant deliberately lives outside the OS temp directory, because nono default-allows temp dirs — a decoy hidden in a directory the sandbox was going to let through anyway would pass every time and prove nothing. Getting a negative test to mean something takes as much care as getting a positive one to.
Four spikes, one runtime
The confinement mechanism didn’t start as one thing. It grew as four separate tools, built to prove different pieces could work at all: one for kernel confinement, one a filesystem policy layer sitting over a shared graph library and served over NFS, one a spike proving a microVM could boot with the right passthrough, one gluing a dev workflow together. Each did its job. None of them was meant to stay separate.
The realization that closed the gap: every one of those tools was a script-shaped wrapper around a library that was already designed to be composed in-process, not shelled out to. The fix wasn’t a fifth tool to orchestrate the other four — it was recognizing there was only ever supposed to be one runtime, built by composing those libraries directly: kernel isolation for the process, a mediated filesystem graph for what the guest can see on disk, a microVM for the strongest form of compute isolation when that’s warranted. Three concerns, one process, no scripts stitching them together after the fact.
One declaration, both planes
The part of this that matters most for trusting any of it: the policy that gets declared and the policy that gets enforced are read from the same source, by construction. A manifest describes confinement in one shared vocabulary. The control plane that assembles a bundle reads it to declare what should happen. The runtime that actually confines a process reads the identical declaration to make it happen — kernel sandboxing for the process, the mediated filesystem graph for disk access — and neither plane holds its own separate copy that could quietly drift from the other’s.
That pairing is checked before it’s trusted, not just before it’s written down. Where a workload’s confinement is committed to a certificate, the runtime hashes the manifest it’s about to enforce, checks that hash against the one sealed into the cert, verifies the cert against a root key, and refuses to confine anything at all if any of those don’t match exactly — the same hash-first instinct as everywhere else in this stack, applied to the question “is this the policy I think it is” before a single syscall runs under it.
The same shape, one layer down
Give a tool a call instead of a key, and a compromised tool has nothing to leak. Confine the whole process at the kernel instead of trusting it to behave, and a compromised process has nowhere to go: the filesystem it can see and the hosts it can reach are facts enforced below it, not intentions it agreed to. Different layer, same move — a boundary is only as real as what enforces it, and “the process was supposed to behave” was never an answer to that.
Open source: github.com/agentic-research/cloister. The confinement model, the harness-sandbox tests, and the host-runtime consolidation are documented in the repo’s docs/.