getkern/kern: a rootless container runtime that documents its own wrong benchmark
a fast, rootless sandbox and virtual resource runtime. Run any workload in a real container, including an agent's tool-call or AI-generated code.
At a glance
- What is it?
- A daemonless container runtime and sandbox written in Rust, where the same binary is both the container engine and the box an agent's generated code runs in. The build manifest contains a comment recording that a speed conclusion was backwards, and the workspace version is left at 0.0.0 while releases are tagged v0.25.1.
- Who is it for?
- Adopt it if you start containers per tool call and the daemon's idle footprint is your actual cost, and if you can live inside the unprivileged user namespace model. Do not treat it as a hostile-code boundary, because the project's own scope statement rules that case out.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 3 days ago.
- What is it written in?
- Mainly Rust, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 2, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The build manifest records a speed conclusion that was backwards
The release profile in Cargo.toml carries a comment block that documents a reversal, in unusually blunt terms. One line reads, in capitals, that the phrase "VERIFIED A HAIR FASTER" is what the comment used to say, and that it was backwards.
The measurements are given. Opt-level 3 on the project's own crates produced five runs with point estimates from plus 7.6 to minus 38.3 microseconds, and two of those intervals span zero, which means the result did not separate from noise. A second configuration, opt-level 3 with a standard library built without size optimization, gave six runs from minus 16 to minus 50 microseconds. The resolution method is equally specific: eleven paired runs of 120 to 400 samples each, against an instrument shown in the same runs, to separate an injected 50 microsecond difference inside a 2.6 millisecond box start.
The two comments above that reversal disagree with each other. One says opt-level is kept at 3 on purpose because startup speed is the headline. The next says a size-optimised build at "z" shrinks the binary noticeably with no measurable latency cost, on the grounds that cold start is syscall-bound in unshare, mount and exec rather than CPU-bound.
Leaving a wrong claim and its correction in the manifest is unusual, and it is the most honest thing in the repository.
The workspace version is 0.0.0 while releases are tagged v0.25.1
The manifest declares its workspace version as 0.0.0, which is a placeholder rather than a shipped number. Real versioning happens at release time. The tags tell the story: v0.20.0 on 2026-09-22, v0.25.0 two days later on 2026-09-24, and v0.25.1 on 2026-09-29.
That jump from 0.20 to 0.25 inside two days is worth noticing, because the changelog is the only account of what those intermediate minors contained. The last push landed on 2026-09-29, shortly after the v0.25.1 tag, and the repository is not archived.
The practical effect of the placeholder is on anyone building from source rather than installing a release: a locally built binary has no meaningful version string to report, and the workspace layout is a five-crate split with kern-cli, kern-common, kern-compose, kern-oci and kern-isolation as members.
Two directories are deliberately excluded from the workspace. The fuzz harness is its own nightly and sanitizer workspace and is never built by a normal cargo build. The Windows entry is a shim crate, windows/kern-win, that targets WSL2 and is cross-compiled by the release pipeline on its own, so that an ordinary Linux build or clippy or test run never touches a foreign target.
Three box kinds, and what each one is for
Kern calls a container a box, and the quickstart names three kinds of them.
kern box dev --image alpine -it -- shThat is an interactive shell inside a real OCI image.
kern box svc --image nginx:alpine -d -p 8080:80That is a service, detached, publishing port 8080 on the host against port 80 in the container.
kern box job --image python:3.12-slim --security-profile untrusted -- python3 -c "print('hi')"That is the third kind, a job, and it is the one aimed at running code a model produced. The untrusted profile is the important flag: it is the seccomp allowlist combined with capability dropping and a read-only root, all folded into one switch, which the documentation describes as `--cap-drop ALL` and `--read-only` in one flag. An always-on allowlist keeps kern's 35 escape syscalls denied.
The rest of the surface is the set of commands people expect from a runtime: `ps`, `logs`, `exec`, `stats`, `inspect`, `top` and `doctor`. That last one checks the host and says what to fix, which matters because Ubuntu 23.10 and newer need one root step performed before anything else works.
The examples directory holds 94 runnable scripts, one per behavior, spread across subdirectories for agents, basics, builds, CI, compose, edge cases, hardening, precompiled images, resources and security.
The untrusted profile sits next to a scope statement that rules it out
There is a tension in the documentation that a reader should see plainly. The quickstart offers a job kind explicitly labeled untrusted code, with a strict profile, as the pattern for running model output. Elsewhere, the section on what kern is not states that it is for code you chose to run, not for hostile code.
The mechanism explains why. The boundary is the Linux kernel, built on an unprivileged user namespace, and a kernel privilege-escalation bug is therefore an escape by construction. Kern is not a hypervisor and does not sit below the kernel.
The project's own honesty about this is worth crediting. Where a boundary is cooperative rather than kernel-enforced, SECURITY.md says so and names the bypass. The threat model and the CVE posture documents are separate files, and the posture document runs 25 published container-runtime escapes against this tree one at a time, while the pentest directory asserts the boundaries against the kernel directly.
So the enforcement stack is six namespaces, a pivot_root, dangerous capabilities dropped before exec, the seccomp allowlist, cgroup v2 limits and a deny-by-default /dev. What it does not claim is that this survives a kernel bug.
The MCP configuration calls uvx, which no install step mentions
Kern exposes an MCP server for Claude Code, Cursor, Claude Desktop and LM Studio, through the Kern Sandbox package rather than through the runtime binary. The same configuration block goes into `claude_desktop_config.json`, into an `mcp.json` for Cursor or LM Studio, or into a `.mcp.json` at the project root for Claude Code.
{
"mcpServers": {
"kern": { "command": "uvx", "args": ["--from", "kern-sandbox", "kern-mcp"] }
}
}The command being invoked is `uvx`, which means the block silently depends on a separate Python toolchain being installed and on PATH. Nothing in the install section, which covers the curl line for Linux, the PowerShell line for Windows and the Colima route for macOS, mentions installing it. A user who follows the install instructions exactly and pastes the documented MCP block gets a server that will not start.
The same gap appears in the agent-facing binding. Kern Sandbox is published to PyPI and npm under the name kern-sandbox, and on Linux the pip install brings kern along with it, while on other platforms the runtime comes from the install line above. The Python entry point is a single call:
import kern_sandbox as kern
r = kern.run_code("print(sum(range(100)))")
print(r.stdout, r.fault) # 4950 NoneEach call gets its own container, for one call or for a whole session, and a timeout or an out-of-memory condition returns as a typed fault rather than an exception.
On macOS the install runs inside a Colima virtual machine
The macOS path is a virtual machine, and the documentation does not pretend otherwise.
brew install colima
colima start
colima sshThen, inside that VM, the same Linux install line runs. Kern Sandbox is installed into the VM as well, together with the code that calls it, so a Python agent on macOS reaches the runtime through a VM boundary.
The headline claims are about the runtime rather than the host: one static binary, no daemon, nothing to start, zero resident memory at rest, and libc as its only Rust dependency. Those hold regardless of what backs the kernel underneath.
The Windows path has the same shape by a different mechanism. The Windows entry is not a native runtime at all; it is a shim crate that targets WSL2, cross-compiled separately by the release pipeline so the normal Linux build never touches it.
So of the three platforms, Linux is the only one where the runtime is directly on the host. That is not a criticism, since an unprivileged user namespace and cgroup v2 both come from the kernel, and macOS has neither. It does mean that a claim about footprint or latency on macOS is a claim about Colima as much as about kern.
80x against docker run, 3.6x against rootless runc
The performance table quotes three multipliers, and they are not equally conservative.
Against `docker run --rm`, one isolated `/bin/true` is reported at 80x faster and 200 containers at once at 130x faster. Those numbers include the daemon's cold path, since the comparison target is a command that has to start a daemon and a container runtime. Against rootless `runc`, the more structurally similar baseline, the same single container is reported at 3.6x faster.
The footprint table is the cleaner claim. Kern has no daemon, Docker needs `dockerd` plus `containerd`, and Podman has neither. Resident memory with nothing running is given as 0 for kern, 154 to 160 MB for Docker and 0 for Podman. Rootless is listed as always on for kern, opt-in for Docker and on for Podman.
The footnote is worth respecting: same machine, same workload, same day, rounded down. Every number is a floor rather than a midpoint, and the method plus every runtime version is in BENCHMARKS.md, with a benchmark script in the examples directory. Published this way, the table cannot be accused of rounding in its own favor.
kern run applies container limits to a process with no container
One feature sits outside the container story entirely. Beyond boxing workloads, `kern run` applies the same capability and resource limits to a plain process on the host, documented separately in the resources guide.
That is the virtual resource half of the project. The same cgroup v2 limits and capability dropping that constrain a box can be applied to something running directly in your session, which is the useful case when you want to bound a build script or a tool invocation without paying for a container start at all.
The stack side follows a parallel design. An existing `docker-compose.yml` is accepted unchanged, and there is an equivalent TOML format where keys are spelled like the box flags:
[box.cache]
image = "redis:7-alpine"
[box.web]
image = "nginx:alpine"
ports = ["8080:80"]
depends_on = ["cache"]kern compose stack.toml up # start it (or point it at your compose.yaml)
kern compose stack.toml ps # what is running, and what each service publishes
kern compose stack.toml port web 80 # the host address serving a portEach service gets its own network namespace and the services reach one another by name. The scope is stated as the local development loop rather than a production orchestrator, which matches a runtime optimized for starting many short-lived containers quickly.
Editorial conclusion
Adopt it if you start containers per tool call and the daemon's idle footprint is your actual cost, and if you can live inside the unprivileged user namespace model. Do not treat it as a hostile-code boundary, because the project's own scope statement rules that case out. Before building on it, read the threat model and CVE posture documents, verify your host passes kern doctor, and note that Ubuntu 23.10 and newer need a root step before anything else works.
Frequently asked questions
What is getkern/kern?
A rootless container runtime and sandbox delivered as one static binary with no daemon, where libc is the only Rust dependency and a container is called a box. It supports OCI pull, build, commit, push, save and load, plus the usual ps, logs, exec, stats, inspect, top and doctor commands.
What does the untrusted security profile do in kern?
It folds the seccomp allowlist, capability dropping and a read-only root into one flag, equivalent to --cap-drop ALL with --read-only. The always-on allowlist keeps kern's 35 escape syscalls denied.
How does kern compare to Docker and Podman?
The published table reports 80x faster than docker run --rm for one isolated container and 130x faster for 200 at once, against 3.6x faster than rootless runc. Resident memory with nothing running is listed as 0 for kern and Podman against 154 to 160 MB for Docker, with the figures rounded down.
Does kern run on macOS and Windows?
On macOS through Colima, so you install Colima, start it, ssh in and run the Linux installer inside the VM, along with pip install kern-sandbox. The Windows entry is a shim crate named windows/kern-win targeting WSL2, cross-compiled separately by release CI.
How do I run an agent's generated code with kern?
Install the Kern Sandbox binding with pip install kern-sandbox on Linux or npm install kern-sandbox for Node, then call kern.run_code() from Python. The code runs in a container of its own, and a timeout or out-of-memory condition returns as a typed fault on the result rather than raising.
Is kern a boundary for hostile code?
The project's own scope statement says it is for code you chose to run, not for hostile code, because the boundary is the Linux kernel on an unprivileged user namespace, so a kernel privilege-escalation bug is an escape. Where a boundary is cooperative rather than kernel-enforced, SECURITY.md names the bypass.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/getkern-kern)