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
live containment

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.

01

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.

02

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.

03

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.

04

Observe

Live stdout/stderr stream over SSE, alongside an immutable per-session audit log: every egress decision, binding invocation, quota kills, result, teardown.

05

Deliver

The workload emits a structured result that comes back over the API, SDK, MCP, and an optional webhook.

06

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.

01

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.

02

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.

03

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 sandbox

The 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.

oneshot

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.

interactiveDocker/k8s warm-pod = Phase R

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

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.

gitk8s + real-remote = Phase R

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.

Built & tested

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.

Full architecture →
Caller

Agent

SDK · MCP · REST · Console

  • run(code, egress, scopes)
  • ← stream() · result()
  • ← audit()
run
Control plane

Fastify + Orchestrator

backend-agnostic core

  • • orchestrator — lifecycle
  • • credential broker — mints & withholds
  • • audit log — immutable
  • • SSE stream + webhooks
  • • auth + org-scoped tenancy
Joblaunch / teardown
Session pod

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 R

microVM · 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 · today

gVisor (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 · dev

host 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 · model

no 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.

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.

session s-7f9c2e · runninggVisor · runscLIVE STREAM$ python workload.pyresolving https://169.254.169.254 …urlopen error: egress denied by policycomputing result …enclave.result({"answer": 285})AUDIT LOGsandbox_startedrunsc · ro-rootfsegress_denied169.254.169.254workload_exitedcode 0result_collectedjson · 1 keysession_torn_downobjects reclaimedno secret enters the sandbox · the public Session has no token field
Demo recording coming soon

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.

run.tsts
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

Built

A 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

Partial

The 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