Give an agent exactly this much, and a record of all of it.
Core runs each agent in a cell, with its own namespaces, a Landlock ruleset, a seccomp filter and a cgroup, built by a worker that drops every privilege before the agent starts. What the agent may touch is a set of capabilities handed down by whoever started it, and a cell can only ever hand down less. Everything that crosses the boundary goes into a signed ledger.
// build.zon: what this cell may do, and no more
.{
.paths = .{ .{ .path = "src", .rights = .rw },
.{ .path = "/usr", .rights = .ro } },
.exec = .{ "/usr/bin/make", "/usr/bin/zig" },
.net = .{}, // no route out
.model = .{ .role = "coder", .tokens = 200_000 },
.budget = .{ .cpu = 4, .memory = "4GiB", .wall = "20m", .pids = 256 },
.spawn = .{ .depth = 1, .count = 4 }, // sub-cells inherit a subset
}Five mechanisms
A sandbox the kernel enforces
User, mount, pid, net, ipc and uts namespaces; a read-only view of the host; a private writable layer; Landlock on paths; seccomp on system calls; cgroup v2 on resources. The worker holds three file capabilities and drops them before exec. Thirty-three catalogued escape techniques are each a test that must fail inside.
Rights that narrow
Eight types, path, exec, net, secret, model, budget, spawn and ledger. A handle is bound to its cell and cannot be replayed. Derivation is a subset check per type; revocation follows the derivation tree. A widening is refused and recorded.
Written, synced, acknowledged
One hash chain per cell, sealed in segments with Ed25519 and ML-DSA-65, each seal recorded in a host-wide stream. Execs and denied calls are captured through seccomp notification. Exportable as JSON lines. Replay a ledger against a new model and diff the result.
Capture, rollback, fork, merge
Captures freeze the cell, stage changed files, thaw, hash. Rollback keeps the cell identity; fork starts a sibling from the same point. zc merge applies an approved diff hash to the requester's tree, only under write capabilities, and ledgers the approval.
No route without a right
A cell without a net capability has no route out. With one, nftables in the cell's namespace redirects allowed connections to a relay that resolves names, checks the TLS server name, opens the connection itself and records denials. Secrets are inserted by the relay; the cell never sees them.
A gateway on loopback
Roles map to local or remote models per host. Request fields are allow-listed; provider keys never enter a cell. Tokens and money are reserved before a call and settled after. Local servers run only if their binary hash matches.
A session, end to end
- DeclareWrite a
cell.zon. The validator refuses a semantic fault with the line number before anything runs. - Run
zc run --profile cell.zon -- <command>. The daemon, which holds no capability itself, asks the worker to build the cell and places it under its cgroup and budgets. - WorkThe agent sees its view and nothing else. Sub-cells it spawns inherit a subset. Every boundary crossing becomes a ledger entry.
- StopExit, or a budget reached. The ledger names the cause. The cell's writes sit in its overlay.
- Read, then merge
zc diff, thenzc mergewith the hash you read, orzc drop. Nothing reaches your tree unseen. - ReplayAny ledger replays against a new model or policy; the diff is your regression test for agents.
Compared
Sandboxes are necessary and several good ones exist. Core assumes the sandbox and adds the record, the narrowing and the way back.
| Zethro Core | NVIDIA OpenShell | Nono | OpenSandbox | systemd-nspawn | Firejail | |
|---|---|---|---|---|---|---|
| Kernel-enforced sandbox | yes | yes | yes | container | yes | yes |
| Per-call scoped rights | capabilities | policy | per tool call | no | no | no |
| Delegation that only narrows | yes, per type | no | no | no | no | no |
| Signed, replayable ledger | yes | logs | no | no | no | no |
| Snapshots, rollback, fork | yes | no | no | no | no | no |
| Merge after diff | yes | no | no | no | no | no |
| Budgets as rights | cpu, mem, wall, net, tokens, money | no | no | no | cgroup only | no |
| Secrets kept out of the sandbox | relay | no | proxy | no | no | no |
| Installed as | one Debian package | vendor stack | binary | Docker, Kubernetes | Debian package | Debian package |
From each project's public documentation at the time of writing. Corrections welcome through the repository.
Engineering
- Language
- Zig 0.17; C libraries only from Debian (libseccomp, libnftables, libcurl, libssl)
- Executables
zcored(no capability),zcore-worker(three file capabilities, dropped),zc,zmodel,libzcore.so.1with a C header- Protocol
- length-prefixed JSON frames, unknown fields rejected, daemon version M serves M and M-1
- Kernel
- Linux 6.12 or later, with Landlock, cgroup v2, user namespaces, seccomp notification and idmapped mounts
- Verification
- unit tests, an escape suite in detect and held modes, a container and VM matrix, a second-builder security review per increment
- Licence
- open source
Core is in active development toward 1.0. Chapters 01 to 11 of the specification are complete; the daemon, worker, capability model and per-cell socket are built and verified. Follow progress in the repository.