⚡ The Rust VMM that unlocked forking live Kubernetes clusters in ~100 ms ⭐ Star it if you like it!
5
stars
6
commits
Rust
primary language
Sep 3, 2026
updated
Fork a running Kubernetes cluster in ~100 ms.
Run 50 copies on one 64 GB box.
RL training and agent evals whose environments are Kubernetes -
clusters, charts, in-cluster workloads - need thousands of isolated,
resettable worlds. Not one sandbox, and not a cold kind cluster per
trial. Booting a fresh Kubernetes cluster takes ~30 s and full RAM
per copy. k7d boots it once, then forks the live cluster in
~100 ms; forks share memory until they diverge, so 50 copies cost
dirty pages, not 50 × full guest RAM.
The same engine is also a great fork-first VMM when your unit is a single VM sandbox (including docker-in-VM): blazing-fast warm forks with faithful snapshotting of memory, disk, processes, and networking. For running that at scale - Kubernetes orchestrating your sandboxes, plus a CLI / API / Python SDK for agents - see the sibling project Katakate k7.
100% open‑source (Apache‑2.0). For technical support, write us at: hi@katakate.org
unsafe / arithmetic paths, and
Aeneas→Lean on the tree
budget/eviction model. Not a claim that everything is proven -
details below.You need a Linux amd64 / x86_64 host with KVM (/dev/kvm present) -
same ISA (amd64 is the Debian name; tarballs use x86_64). No arm64
build yet. Rust and Docker are required to build from source. Prebuilt
release tarballs are produced by make release
(k7d-v*-x86_64-linux.tar.gz + install.sh).
git clone https://github.com/Katakate/k7d && cd k7d
make release # daemon, shim, guest kernel, rootfs → dist/
sudo RUST_LOG=info ./dist/k7d & # owns VMs + /run/k7d/k7d.sock
cd examples/cluster-tree-search
python3 run_demo.py --mode busybox --branches 4
# density claim: python3 run_demo.py --mode busybox --branches 50
The demo forks a live 3-VM cluster, scores branches, keeps the winner,
prunes the losers, and prints the fork wall-clock. To put real
Kubernetes pods inside those VMs (runtimeClassName: k7), see
HACKING.md. Full docs (API reference, installers) will
ship separately - this README is the product pitch + getting started.
Second wave: one copy is about to get wrecked on purpose. 21 / 24 VMs.
The whole run, 7×. Delete fails. A lab is sacrificed. The door holds.
Someone planted a miner in a Deployment that looks like a helper.
The real app (k7-victim) is fine. Kimi K3 does not touch
production first - it clones the cluster three ways and tries delete,
scale-to-zero, and “just watch.” The miner comes back every time.
So it forks again from the copy that already knows delete is a lie.
One of those labs restarts k3s to catch the respawner and is left
broken on purpose. No rollback. Another hangs an admission lock on
the name node-agent; recreate comes back denied. Only that pair of
moves is replayed on the source. Soak: still gone. Victim 2/2.
Tetragon clean.
The story ·
Video ·
JSONL.
Dashboard: examples/k7view/.
If you already have Kubernetes tasks or scenarios (a Helm chart, a set of YAML manifests, an eval harness that talks to a kube-apiserver), the shape is:
fork_batch(N) → run your N policies against the N copies → score
→ protect the winners, prune the losers → let the daemon
auto_evict under your RAM/disk budget.rollback to an
earlier node when you don't.GRPO (and most group-relative methods) compare rewards within a group. If member A starts from a colder cache, a different etcd revision, or a half-ready Deployment than member B, the reward gap is noise, not signal. A k7d fork is a copy of the live machine - same memory, same disk, same in-cluster TLS sessions, same kube-apiserver state. Every member of the group begins from a byte-identical world, then diverges only because of what your policy did.
That is the difference between "we reset the env" and "we cloned the universe."
Your training loop owns rewards and policy. k7d owns environments and
budgets. The agent talks JSON-lines over a Unix socket
(/run/k7d/k7d.sock). The verbs you actually need:
| You want to… | Call |
|---|---|
| Start from a warm VM or live cluster | tree_create / tree_create_cluster / tree_adopt_cluster |
| Open N parallel rollouts from one checkpoint | tree_fork_batch |
| Try again from an earlier node without destroying it | tree_rollback |
| Pin a winner so budget pressure can't kill it | tree_protect |
| Drop a losing subtree | tree_prune |
| Enforce RAM/disk caps now | tree_auto_evict |
A thin Python client that covers exactly this loop lives in
examples/cluster-tree-search/. Treat
it as the template for wiring your GRPO trainer - not as a finished
SDK. To watch a live tree (git-graph, fork latency, protect/evict
notes, per-branch traces) run examples/k7view/
on the node - k7d stays machine-first; k7d-view is the observer. The
full API reference will live in the docs site.
You do not need to be a VMM engineer to use k7d. You do need to know why a 100 ms cluster fork is even possible, because that is the product.
Memory is shared until someone writes. Guest RAM lives in one file. A fork pauses the source for a moment, notes which pages changed since the last checkpoint, maps the child's memory as a copy-on-write view of the parent's, and copies only those dirty pages. Everything else is shared. That is why 50 forks of a cluster fit in 64 GB: you pay for divergence, not for the base.
The cluster does not reboot because the network lies consistently. Each cluster lives on its own private Linux bridge. A fork gets a new bridge with the same guest IPs and MAC addresses as the source. From inside the guest, nothing moved - same addresses, same ARP cache, same TLS certs, same established TCP - so kubelet, the CNI, and the control plane keep running. Separate bridges mean forks cannot see each other. Without this, every fork would force a kubelet restart and a ~1-2 s agent restart per node, and the 100 ms claim would be impossible.
Forks live in a tree the daemon manages under budget:
base cluster ──► fork A ──► fork A1 (protected: winner)
├─► fork B (pruned: low reward)
└─► fork C ──► rollback ─► fork C'
These are the kinds of bugs that silently break "byte-identical."
CHALLENGES.md has all 56; these three are the
headline ones:
CLOCK_REALTIME stuck, and Kubernetes quietly parks.
Fix: re-arm the timer (and reset the paravirtual clock) on every
restore. (CHALLENGES.md #40)On one bare-metal box (~€40/month bare-metal: Ryzen 5 3600, 6 cores, 64 GiB, NVMe):
| Scale check | Measured | Enforced budget |
|---|---|---|
| Warm single-VM fork (<25% dirty) | ~5 ms | 50 ms |
| Warm-fork a live 3-node k3s cluster (under API churn) | ~105 ms | 1 s |
| 50 × 3-VM cluster-tree forks (shared pause) | ~4.1 s (~82 ms/cluster) | 20 s |
| VM boot → guest agent ready (cold) | ~163 ms | 250 ms |
Every row is an integration-test assertion
(LATENCY_BUDGETS.md). Full methodology:
the benchmark write-up.
Two layers - most RL users only care about the first.
This is the k3s that lives inside the VMs you fork. The fork engine
is N-node (tree_create_cluster(vm_count) / adopt any live set) -
there is no hard-coded 3. The CI fixture that proves the headline
numbers is a 3-node control plane with flannel + kube-proxy and a real
in-cluster Deployment. That default profile keeps stock k3s add-ons
off so the lean path stays lean; each add-on below is an opt-in
profile on the same switchboard, with its own proving test. Status
below mixes “API can do it” with “fixture exercises it.”
| Feature | Status | Notes |
|---|---|---|
| k3s control plane (server + agents) | ✅ Today | Fixture proves 3 Ready nodes; TLS / node IPs survive fork |
| N-node clusters (5, 20, …) | ✅ Today | Same fork path for any vm_count; limited by host RAM, not by the API. At ~3.2 GiB/node, a 20-node base alone is ~64 GiB - shrink guest memory (or use a bigger box) and it forks like the 3-node case |
Flannel (host-gw) | ✅ Today | Shared L2 between member VMs |
| kube-proxy (ClusterIP by IP) | ✅ Today | |
| Deployments / ReplicaSets / Pods | ✅ Today | e.g. inner-load Ready on source and fork |
| ConfigMaps / Secrets (as in-cluster objects) | ✅ Today | Exercised under churn before fork |
| overlayfs snapshotter (guest containerd) | ✅ Today | |
| CoreDNS | ✅ Today | Fixture proves DNS on all members across a warm fork - test_inner_k3s_coredns_dns_fork |
| Traefik / Ingress | ✅ Today | HTTP through an Ingress on source and fork - test_inner_k3s_ingress_fork |
| ServiceLB | ✅ Today | Traefik Service reports guest IPs as LB ingress; same proving test as Ingress - test_inner_k3s_ingress_fork |
| metrics-server | ✅ Today | kubectl top / metrics.k8s.io Available on all three nodes across a warm fork - test_inner_k3s_metrics_server_fork |
local-path / in-cluster PVC provisioning | ✅ Today | Same bytes on source and fork, then independent divergence - test_inner_k3s_local_path_pvc_fork |
| NetworkPolicy | ✅ Today | Default-deny + allow enforced on source and fork - test_inner_k3s_network_policy_fork. Guest kernel needs ipset + xt_set, xt NFLOG/limit, and nft_log/nft_limit (CHALLENGES.md #93) |
| HPA | ✅ Today | CPU-metrics scale-up on source and fork; observed utilization diverges after a fork-only load change - test_inner_k3s_hpa_scale_fork |
| Embedded etcd datastore | ✅ Today | Single-member --cluster-init WAL and writes survive a warm fork; per-bridge writes stay isolated - test_inner_k3s_etcd_datastore_fork |
| ArgoCD core GitOps | ✅ Today | In-cluster git://; Application Synced/Healthy + reconciledAt on both bridges; fork-only commit syncs only on the fork - test_inner_k3s_argocd_gitops_fork. application-controller shards and does not hold a coordination Lease (CHALLENGES.md #96) |
| Cilium (eBPF CNI / policies) | 🔜 Later | Not validated inside the guest; outer host may run Cilium |
| Longhorn / CSI drivers (iSCSI, NFS, …) | 🔜 Later | Guest kernel is minimal; no CSI path yet |
Nested hostNetwork pods | ❌ Not today | Known failure mode in the guest |
Need CoreDNS + Ingress on one cluster? Flip the profile flags - the switchboard is configuration, not a redesign. Same for a larger CI fixture: wiring 20 nodes is configuration + RAM, not a new fork feature.
This is the outer layer: kubectl on the host schedules pods into k7d
microVMs via runtimeClassName: k7. Relevant if you also want
single-VM sandboxes, not only whole-cluster forks.
| Feature | Status | Notes |
|---|---|---|
runtimeClassName: k7 (CRI / containerd shim) | ✅ Today | |
kubectl logs / exec / exec -it (PTY) | ✅ Today | Incl. resize, Ctrl-C, detach |
| Pod IP, Services, DNS, egress | ✅ Today | Host CNI dataplane |
| ConfigMap / Secret / projected / downwardAPI / emptyDir | ✅ Today | |
| hostPath, local-path PVC, k7d RWO disk volumes | ✅ Today | |
| Memory / CPU limits; multi-container / sidecars | ✅ Today | |
| Warm VM + whole-cluster fork / snapshot tree | ✅ Today | The point of the project |
Init containers; natural exit / restartPolicy | ✅ Today | Multi-container pods |
Multi-vCPU guests (cpu: "2"+) | ✅ Today | From pod CPU limits; fork/snapshot parity |
hostNetwork, NetworkPolicy, IPv6, arbitrary CSI / RWX | 🔜 Later | |
| Cross-node fork | 🔮 Later | Host-local trees today |
| Firecracker | Kata | CubeSandbox / E2B-style | k7d | |
|---|---|---|---|---|
| Warm fork of a running VM | snapshot → restore | no | snapshot + N restores (~220 ms) | live copy-on-write fork (~5 ms) |
| Snapshot tree (fork / rollback / protect / budget) | no | no | SDK around sandboxes | yes - daemon API |
| Forks a whole k8s cluster | no | no | no | yes (~105 ms) |
| Runs as a Kubernetes RuntimeClass | via FC-containerd | yes | no | yes (runtimeClassName: k7) |
| Formal methods | audit/fuzz culture | - | - | Kani + Aeneas on selected paths (memory math, tree budgets) |
They fork a sandbox. k7d forks a VM or an entire cluster. Deliberately not E2B-API compatible - different job.
Selected critical pieces are machine-checked - not the whole runtime:
| Tool | What it covers |
|---|---|
| Kani | Bounded proofs over selected unsafe / address-arithmetic harnesses |
| Aeneas → Lean | Functional correctness of the snapshot-tree budget / LRU eviction model |
make kani # selected unsafe / arithmetic harnesses
make verif-gen verif-build # regenerate Lean model + prove it
runtimeClassName: k7install.sh (make release)/etc/k7d/config.toml)docs/blog/2026-08-07-k7d-cluster-fork-benchmark.md - hardware, exact commands, methodologyCHALLENGES.md - 56 non-trivial bugs with root causes and time lost (the three above are the headline; start anywhere)todo-ideas.md - maturity-fixture backlog (write-during-fork, dirty floods, Kafka/KRaft, …) - not a specHACKING.md - build, test, and the RuntimeClass install stepsApache-2.0 - see LICENSE.
6 commits
Rust
90.4%
Lean
6.9%
Shell
2.3%
⚡ The Rust VMM that unlocked forking live Kubernetes clusters in ~100 ms ⭐ Star it if you like it!
5
stars
6
commits
Rust
primary language
Sep 3, 2026
updated
Fork a running Kubernetes cluster in ~100 ms.
Run 50 copies on one 64 GB box.
RL training and agent evals whose environments are Kubernetes -
clusters, charts, in-cluster workloads - need thousands of isolated,
resettable worlds. Not one sandbox, and not a cold kind cluster per
trial. Booting a fresh Kubernetes cluster takes ~30 s and full RAM
per copy. k7d boots it once, then forks the live cluster in
~100 ms; forks share memory until they diverge, so 50 copies cost
dirty pages, not 50 × full guest RAM.
The same engine is also a great fork-first VMM when your unit is a single VM sandbox (including docker-in-VM): blazing-fast warm forks with faithful snapshotting of memory, disk, processes, and networking. For running that at scale - Kubernetes orchestrating your sandboxes, plus a CLI / API / Python SDK for agents - see the sibling project Katakate k7.
100% open‑source (Apache‑2.0). For technical support, write us at: hi@katakate.org
unsafe / arithmetic paths, and
Aeneas→Lean on the tree
budget/eviction model. Not a claim that everything is proven -
details below.You need a Linux amd64 / x86_64 host with KVM (/dev/kvm present) -
same ISA (amd64 is the Debian name; tarballs use x86_64). No arm64
build yet. Rust and Docker are required to build from source. Prebuilt
release tarballs are produced by make release
(k7d-v*-x86_64-linux.tar.gz + install.sh).
git clone https://github.com/Katakate/k7d && cd k7d
make release # daemon, shim, guest kernel, rootfs → dist/
sudo RUST_LOG=info ./dist/k7d & # owns VMs + /run/k7d/k7d.sock
cd examples/cluster-tree-search
python3 run_demo.py --mode busybox --branches 4
# density claim: python3 run_demo.py --mode busybox --branches 50
The demo forks a live 3-VM cluster, scores branches, keeps the winner,
prunes the losers, and prints the fork wall-clock. To put real
Kubernetes pods inside those VMs (runtimeClassName: k7), see
HACKING.md. Full docs (API reference, installers) will
ship separately - this README is the product pitch + getting started.
Second wave: one copy is about to get wrecked on purpose. 21 / 24 VMs.
The whole run, 7×. Delete fails. A lab is sacrificed. The door holds.
Someone planted a miner in a Deployment that looks like a helper.
The real app (k7-victim) is fine. Kimi K3 does not touch
production first - it clones the cluster three ways and tries delete,
scale-to-zero, and “just watch.” The miner comes back every time.
So it forks again from the copy that already knows delete is a lie.
One of those labs restarts k3s to catch the respawner and is left
broken on purpose. No rollback. Another hangs an admission lock on
the name node-agent; recreate comes back denied. Only that pair of
moves is replayed on the source. Soak: still gone. Victim 2/2.
Tetragon clean.
The story ·
Video ·
JSONL.
Dashboard: examples/k7view/.
If you already have Kubernetes tasks or scenarios (a Helm chart, a set of YAML manifests, an eval harness that talks to a kube-apiserver), the shape is:
fork_batch(N) → run your N policies against the N copies → score
→ protect the winners, prune the losers → let the daemon
auto_evict under your RAM/disk budget.rollback to an
earlier node when you don't.GRPO (and most group-relative methods) compare rewards within a group. If member A starts from a colder cache, a different etcd revision, or a half-ready Deployment than member B, the reward gap is noise, not signal. A k7d fork is a copy of the live machine - same memory, same disk, same in-cluster TLS sessions, same kube-apiserver state. Every member of the group begins from a byte-identical world, then diverges only because of what your policy did.
That is the difference between "we reset the env" and "we cloned the universe."
Your training loop owns rewards and policy. k7d owns environments and
budgets. The agent talks JSON-lines over a Unix socket
(/run/k7d/k7d.sock). The verbs you actually need:
| You want to… | Call |
|---|---|
| Start from a warm VM or live cluster | tree_create / tree_create_cluster / tree_adopt_cluster |
| Open N parallel rollouts from one checkpoint | tree_fork_batch |
| Try again from an earlier node without destroying it | tree_rollback |
| Pin a winner so budget pressure can't kill it | tree_protect |
| Drop a losing subtree | tree_prune |
| Enforce RAM/disk caps now | tree_auto_evict |
A thin Python client that covers exactly this loop lives in
examples/cluster-tree-search/. Treat
it as the template for wiring your GRPO trainer - not as a finished
SDK. To watch a live tree (git-graph, fork latency, protect/evict
notes, per-branch traces) run examples/k7view/
on the node - k7d stays machine-first; k7d-view is the observer. The
full API reference will live in the docs site.
You do not need to be a VMM engineer to use k7d. You do need to know why a 100 ms cluster fork is even possible, because that is the product.
Memory is shared until someone writes. Guest RAM lives in one file. A fork pauses the source for a moment, notes which pages changed since the last checkpoint, maps the child's memory as a copy-on-write view of the parent's, and copies only those dirty pages. Everything else is shared. That is why 50 forks of a cluster fit in 64 GB: you pay for divergence, not for the base.
The cluster does not reboot because the network lies consistently. Each cluster lives on its own private Linux bridge. A fork gets a new bridge with the same guest IPs and MAC addresses as the source. From inside the guest, nothing moved - same addresses, same ARP cache, same TLS certs, same established TCP - so kubelet, the CNI, and the control plane keep running. Separate bridges mean forks cannot see each other. Without this, every fork would force a kubelet restart and a ~1-2 s agent restart per node, and the 100 ms claim would be impossible.
Forks live in a tree the daemon manages under budget:
base cluster ──► fork A ──► fork A1 (protected: winner)
├─► fork B (pruned: low reward)
└─► fork C ──► rollback ─► fork C'
These are the kinds of bugs that silently break "byte-identical."
CHALLENGES.md has all 56; these three are the
headline ones:
CLOCK_REALTIME stuck, and Kubernetes quietly parks.
Fix: re-arm the timer (and reset the paravirtual clock) on every
restore. (CHALLENGES.md #40)On one bare-metal box (~€40/month bare-metal: Ryzen 5 3600, 6 cores, 64 GiB, NVMe):
| Scale check | Measured | Enforced budget |
|---|---|---|
| Warm single-VM fork (<25% dirty) | ~5 ms | 50 ms |
| Warm-fork a live 3-node k3s cluster (under API churn) | ~105 ms | 1 s |
| 50 × 3-VM cluster-tree forks (shared pause) | ~4.1 s (~82 ms/cluster) | 20 s |
| VM boot → guest agent ready (cold) | ~163 ms | 250 ms |
Every row is an integration-test assertion
(LATENCY_BUDGETS.md). Full methodology:
the benchmark write-up.
Two layers - most RL users only care about the first.
This is the k3s that lives inside the VMs you fork. The fork engine
is N-node (tree_create_cluster(vm_count) / adopt any live set) -
there is no hard-coded 3. The CI fixture that proves the headline
numbers is a 3-node control plane with flannel + kube-proxy and a real
in-cluster Deployment. That default profile keeps stock k3s add-ons
off so the lean path stays lean; each add-on below is an opt-in
profile on the same switchboard, with its own proving test. Status
below mixes “API can do it” with “fixture exercises it.”
| Feature | Status | Notes |
|---|---|---|
| k3s control plane (server + agents) | ✅ Today | Fixture proves 3 Ready nodes; TLS / node IPs survive fork |
| N-node clusters (5, 20, …) | ✅ Today | Same fork path for any vm_count; limited by host RAM, not by the API. At ~3.2 GiB/node, a 20-node base alone is ~64 GiB - shrink guest memory (or use a bigger box) and it forks like the 3-node case |
Flannel (host-gw) | ✅ Today | Shared L2 between member VMs |
| kube-proxy (ClusterIP by IP) | ✅ Today | |
| Deployments / ReplicaSets / Pods | ✅ Today | e.g. inner-load Ready on source and fork |
| ConfigMaps / Secrets (as in-cluster objects) | ✅ Today | Exercised under churn before fork |
| overlayfs snapshotter (guest containerd) | ✅ Today | |
| CoreDNS | ✅ Today | Fixture proves DNS on all members across a warm fork - test_inner_k3s_coredns_dns_fork |
| Traefik / Ingress | ✅ Today | HTTP through an Ingress on source and fork - test_inner_k3s_ingress_fork |
| ServiceLB | ✅ Today | Traefik Service reports guest IPs as LB ingress; same proving test as Ingress - test_inner_k3s_ingress_fork |
| metrics-server | ✅ Today | kubectl top / metrics.k8s.io Available on all three nodes across a warm fork - test_inner_k3s_metrics_server_fork |
local-path / in-cluster PVC provisioning | ✅ Today | Same bytes on source and fork, then independent divergence - test_inner_k3s_local_path_pvc_fork |
| NetworkPolicy | ✅ Today | Default-deny + allow enforced on source and fork - test_inner_k3s_network_policy_fork. Guest kernel needs ipset + xt_set, xt NFLOG/limit, and nft_log/nft_limit (CHALLENGES.md #93) |
| HPA | ✅ Today | CPU-metrics scale-up on source and fork; observed utilization diverges after a fork-only load change - test_inner_k3s_hpa_scale_fork |
| Embedded etcd datastore | ✅ Today | Single-member --cluster-init WAL and writes survive a warm fork; per-bridge writes stay isolated - test_inner_k3s_etcd_datastore_fork |
| ArgoCD core GitOps | ✅ Today | In-cluster git://; Application Synced/Healthy + reconciledAt on both bridges; fork-only commit syncs only on the fork - test_inner_k3s_argocd_gitops_fork. application-controller shards and does not hold a coordination Lease (CHALLENGES.md #96) |
| Cilium (eBPF CNI / policies) | 🔜 Later | Not validated inside the guest; outer host may run Cilium |
| Longhorn / CSI drivers (iSCSI, NFS, …) | 🔜 Later | Guest kernel is minimal; no CSI path yet |
Nested hostNetwork pods | ❌ Not today | Known failure mode in the guest |
Need CoreDNS + Ingress on one cluster? Flip the profile flags - the switchboard is configuration, not a redesign. Same for a larger CI fixture: wiring 20 nodes is configuration + RAM, not a new fork feature.
This is the outer layer: kubectl on the host schedules pods into k7d
microVMs via runtimeClassName: k7. Relevant if you also want
single-VM sandboxes, not only whole-cluster forks.
| Feature | Status | Notes |
|---|---|---|
runtimeClassName: k7 (CRI / containerd shim) | ✅ Today | |
kubectl logs / exec / exec -it (PTY) | ✅ Today | Incl. resize, Ctrl-C, detach |
| Pod IP, Services, DNS, egress | ✅ Today | Host CNI dataplane |
| ConfigMap / Secret / projected / downwardAPI / emptyDir | ✅ Today | |
| hostPath, local-path PVC, k7d RWO disk volumes | ✅ Today | |
| Memory / CPU limits; multi-container / sidecars | ✅ Today | |
| Warm VM + whole-cluster fork / snapshot tree | ✅ Today | The point of the project |
Init containers; natural exit / restartPolicy | ✅ Today | Multi-container pods |
Multi-vCPU guests (cpu: "2"+) | ✅ Today | From pod CPU limits; fork/snapshot parity |
hostNetwork, NetworkPolicy, IPv6, arbitrary CSI / RWX | 🔜 Later | |
| Cross-node fork | 🔮 Later | Host-local trees today |
| Firecracker | Kata | CubeSandbox / E2B-style | k7d | |
|---|---|---|---|---|
| Warm fork of a running VM | snapshot → restore | no | snapshot + N restores (~220 ms) | live copy-on-write fork (~5 ms) |
| Snapshot tree (fork / rollback / protect / budget) | no | no | SDK around sandboxes | yes - daemon API |
| Forks a whole k8s cluster | no | no | no | yes (~105 ms) |
| Runs as a Kubernetes RuntimeClass | via FC-containerd | yes | no | yes (runtimeClassName: k7) |
| Formal methods | audit/fuzz culture | - | - | Kani + Aeneas on selected paths (memory math, tree budgets) |
They fork a sandbox. k7d forks a VM or an entire cluster. Deliberately not E2B-API compatible - different job.
Selected critical pieces are machine-checked - not the whole runtime:
| Tool | What it covers |
|---|---|
| Kani | Bounded proofs over selected unsafe / address-arithmetic harnesses |
| Aeneas → Lean | Functional correctness of the snapshot-tree budget / LRU eviction model |
make kani # selected unsafe / arithmetic harnesses
make verif-gen verif-build # regenerate Lean model + prove it
runtimeClassName: k7install.sh (make release)/etc/k7d/config.toml)docs/blog/2026-08-07-k7d-cluster-fork-benchmark.md - hardware, exact commands, methodologyCHALLENGES.md - 56 non-trivial bugs with root causes and time lost (the three above are the headline; start anywhere)todo-ideas.md - maturity-fixture backlog (write-during-fork, dirty floods, Kafka/KRaft, …) - not a specHACKING.md - build, test, and the RuntimeClass install stepsApache-2.0 - see LICENSE.
6 commits
Rust
90.4%
Lean
6.9%
Shell
2.3%