The platform under your agents
Run untrusted, agent-generated code safely.
Enclave is the platform under your agents — a control plane, SDKs, and a console. Each run lands in an isolated, ephemeral session under resource quotas and default-deny egress, with brokered credentials and service bindings the code can use but never sees. Isolation comes from a hardware-virtualized microVM — Firecracker on KVM — with gVisor on Kubernetes today. Stream it live, collect a structured result, tear it all down. Isolated, credential-scoped, and auditable by default.
- hardware-isolated microVMs
- secrets never enter the sandbox
- org-scoped multi-tenancy
- full audit trail
one request → one isolated, observable session → full teardown
The problem
Code you didn't write, running where it can hurt you.
The model decides; the code just runs. On shared infrastructure, an untrusted workload has four easy ways to cause real damage — and Enclave answers each with a specific, default-on control.
Exfiltrate your data
Generated code can open a socket and stream secrets, source, or customer data to anywhere on the internet.
Contained by
Default-deny egress. Nothing leaves the sandbox unless an explicit CIDR allowlist permits it — and every decision is audited.
Read host credentials
A workload on shared infra can reach the cloud metadata endpoint or a mounted service-account token and assume your identity.
Contained by
No ambient identity. No service-account token, the metadata IP is blocked, and no brokered secret ever enters the sandbox — service-binding secrets are injected at the network boundary.
Exhaust resources
A fork bomb, a memory balloon, or an infinite loop can starve every other tenant on the node.
Contained by
Hard resource quotas. Per-session cpu, memory, wall-clock, and pids limits; an over-budget workload is killed with a precise reason.
Escape into your cluster
A container breakout turns one bad function call into lateral movement across everything the kernel can see.
Contained by
Kernel-level isolation. A hardware-virtualized microVM or gVisor's runsc — non-root, all caps dropped, read-only rootfs, no host mounts.
And when something does go wrong, you can’t prove to a customer or an auditor that it didn’t. Enclave is the platform under the agents — it makes running untrusted code a routine, least-privilege, auditable operation instead of a gamble.
How it works
One request becomes one contained, observable session.
Enclave drives the same lifecycle for every workload — from provisioning the sandbox to reclaiming the last object — and records what happened along the way.
Provision
Each request gets one ephemeral, isolated session, created on demand — on the Kubernetes backend, a single gVisor-sandboxed Job behind the same interface the simulator and Docker share.
Contain
No host mounts, no service-account token, non-root, all caps dropped, read-only rootfs; default-deny egress that also blocks the cloud metadata IP; CPU / memory / wall-clock quotas.
Broker access
Any external access is brokered without placing a secret in the sandbox: service-binding secrets are injected at the egress proxy, and a private-repo git token stays on the clone init-container. The public Session has no token field.
Observe
Live stdout/stderr stream over SSE, alongside an immutable per-session audit log: every egress decision, binding invocation, quota kills, result, teardown.
Deliver
The workload emits a structured result that comes back over the API, SDK, MCP, and an optional webhook.
Teardown
Every per-session object — Job, NetworkPolicy, Secret, ConfigMap — is reclaimed. No residue.
Containment
Secure by default, on every path.
These aren't toggles you remember to set — they're the baseline for every session, enforced the same way across every backend: a hardware-isolated microVM, gVisor on Kubernetes, Docker, or the simulator.
Hardware-isolated microVM
Workloads run inside a Firecracker microVM (KVM) — a hardware-virtualized boundary — or under gVisor's runsc on Kubernetes today; never directly on the host kernel.
No host credentials
automountServiceAccountToken=false and a default-deny NetworkPolicy that also blocks the 169.254.169.254 metadata IP.
Least privilege
runAsNonRoot, all Linux capabilities dropped, read-only root filesystem, no privilege escalation, no host path mounts.
Default-deny egress
Nothing leaves the sandbox unless an explicit allowlist of CIDRs permits it. Every decision is audited.
Resource quotas
Per-session CPU, memory, and wall-clock limits. Over-budget workloads are killed with a precise reason.
Secrets at the boundary
Service-binding secrets are held by the egress proxy and injected at the network edge — never inside the sandbox. A private-repo git token is held by the clone init-container and withheld from the workload.
Immutable audit log
Every egress decision, binding invocation, quota kill, the result, and teardown — recorded per session.
Full teardown
Every per-session object is reclaimed when the run ends. Sessions are ephemeral by construction.
Credentials & service bindings
A secret the code can use, but never sees.
Agents need to act with real credentials — call an API, push to a private repo. With service bindings the secret never enters the sandbox at all: it is injected at the network boundary. For a private-repo source, the brokered git token is held by the clone init-container and withheld from the workload.
Bind
A session is granted a service binding at launch. The secret for the external service is held in the control plane and never placed in the sandbox — the workload gets only a base-URL env var.
Inject at the boundary
The per-session egress proxy holds the secret. When the workload calls the bound base URL, the proxy injects the secret and forwards to the real upstream — the secret is added at the network edge, never inside the sandbox.
Withhold
For a private-repo source, the brokered git token is injected only into the clone init-container and withheld from the workload. No secret is ever returned by the API or stored on the public Session — it structurally cannot leak.
Service bindings — injection at the network boundary
no secret in the sandboxThe stronger model. The secret for an external service is held in the control plane and never placed in the sandbox. A session is granted a binding at launch and gets only a base-URL env var — a URL, not a secret. Its NetworkPolicy permits egress only to a per-session egress proxy, which matches the binding, injects the secret, forwards to the real upstream, and audits every call (binding_invoked / binding_denied).
v1 boundary: HTTP(S) + static-secret only, via a no-MITM reverse-proxy. Transparent forward-proxy with injected CA, OAuth token-exchange, non-HTTP protocols, and auto-rotation are later.
Execution interface
Run a script, or hold a warm conversation with the sandbox.
The runner (Python + Node) supports two execution modes behind one protocol, each able to emit a structured result and artifacts — from a single batch run to a stateful, multi-turn interactive session.
One-shot run
Run a program, script, snippet, or a git-repo entrypoint to completion with a timeout. Capture stdout, stderr, exit code, a structured JSON result, and declared output artifacts.
Interactive (code-interpreter)
An agent-driven warm sandbox that accepts a sequence of exec turns sharing one namespace — interpreter globals, filesystem, installed packages. In-order, bounded by per-turn wall-clock plus idle-TTL and max-lifetime.
Filesystem I/O
Seed an input file set into the workdir; collect declared output artifacts into the result. Serves both modes — upload data, analyze it, return a result plus artifacts.
Git workload source
Point a session at a repo — { repo, ref, subpath?, entrypoint } — shallow-cloned into the sandbox. Private repos authenticate with a brokered, withheld git credential.
Egress is observed by the runner but enforced at the network layer — never by the workload itself. v1 interactive is single-language, one warm process, in-order turns; git is one repo, shallow, no submodules.
Identity & tenancy
Isolation between workloads — and between tenants.
The sandbox isolates one run from the host. Governance isolates one customer from another. Both are enforced where it counts: server-side in the control plane, on every route.
Authenticated everywhere
Every caller-facing route requires a verified API key or user JWT. Auth is enforced in the control plane — not a BFF veneer the API trusts blindly.
Fixed RBAC roles
owner / admin / developer / viewer, with scopes checked server-side on every route. A viewer cannot create or tear down a session, no matter how it asks.
Org-scoped multi-tenancy
Every session, fleet, trigger, and audit record belongs to a tenant. All queries are tenant-scoped — a tenant can never see or touch another's resources.
Proven, not promised
Cross-tenant access is denied server-side and asserted by tests, mirroring the secret-withholding discipline. SOC-2-oriented controls and evidence.
Strong per-tenant Kubernetes namespace isolation for session objects is the one remaining piece, gated behind a live cluster (Phase R).
Architecture
A backend-agnostic core, between the caller and the sandbox.
The control plane is the hub: everything else is a client of its REST API, and every workload runs behind one pluggable backend interface.
Agent
SDK · MCP · REST · Console
- run(code, egress, scopes)
- ← stream() · result()
- ← audit()
Fastify + Orchestrator
backend-agnostic core
- • orchestrator — lifecycle
- • credential broker — mints & withholds
- • audit log — immutable
- • SSE stream + webhooks
- • auth + org-scoped tenancy
gVisor sandbox (runsc)
the dangerous side of the boundary
- no service-account token
- non-root · all caps dropped
- read-only rootfs · no host mounts
- egress: default-deny
- credential injected (env)
- CPU / memory / wall-clock quotas
logs & result stream back over SSE · the audit log records every egress decision, quota kill, and teardown · every object is reclaimed on teardown
One interface, four backends
The isolation boundary is a hardware-virtualized microVM.
The control plane talks to one SessionBackend interface, so the orchestrator, audit, streaming, credential, and tenancy logic are backend-agnostic. Develop against an in-process model on a laptop; run it behind a Firecracker microVM — every path inherits identical behaviour.
FirecrackerBackend
In build · Phase RmicroVM · KVM
The isolation boundary: a per-session Firecracker microVM with its own guest kernel, hardware-virtualized on KVM. Same runner protocol, credential inject, deny-all egress, and result capture — behind the one interface every backend shares.
- Hardware-level isolation, not a shared kernel
- Deny-all egress + per-session resource limits
KubernetesBackend
Built · todaygVisor (runsc)
The boundary shipping today. Provisions a gVisor Job + per-session NetworkPolicy + credential Secret + code mount, streams logs, maps terminal state to a kill-reason, and tears it all down.
- Syscall-level isolation (runsc)
- Enforced allowlist egress & resource limits
DockerBackend
Built · devhost kernel
A dev convenience that executes the runner with hardened defaults (non-root, read-only rootfs, caps dropped, --network none). Not a security boundary for genuinely untrusted code.
- Local container execution
- Cannot enforce allowlist egress — warns loudly
SimulatorBackend
Built · modelno boundary · in-process
Models the sandbox's observable behaviour — egress decisions, host-fs isolation, quota kills, credential withholding — without executing code. Honest about being a model.
- Fast hermetic tests & the adversarial demo
- The local console & every dev loop
The Firecracker microVM backend is in active development (Phase R); gVisor on Kubernetes is the isolation boundary shipping today. Allowlist egress is enforced on Kubernetes; Docker and Firecracker get deny-all plus a loud warning, never a silent gap.
Four surfaces, one API
Call it however your agent works.
The control plane is the single source of truth. The SDK, MCP server, and console are all thin clients of its REST API — so behaviour is identical no matter how you reach it.
HTTP API
The control plane is a Fastify REST API. Create a session, poll its status, fetch the result and audit, stream over SSE, tear it down.
API reference→TypeScriptSDK
A typed client — run / stream / result / audit / teardown, plus interactive exec, fleets, git and filesystem sources, and service bindings — so callers never hand-roll HTTP or SSE.
SDK docs→MCPAgent tools
An MCP server exposes the platform to models as tools — the core run/result/audit/teardown set plus git workloads, fleets, and service bindings — so an agent can drive Enclave directly.
MCP tools→WebConsole
A React console for launching runs and watching the live stream + audit log — a human-facing view of the same API, with auth and org scoping.
Console docs→See it run
Four hostile workloads contained. One clean run returns.
The whole containment story in one command. Watch a metadata-IP exfil get denied, a fork bomb get killed, and a clean workload return its structured result — while the credential token stays withheld the entire time.
Quickstart
A whole session in five calls.
Run untrusted code, watch it live, collect the structured result, and tear it down — over the typed SDK. The same lifecycle is available over the REST API, the MCP server, and the web console.
No brokered secret is ever returned — service-binding secrets stay at the network boundary.
import { EnclaveClient } from "@enclave/sdk";
const enclave = new EnclaveClient({ baseUrl: "http://127.0.0.1:8088" });
const session = await enclave.run({
code: `print("hi"); enclave.result({ ok: true })`,
language: "python",
egress: { mode: "deny_all", allow: [] },
});
for await (const frame of session.stream()) console.log(frame); // live
const result = await session.result(); // structured
await session.teardown();Deployment
Self-host it, or run the hosted profile. Same binary.
Enclave is sovereign by construction — run it inside your own cluster, or boot the same control-plane binary in its multi-tenant hosted profile. The difference is configuration, not a fork.
Self-host
BuiltA complete set of Kubernetes manifests — Namespace, gVisor RuntimeClass, least-privilege RBAC, LimitRange, and the control-plane Deployment + Service — composed by one kustomization.
- Runs entirely inside your cluster
- No data leaves your boundary
- Native on macOS for dev (simulator / Docker)
Hosted / multi-tenant
PartialThe same binary boots in the hosted profile: auth, RBAC, and tenant isolation are forced on, and the dev bypass is refused so it can never boot open. A kustomize overlay flips the profile.
- Auth + tenant isolation enforced by default
- Open-by-accident is structurally refused
- Per-tenant namespace + live apply = Phase R
No managed signup or billing system in v1 — the hosted profile is the multi-tenant runtime, not a SaaS storefront.
Get started
Give your agents a place to run code that can't hurt you.
Read the architecture, browse the per-component docs, or clone the repo and run the adversarial demo in one command.
$ pnpm install && pnpm demo