E2B compatibility
The E2B gatewayThe kibotos-e2b service, which translates requests from the E2B SDK into the native API so that programs written for E2B can use Kibotos. kibotos-e2b translates the E2B control API and the envd protocol into the Kibotos native API, so programs written with the official E2B SDK run on Kibotos. These pages show which SDK calls and endpoints work, how they behave on Kibotos, and what is not supported.
Compatible versions
E2B compatibility is measured against the official JavaScript SDK:
- The version that passed acceptance is
e2b@2.46.1. - The compatibility target is
e2b@2.49.1. It has not passed acceptance yet. - The capabilities on these pages are those verified with
2.46.1.
Example
The example needs Node.js 22 or later and e2b@2.46.1. It reads the connection settings from these environment variables:
| Variable | Meaning |
|---|---|
E2B_DOMAIN | The sandbox domain of the deployment, without a scheme, such as sandbox.example.com |
E2B_API_KEY_FILE | Path of a file that holds a gateway API key from the deployer |
E2B_API_URL | Optional. The control API address. Defaults to https://api. followed by E2B_DOMAIN |
E2B_TEMPLATE | Optional. The Template to start. Defaults to kibotos-minimal |
When the deployment's certificate is not from a public CA, also set Node.js's own NODE_EXTRA_CA_CERTS to the CA file.
The following example creates a short-lived sandbox, runs a command, and then deletes the sandbox. lifecycle explicitly chooses deletion on expiration:
import { readFile } from 'node:fs/promises';
import { Sandbox } from 'e2b';
const domain = process.env.E2B_DOMAIN;
const sandbox = await Sandbox.create(process.env.E2B_TEMPLATE || 'kibotos-minimal', {
apiKey: (await readFile(process.env.E2B_API_KEY_FILE, 'utf8')).trim(),
domain,
apiUrl: process.env.E2B_API_URL || `https://api.${domain}`,
secure: true,
timeoutMs: 60_000,
lifecycle: { onTimeout: 'kill', autoResume: false },
});
try {
const result = await sandbox.commands.run('printf kibotos-ready');
console.log(result.stdout);
} finally {
await sandbox.kill();
}Save the example as example.mjs, then install the SDK and run it:
npm install e2b@2.46.1
E2B_DOMAIN=sandbox.example.com E2B_API_KEY_FILE="$HOME/.config/e2b/api-key" node example.mjsBy default, the SDK creates sandboxes that require public internet access. If you do not need network access, add allowInternetAccess: false to the create options. The address families and outbound capabilities a deployment supports depend on the node configuration. For background on IPv4 support, see #59. For the outbound policy, see Network.
What you can use
Each row is one area of the SDK. The area links to the page that describes its behavior on Kibotos.
| Area | What works | Endpoints |
|---|---|---|
| Sandboxes and lifecycle | Sandbox.create, Sandbox.connect, getInfo(), listing, sandbox.kill(), sandbox.pause(), sandbox.setTimeout, and Idempotency-Key | POST /sandboxes, GET /sandboxes/{id}, GET /v2/sandboxes, DELETE /sandboxes/{id}, POST /sandboxes/{id}/pause, connect, timeout, refreshes |
| Volumes | Standalone Volumes created by name and mounted with volumeMounts | POST /volumes, GET /volumes, GET /volumes/{id}, DELETE /volumes/{id} |
| Commands and files | sandbox.commands.run, PTYs, input and signals, with a chosen user and cwd | /process.Process/{Start,Connect,SendInput,CloseStdin,SendSignal,Update}, all POST |
| Commands and files | sandbox.files.* and non-recursive files.watchDir | /filesystem.Filesystem/{Stat,MakeDir,Move,ListDir,Remove,WatchDir} (POST), GET /files, POST /files, GET /health |
| Network | allowInternetAccess, addresses and CIDRs in network.allowOut and network.denyOut, network.egressProxy, and sandbox.updateNetwork() | allow_internet_access in create requests, PUT /sandboxes/{id}/network |
| Metrics | sandbox.getMetrics() and Sandbox.getMetrics(id), when the deployment is connected to an instance metrics store | GET /sandboxes/{id}/metrics, GET /sandboxes/metrics |
| Application ports | HTTP and WebSocket forwarding to ports in the sandbox, public or private, with optional Host rewriting | {port}-{sandboxID}.<domain> |
Capabilities the gateway does not provide return an explicit error. See Not supported.
Not supported
An unsupported capability always fails with an error. The gateway never ignores it and reports success, so your code finds out at once.
How unsupported calls fail
- The gateway returns HTTP 501 with the response body
{"code":501,"message":"unimplemented: <capability name> is not supported by the core gateway"}. - The SDK throws
SandboxErrorwith the message501: unimplemented: <capability name> is not supported by the core gateway. - The gateway returns 501 instead of 404 because the official SDK interprets 404 as "sandbox does not exist".
- Endpoints the gateway does not implement at all, such as
GET /sandboxes, sandbox logs, and template build and listing, return a plain 404, which the SDK reports as a missing sandbox.
Endpoints
The following routes exist but always return 501. They return immediately after authentication, without calling the native API or changing gateway state.
| Request | Capability name | Missing native capability |
|---|---|---|
POST /sandboxes/{id}/fork | sandbox fork | Snapshot capture and creating copies from snapshots |
POST /sandboxes/{id}/snapshots | snapshot capture | Snapshot resources and capture commands |
GET /snapshots | snapshot listing | Same as above |
DELETE /templates/{ref} | snapshot deletion | Same as above |
GET /teams/{teamID}/metrics, GET /teams/{teamID}/metrics/max | team metrics | Teams: the gateway's API key is shared by the whole deployment, so there is no team to report on |
When the deployment is not connected to an instance metrics store, GET /sandboxes/metrics and GET /sandboxes/{id}/metrics also return 501, with the capability name metrics. See Metrics.
For progress on these capabilities, see #81, #82, #85, and #86.
Create options
The official SDK sends every option you configure. An option the gateway cannot implement makes the create request fail, instead of being ignored with a 201. The create response does not echo these fields, so a failure is the only way you would know the option did not take effect. The check runs before any state is written and before any native API call.
| Field | Capability name | Missing native capability |
|---|---|---|
Non-empty envVars | sandbox environment variables | Setting environment variables at creation |
iam with a token | IAM tokens | Token binding |
Non-empty mcp | MCP configuration | MCP management |
network.allowOut containing domain names | network egress allowlist domains | Outbound network policy by domain name |
network.rules | network egress rules | Same as above |
autoResume: {"enabled": true} | autoResume | Automatic wake-up through application ports |
Non-empty snapshotID | snapshot restore | Creating sandboxes from snapshots |
- Every option in the table returns 501 with the response body described above.
- The error message has the same format as other creation errors, with an extra
create sandbox:prefix. - A field that is absent,
null, an empty object, or an empty array counts as unset, and creation proceeds normally.
Other calls and options
| Capability | On Kibotos | Details |
|---|---|---|
| Memory pause | sandbox.pause() and autoPause always perform a cold pause. Memory and running processes are not kept | Sandboxes and lifecycle |
| Recursive directory watching | files.watchDir with recursive: true returns unimplemented. allowNetworkMounts is ignored | Commands and files |
CreateWatcher, GetWatcherEvents, RemoveWatcher | Return unimplemented. They require watch state across requests, and the gateway keeps no state | Commands and files |
| Network options when changing the network | Domain names in allowOut, rules, egressProxy with only username, and options the ctrl does not support return 501 | Network |
How the gateway works
The gateway has no storage of its own:
- E2B-specific information (metadata, creation options, volume names) is written into the
labelsandannotationsof the WorkspaceA complete Linux environment for an AI Agent, running in its own MicroVM. Agents read and write files, run processes, and start services in it without affecting the host or other Workspaces. or VolumeA persistent volume that exists independently of any Workspace. A Workspace binds at most one Volume, mounted at /data by default. along with the create command, and ctrl keeps it. - The envd token and traffic token are not stored. The gateway derives them from the gateway key and the sandbox ID.
- Each gateway instance caches only what it reads from ctrl, so several instances can serve at the same time. Each instance needs its own Operator identity; see Prepare the identity and start.
Creating and stopping sandboxes, running commands, and file operations all become calls to the Kibotos native API. The gateway itself runs no VMs. It does not emulate capabilities that the native API does not yet provide: it never copies disks, calls private VMM interfaces, or writes to the ctrl database, and it keeps no sandbox lifecycle state of its own.
- For deployment, see Install the E2B gateway and Reinstalling the gateways.
- For the code structure and tests, see E2B gateway code structure and tests.
Next steps
- Migrate from E2B: move an existing program step by step.
- Sandboxes and lifecycle: creation, pause and resume, and expiration on Kibotos.
- Commands and files: running processes and transferring files.
- Core concepts: Workspaces, Volumes, and their states.
- Guarantees and limits: when data is kept.
Go SDK
The Go SDK lets Go programs call Kibotos. This page covers installing it, connecting to ctrl with an Operator identity, the conventions it carries for write operations, and reaching the files, processes and services of a Workspace.
Migrate from E2B
This page shows how to move a program from E2B to Kibotos: check that what it uses is available, point the SDK at the gateway, and replace what differs. For the full behavior of each call, see the other pages in this section.