Kibotos

Sandboxes and lifecycle

With the E2B SDK you create, pause, resume, extend, and kill sandboxes on Kibotos with the same calls as on E2B. This page covers how each lifecycle call behaves on Kibotos, what resources a new sandbox gets, how expiration and Idempotency-Key retries work, and what queries return.

Overview

Each sandbox is a 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. in Kibotos. The lifecycle calls map to these endpoints:

SDK callEndpointOn Kibotos
Sandbox.createPOST /sandboxesCreates the sandbox with the resources the deployment sets. See Creating a sandbox
getInfo()GET /sandboxes/{id}Returns the configuration in effect. See Sandbox information
The SDK's list callGET /v2/sandboxesLists sandboxes, including paused ones
sandbox.kill()DELETE /sandboxes/{id}Deletes the sandbox. A standalone Volume mounted with volumeMounts is kept; the /data Volume of a sandbox created without volumeMounts is deleted with it. See Volumes
sandbox.pause()POST /sandboxes/{id}/pauseCold pause. See Pause and resume
Sandbox.connectPOST /sandboxes/{id}/connectResumes a paused sandbox and only extends its lifetime
sandbox.setTimeoutPOST /sandboxes/{id}/timeoutSets the expiration time, longer or shorter. See Expiration
NonePOST /sandboxes/{id}/refreshesExtends the lifetime by at least 15 seconds

The examples on this page leave out the connection options (apiKey, domain, apiUrl). Pass them as in the example on E2B compatibility.

Creating a sandbox

Create a sandbox that lives for ten minutes and pauses instead of being deleted when it expires:

import { Sandbox } from 'e2b';

const sandbox = await Sandbox.create('kibotos-minimal', {
  timeoutMs: 10 * 60_000,
  lifecycle: { onTimeout: 'pause', autoResume: false },
});
  • The request returns 201 once the sandbox is running, waiting at most 90 seconds. A sandbox that is not running by then returns 502 and may still start. Retry with the same Idempotency-Key to wait for that sandbox instead of creating another; see Retries with Idempotency-Key.
  • A request body larger than 1 MiB returns 400.
  • The resources come from the deployment settings, not from the request. See Resources.
  • A create that no node can place returns 503. See Insufficient capacity.
  • For how long the sandbox lives, see Expiration.

Metadata and option size

The gateway stores metadata and E2B options in ctrl, so they count toward ctrl's total limits:

LimitValueCounted
Total annotations262144 bytesThe raw JSON of the metadata, plus the keys and values of other annotations such as maskRequestHost
Total labels65536 bytesThe label of each metadata entry (counted as a 48-character digest when the key exceeds 63 characters or does not follow label rules), plus the keys and values of other labels such as the namespace, tokens, and boolean options

If either limit is exceeded, the create returns 400 and no sandbox is created.

Resources

E2B create requests carry no resource fields. The gateway requests resources for each new sandbox according to deployment settings:

ResourceGateway settingDefault
CPUKIBOTOS_E2B_DEFAULT_CPU_MILLIS1 core
MemoryKIBOTOS_E2B_DEFAULT_MEMORY_BYTES1 GiB
Writable space on the root file systemKIBOTOS_E2B_DEFAULT_DISK_BYTES5 GiB
  • cpuCount, memoryMB, and diskSizeMB echo the values the sandbox actually received.
  • diskSizeMB is the writable space confirmed by the node. While the sandbox is starting, or if it was never successfully placed, there is no confirmed value yet. GET /sandboxes/{id} and the list endpoint still return the sandbox, with diskSizeMB set to 0. E2B requires this field to be a non-negative integer and never empty, and upstream also returns 0 when the value is missing.
  • The writable space takes up capacity in the node's storage pool from placement onward. Only data actually written takes up disk. Deployments with small storage pools need to lower this value according to the number of sandboxes.
  • The settings affect only sandboxes created afterward. The writable space of existing sandboxes does not change.

Deployers set these variables as described in Install the E2B gateway.

Pause and resume

Pause and resume a sandbox:

await sandbox.pause();
const resumed = await Sandbox.connect(sandbox.sandboxId);

On Kibotos, a pause is a cold pause: the gateway stops the sandbox with the Kibotos StopWorkspace call, and a resume starts it again with StartWorkspace. Kibotos chose these semantics deliberately.

