Sandbox: runtime tiers + fleet-scheduled placement
Status
accepted — 2026-05-31 (owner-ratified). Drafted from a design conversation about whether the sandbox should integrate with infra/net/box (kbox) and infra/net/fleet; refined to the isolation-class lens (Axis 1). Ratified decisions on the open questions:
- Q1a — add the WASM class: YES. ~10 ms cold start is a genuinely new
capability for short, frequent agent runs; serves the WASI-targetable subset (not a shared-kernel replacement). → SANDBOX-024 is unblocked.
- Q1b — shared-kernel slot: keep Incus for now. OCI is the same
isolation class as the Incus system-container, so swapping is a benchmark-gated boot-latency optimization, not initial scope. Revisit only if a real-workload benchmark shows the boot win is material.
- Q2 — placement contract: sandbox CALLS Fleet's scheduler. The session
stays a sandbox-owned object (tenantquotacapabilities/lifecycle); Fleet is a pure capacity/placement layer. NOT a fleet-native
SandboxSessionCRD. → SANDBOX-025 still needs a joint contract RFC withinfra/net/fleetbefore implementation, but the direction + ownership split are ratified. - *3 — WASM class capabilities: Exec + File IO + Upstream; no
Terminal/Watcher*(no real shell to attach; Watcher is a full-OS concept).
- Q4 — sequencing: SANDBOX-024 (WASM driver) first, self-contained;
SANDBOX-025 (fleet placement) after, gated on the joint fleet RFC.
The boundary contract + axes below are normative as of ratification.
Summary
Today a sandbox session is one Incus VM on one host (s.khost1), placed by a single in-process Manager warm pool. That fixes both how a session is isolated (one runtime) and where it runs (one host). This RFC separates those into two independent axes:
- Axis 1 — runtime tier (vertical: how isolated / how fast). The
runtime.Runtimedriver seam already abstracts this (subprocess / firecracker / incus). Add a kbox tier (OCI + WASM) so sessions can pick an isolation/latency class instead of always paying full-VM boot. - Axis 2 — placement (horizontal: which host). Replace the single-host
warm pool with Fleet-scheduled placement (
infra-RFC-004), so the service spans a fleet of hosts — lifting the SANDBOX-019 single-host perf/pool ceiling and removing the SPOF.
Motivation
- Latency floor. An Incus system container boots in ~5–8 s. Many agent
code-runs are short and frequent; a kbox WASM workload is ~10 ms cold (box#112, sandboxed by default). The current single tier overserves those.
- Capacity + SPOF. One host caps concurrent sessions and is a single
point of failure.
infra-RFC-004reframes Fleet as a universal compute-orchestration backend that schedules workloads onto cluster nodes — exactly the placement problem sandbox hand-rolls today. - The seams already exist.
runtime.Runtime(driver plugin) and Fleet'sscheduler make both axes additive, not rewrites.
Axis 1 — runtime tiers (by isolation class)
A runtime tier is not a linear "fast→slow" ladder; what actually differentiates a tier is where the security boundary sits. There are three real isolation classes, and a session's class is chosen by policy (language / workload / tenant plan):
| Class | Boundary | Backings | Cold start | Fits |
|---|---|---|---|---|
| WASM | capability sandbox — code has no kernel access, only the WASI syscalls granted | kbox-WASM | ~10 ms | pure-compute, WASI-targetable runs |
| Shared kernel | namespaces + cgroups + seccomp; all workloads share the host kernel | Incus system container (default today) — OR kbox OCI container | ~100 ms – 8 s | the workhorse: normal short-lived Linux apps |
| Dedicated kernel | each workload gets its own kernel (hypervisor) | Incus --vm, Firecracker microVM (#014) |
~200 ms – 8 s | untrusted / hostile code |
Plus subprocess (no isolation) for dev/local only — not a production tier.
Key consequence (why OCI is not a separate tier): the Incus driver shipped so far runs system containers by default (cfg.VM gates --vm, default false). A kbox-OCI workload is the same isolation class as that — both are shared-kernel. So OCI and Incus-system-container are not two rungs; they are two implementations of the shared-kernel slot. Running both is double the driver surface (every capability × every driver) for zero isolation gain. The shared-kernel slot should have exactly one backing.
The optional capabilities (Terminal, Upstream, Archiver, Watcher, resource limits, network modes) are per-class — a class advertises what it supports; WASM omits the full-OS ones (terminal/watcher). SANDBOX-024 implements the WASM class behind runtime.NewKbox.
Axis 2 — placement
Today: Manager → local runtime.Runtime bound to this host's warm pool.
Proposed: Manager → a placement seam that asks Fleet to schedule the session onto a node, and dispatches the runtime.Runtime calls to that node's sandbox agent. Warm pools become per-node, fleet-aware; the global floor is a Fleet policy. SANDBOX-025 implements this.
Boundary contract (the crux)
| Concern | Owner |
|---|---|
| Tenant identity, quota, session semantics, capability API | sandbox |
| Runtime tier implementation (how a node runs the workload) | sandbox driver (incus / kbox / firecracker) |
| Node selection, capacity, bin-packing, node health, failover | fleet |
| ImageOCIWASM artifact management | kbox (when that tier is used) |
Sandbox stays the tenant-facing API + policy layer; fleet is the placement layer; kbox is an artifact+runtime layer. A session is a sandbox concept that may be realized as a fleet-scheduled, kbox/incus-backed workload.
Open questions (for ratification)
- Q1 — which isolation classes do we back, and with what? Split into two
sub-decisions, because OCI is not a separate tier (see Axis 1):
- Q1a — add the WASM class? (recommend yes.) The ~10 ms cold start is
a genuinely new capability Incus can't touch; the prize for short, frequent agent runs. Caveat: WASI is constrained (no full Linux syscalls; Python/Node-on-WASI immature), so it serves a subset of workloads — not a replacement for the shared-kernel class.
- Q1b — who backs the shared-kernel slot: Incus (today) or kbox-OCI?
*(recommend: keep Incus for now; treat OCI as a benchmark-gated boot- latency optimization, not initial scope.)* Both are the same isolation class, so this is a perf/ops trade, not an architecture one: OCI may boot faster (~100 ms vs ~5–8 s) and reuses kbox's image management (
reuse-first), but Incus is already built + validated and upgrades to the dedicated-kernel class trivially (--vm). Only swap if a benchmark on the real workload mix shows the boot win is material.
- Q1a — add the WASM class? (recommend yes.) The ~10 ms cold start is
- Q2 — placement contract shape. Does sandbox call Fleet's scheduler
(sandbox owns the session object, fleet just places it), or does Fleet own a
SandboxSessionCRD (fleet-native)? The table above assumes the former (looser coupling); ratify the choice. - Q3 — WASM class semantics. *(recommend: Exec + File IO + Upstream;
omit Terminal + Watcher.)* WASM workloads are compute-oriented and short — an interactive PTY has no real shell to attach to, and Watcher is a full-OS concept. File IO (in/out of the WASI sandbox) and Upstream (if it serves HTTP) fit. This is exactly why capabilities are per-class.
- Q4 — sequencing. kbox driver (#024) and placement (#025) are
independent; either can land first. Recommend #024 first (self-contained, no cross-component contract) to de-risk the tier model before the fleet coupling.
Alternatives considered
- Keep single-host + scale the host. Vertical-only; hits a wall and keeps
the SPOF. Rejected as the long-term answer (still fine short-term).
- Sandbox builds its own scheduler. Duplicates Fleet (
infra-RFC-004);violates
reuse-first. Rejected. - Add kbox-OCI as a third shared-kernel tier alongside Incus. Doubles the
driver surface (every capability × every driver) for zero isolation gain — OCI and Incus-system-container are the same isolation class. Rejected as a tier; OCI is only in play as a possible replacement backing for the one shared-kernel slot, gated on a boot-latency benchmark (Q1b).
- Replace Incus with kbox-OCI now. Throws away a working, validated
driver before a benchmark justifies it. Deferred, not rejected — revisit if Q1b's benchmark favors OCI.
Impact
- New:
runtime.NewKboxdriver (#024); placement seam inManager(#025). - Unchanged: the tenant-facing HTTP/WS API, the capability interfaces, the
Incus driver (becomes one tier among several).
References
infra-RFC-004-fleet-global-control-plane.kmd(Fleet control plane)infra/net/box(kbox; OCI + WASM), box#112 (WASM workload backend)sandbox-RFC-001-foundations.kmd(the sector's first RFC)- SANDBOX-024 (kbox driver), SANDBOX-025 (fleet placement), SANDBOX-019
(single-host perf ceiling), SANDBOX-014 (firecracker tier)
policies/hyperscale-first.kmd,policies/reuse-first.kmd