A pause keeps the sandbox ID and the Volume (mounted at /data by default). A resume starts a new execution, and the envd token and traffic token stay the same.

Warning

Memory and running processes are not kept. Changes to the root file system are kept only on a best-effort basis and cannot be treated as a complete disk snapshot. Write files you need to keep to the Volume.

Pausing

POST /sandboxes/{id}/pause performs a cold pause:

  • An empty body, memory:true, and memory:false all perform a cold pause. The SDK's pause() sends memory:true by default; the gateway still performs a cold pause and does not claim to support memory pause.
  • It returns 204 after confirming the sandbox has stopped.
  • A repeated pause returns 409, which the SDK turns into a return value of false.
  • A pause clears the expiration time. See When the expiration time changes.

Resuming

The result of POST /sandboxes/{id}/connect depends on the state of the sandbox:

Sandbox stateResult
Running, or still starting200 once it is running. The expiration time is only extended; see Expiration
Paused, or last failed for a retryable reasonStarts the sandbox, sets the lifetime for this run, waits for the start to finish, and returns 201
Paused, and no node can place it503 with a message containing resource_exhausted. The sandbox stays paused; see Insufficient capacity
Not running within 90 seconds502. The start may still finish; retry with the same Idempotency-Key
Failed for a non-retryable reason, or fails while waiting409, with a message starting with sandbox failed:
Failed and still holding its previous execution, including the rare case where Kibotos could not release the node after a failed placement409. Kibotos refuses to start it again. After an operator stops it with kibo workspace stop --force, connect resumes it

The returned tokens are the same as at creation. As in E2B, connect does not rotate tokens.

Unplanned pauses, restarts, and failures

EventSandbox stateWhat to do
The host runs out of memory and the kernel kills the sandboxPausedconnect resumes it. As with an explicit pause, memory and processes are not kept, and the last writes may be lost
The guest shuts itself downPausedconnect resumes it
The guest reboots itselfStays running; queries and connect succeed as usualRequests to envd and application ports fail until the guest comes back; retry them. Memory and processes are not kept
The sandbox ends unexpectedly for another reason, for example a VMM failureFailed. It does not recover by itselfconnect returns 409, queries and pause return 502, lists do not show it, and retries never succeed. After an operator stops it with kibo workspace stop --force, connect resumes it

For how Kibotos handles these cases and which backends support them, see Stops and restarts handled by the server.

Insufficient capacity

If no node can place the sandbox at start (for example, all nodes are short on memory), that connect returns 503 with a message containing resource_exhausted. Other endpoints that hit insufficient capacity, such as creating a sandbox or a Volume, also return 503.

  • Such a sandbox stays paused, as when a resume fails on upstream E2B: queries return state: paused, lists show it as paused, and pausing it again returns 409. Once capacity recovers, another connect starts it, with no operator intervention needed.
  • A sandbox that could not be placed at creation is also listed as paused. Find it by its metadata, then connect to start it or delete it.
  • For the expiration time after a failed start, see After a failed start.

Waking a sandbox through its application ports (autoResume), snapshots, and cloning are not available; see Not supported.

Expiration

Make a running sandbox expire ten minutes from now:

await sandbox.setTimeout(10 * 60_000);

Each request sets the expiration time in its own way:

RequestEffect
createSets the lifetime to the requested timeout. The JS SDK always sends one: 5 minutes unless you set timeoutMs. A request without one gets the gateway's KIBOTOS_E2B_DEFAULT_TIMEOUT, 1 hour by default. The countdown starts when ctrl accepts the command, so it includes creation time
connectOnly extends. The new endAt is the later of the existing expiration time and "now + the requested timeout". A resume sets the lifetime for this run, counted from when ctrl accepts the start, so start time is included
timeoutSets the expiration time to the requested value, which can extend or shorten it
refreshesOnly extends, by at least 15 seconds (E2B's SandboxTimeoutDefault). A duration that is missing, less than 15 seconds, or not positive is treated as 15 seconds

Expiration action

Create optionAt the expiration time
None, or lifecycle.onTimeout: 'kill'The sandbox is deleted
autoPause: true (lifecycle.onTimeout: 'pause' in the SDK)The sandbox is paused instead of deleted
  • timeout and connect keep the action set at creation.
  • Without autoPause, a resumed sandbox is still deleted when it expires.
  • Both values of autoPauseMemory are treated as a cold pause. Setting only autoPauseMemory without enabling autoPause returns 400.

Timeout values

  • timeout values mean the same as in E2B: a positive integer is a number of seconds, and 0 and negative numbers both mean expire immediately. E2B expresses this as endAt = now; the gateway uses the shortest positive duration, because ctrl accepts only positive expiration durations.
  • The request fields of connect and timeout are required in E2B and are treated as 0 when missing. Only create can omit the field.
  • For connect, 0, negative numbers, and missing fields all request "now", so they keep the original value. When the requested timeout is shorter than the remaining time, the original value is kept and the native expiration revision does not advance. This matches E2B: connect only extends, never shortens.
  • A deployment can cap the duration of a single request with KIBOTOS_E2B_MAX_TIMEOUT. create and connect above the cap return 400, at the same place where E2B checks the team limit. timeout and refreshes are not checked, and E2B does not check them either.

When the expiration time changes

  • All of these requests return success only after the native expiration setting has been updated. The endAt returned by inspect and list comes directly from the native expiration time.
  • Accessing files and running commands do not change the lifetime.
  • The expiration time and the state change of a pause or resume are committed in the same native call. A sandbox that paused successfully has no expiration time, and a delete action set earlier does not fire while it is paused. A sandbox that started successfully always has the expiration time for this run. A failed start is the exception; see After a failed start.
  • Expiration actions are carried out by ctrl; the gateway has no timer of its own. Stopping the gateway does not affect expiration times already set.
  • While ctrl is temporarily unavailable, extensions fail. After it recovers, it carries out expiration actions at the saved times.
  • Once ctrl has started an expiration action, an extension can no longer cancel it.

After a failed start

  • A sandbox that had no expiration time before the resume (for example, a paused one) still has none after the failed resume. It is not paused or deleted even after the timeout of this request passes.
  • The start command writes the expiration time for this run as soon as ctrl accepts it, so after a failed start the gateway sends another native call to clear it. If the gateway exits between these two calls, this expiration time remains.
  • A sandbox that could not be placed at creation keeps its expiration time from creation and is deleted on expiration according to the settings at creation. If a connect to it fails, its expiration time is replaced by the one set in that request.

Retries with Idempotency-Key

create, connect, pause, timeout, refreshes, network changes, and delete support the Idempotency-Key header. Requests with the same key must have the same content. A key longer than 256 bytes returns 400.

When a result is unknown, for example after an interruption, retry with the same key. The gateway first asks ctrl whether the command was already committed: if it was, the gateway waits for it to finish and returns the result; only if it was not does the gateway issue it again.

  • The value of Idempotency-Key is not a Kibotos command IDA stable identifier that the caller generates for every write request. Resending a request with the same command ID does not run the operation twice.. The gateway derives the command ID from it together with the namespace, the operation, and the sandbox. The same value used for different operations yields different command IDs, so you cannot use it to query commands in the native API.
  • Because command IDs are derived from the key, the gateway stores nothing. None of this depends on local gateway state, so retrying against a different gateway instance works the same way.
  • If the same key comes with different request content, ctrl treats it as a conflict and the gateway returns 409.
  • Delete and refreshes also derive their command IDs from the key, and a retry waits for the same command to finish.
  • Revision conflicts return 409. The gateway does not read the new revision and retry the old request; make a new request based on the current state.

Sandbox information

GET /sandboxes/{id} and the list endpoint return the configuration actually in effect. The lifecycle fields:

FieldEcho rules
lifecycle{"onTimeout":"kill","autoResume":false} when the expiration action is delete, and onTimeout:"pause" when it is pause. A paused sandbox has no expiration time, and the echo shows the setting the next start will use
endAtComes directly from the native expiration time
cpuCount, memoryMB, diskSizeMBThe values the sandbox actually received. See Resources

getInfo() in SDK 2.46.1 keeps these fields and the network, port, and Volume fields. The SDK's list call keeps only volumeMounts; read the other fields through getInfo().

The echo rules of the other fields are on their pages: network fields on Network, allowPublicTraffic and maskRequestHost on Application ports, and volumeMounts on Volumes.

Notes

  • The actual state and expiration time of a sandbox are those returned by native API queries.

Next steps

  • Commands and files: run commands and transfer files in a sandbox.
  • Volumes: keep data across pauses and after a sandbox is deleted.
  • Network: control outbound access.
  • Expiration: how expiration works for Workspaces.

On this page