Skip to content

SDK COMPATIBILITY MATRIX

E2B × CubeSandbox

Same workflow, not identical behavior.

Compare public SDK methods by name, see what works unchanged, and find the Cube alternative when behavior differs.

Result All passedTested releases 1.0.0 – 2.62.0Latest validated 2.62.0Recommended ≥ 2.15.0

Python SDK quick start

Use the E2B Python SDK for existing E2B code, or the native CubeSandbox Python SDK for Cube APIs. Install and configure them as follows:

pip install "e2b==2.29.5"
pip install cubesandbox

export CUBE_API_URL="http://127.0.0.1:3000"
export CUBE_API_KEY="e2b_000000"
export CUBE_TEMPLATE_ID="tpl-xxx"
export E2B_API_URL="http://127.0.0.1:3000"
export E2B_API_KEY="e2b_000000"
Compatible7
Partial14
Alternative3
Not available6
Cube extension5

01 · VERSIONS

Every E2B release, tested

Each E2B Python SDK release from 1.0.0 through 2.62.0 was run against the full compatibility suite. Hover a block for its verdict; the bands below explain every judgment.

Pass · 95Partial · 8Incompatible · 53
1.0.0 · Incompatible
1.0.1 · Incompatible
1.0.2 · Incompatible
1.0.3 · Incompatible
1.0.4 · Incompatible
1.0.5 · Incompatible
1.0.6 · Incompatible
1.1.0 · Incompatible
1.2.0 · Incompatible
1.2.1 · Incompatible
1.3.0 · Incompatible
1.3.1 · Incompatible
1.3.2 · Incompatible
1.3.3 · Incompatible
1.3.4 · Incompatible
1.3.5 · Incompatible
1.4.0 · Incompatible
1.5.0 · Incompatible
1.5.1 · Incompatible
1.5.2 · Incompatible
1.5.3 · Incompatible
1.5.4 · Incompatible
1.5.5 · Incompatible
1.5.6 · Incompatible
1.6.0 · Partial
1.7.0 · Partial
1.7.1 · Partial
1.8.0 · Partial
1.9.0 · Partial
1.10.0 · Partial
1.11.0 · Partial
1.11.1 · Partial
2.0.0 · Incompatible
2.0.1 · Incompatible
2.0.2 · Incompatible
2.1.0 · Incompatible
2.1.1 · Incompatible
2.1.2 · Incompatible
2.1.3 · Incompatible
2.1.4 · Incompatible
2.1.5 · Incompatible
2.2.0 · Incompatible
2.2.1 · Incompatible
2.2.2 · Incompatible
2.2.3 · Incompatible
2.2.4 · Incompatible
2.2.5 · Incompatible
2.2.6 · Incompatible
2.2.7 · Incompatible
2.3.0 · Incompatible
2.3.1 · Incompatible
2.3.2 · Incompatible
2.3.3 · Incompatible
2.3.4 · Incompatible
2.3.5 · Incompatible
2.3.6 · Incompatible
2.4.0 · Incompatible
2.4.1 · Incompatible
2.4.2 · Incompatible
2.4.3 · Incompatible
2.5.0 · Incompatible
2.6.0 · Pass
2.6.1 · Pass
2.6.2 · Pass
2.6.3 · Pass
2.6.4 · Pass
2.7.0 · Pass
2.8.0 · Pass
2.8.1 · Pass
2.9.0 · Pass
2.9.1 · Pass
2.10.0 · Pass
2.10.1 · Pass
2.10.2 · Pass
2.11.0 · Pass
2.12.0 · Pass
2.12.1 · Pass
2.12.2 · Pass
2.13.0 · Pass
2.13.1 · Pass
2.13.2 · Pass
2.13.3 · Pass
2.14.0 · Pass
2.14.1 · Pass
2.15.0 · Pass
2.15.1 · Pass
2.15.2 · Pass
2.15.3 · Pass
2.16.0 · Pass
2.17.0 · Pass
2.18.0 · Pass
2.19.0 · Pass
2.20.0 · Pass
2.20.1 · Pass
2.20.2 · Pass
2.20.3 · Pass
2.21.0 · Pass
2.21.1 · Pass
2.22.0 · Pass
2.23.0 · Pass
2.23.1 · Pass
2.24.0 · Pass
2.25.0 · Pass
2.25.1 · Pass
2.26.0 · Pass
2.27.0 · Pass
2.27.1 · Pass
2.28.0 · Pass
2.28.1 · Pass
2.28.2 · Pass
2.29.0 · Pass
2.29.1 · Pass
2.29.2 · Pass
2.29.3 · Pass
2.29.4 · Pass
2.29.5 · Pass
2.29.6 · Pass
2.30.0 · Pass
2.31.0 · Pass
2.32.0 · Pass
2.32.1 · Pass
2.33.0 · Pass
2.34.0 · Pass
2.35.0 · Pass
2.36.0 · Pass
2.37.0 · Pass
2.37.1 · Pass
2.38.0 · Pass
2.39.0 · Pass
2.39.1 · Pass
2.40.0 · Pass
2.41.0 · Pass
2.42.0 · Pass
2.43.0 · Pass
2.44.0 · Pass
2.45.0 · Pass
2.45.1 · Pass
2.46.0 · Pass
2.46.4 · Pass
2.48.0 · Pass
2.49.0 · Pass
2.49.1 · Pass
2.50.0 · Pass
2.51.0 · Pass
2.52.0 · Pass
2.52.1 · Pass
2.53.1 · Pass
2.55.0 · Pass
2.55.1 · Pass
2.56.0 · Pass
2.57.0 · Pass
2.58.0 · Pass
2.59.0 · Pass
2.60.0 · Pass
2.61.0 · Pass
2.62.0 · Pass
1.0.02.62.0
RangeVerdictSuiteReleasesNotes
2.15.0 – 2.62.0PassAll passed72

The full suite passes.

2.6.0 – 2.14.1PassPartially passed23

Passes after triage — the remaining failures are features those SDK versions lack, not platform issues.

1.6.0 – 1.11.1PartialPartially passed8

Create, commands, files, and queries work; those SDK lines simply lack pause, network, and other newer options.

2.0.0 – 2.5.0IncompatibleFailed29

The suite does not pass on this range. Use 2.6.0 or later.

1.0.0 – 1.5.6IncompatibleFailed24

The suite does not pass on this range. For basics only, 1.6.0+ works.

  1. A few releases fail a small number of cases; each was checked case by case, and every remaining failure comes from the SDK itself or the test environment, never from Cube.
  2. run_code needs a matching e2b-code-interpreter: cores 2.38+ do not pair with interpreter 2.9.0, so use a 2.37.1 or older core.

02 · API MATRIX

SDK API matrix

Compatibility is assessed at the public method level. A matching name does not imply matching defaults, return types, or side effects.

All 156 releases were tested. Pin e2b 2.15.0 or later and everything passes; for run_code, pair the interpreter with a 2.37.1 or older core.

Examples run against Cube with a validated E2B Python SDK. Set E2B_API_KEY and CUBE_TEMPLATE_ID first. "Not available" entries show calls Cube does not implement.

Sandbox lifecycle

10
Sandbox.create()
Create a new isolated sandbox from a template.
Partial
Creates sandboxes normally. Not supported: autoPauseMemory=false — Cube always keeps the memory snapshot, so the v2 flag is rejected. The E2B SDK also never reads CUBE_TEMPLATE_ID; pass the template explicitly.
View example ↓Hide example ↑
import os
from e2b import Sandbox

# The context manager kills the sandbox when the block exits.
with Sandbox.create(template=os.environ["CUBE_TEMPLATE_ID"], timeout=60) as sandbox:
    print(sandbox.sandbox_id)
Sandbox.connect()
Attach an SDK client to an existing sandbox.
Partial
The normal connect flow works unchanged. The one difference is what timeout means: E2B sets a fixed deadline (the sandbox dies at that moment, active or not), Cube sets an idle window (it is reclaimed only after N idle seconds; activity keeps it alive). connect() only extends in both SDKs — use set_timeout() to replace it. -1 is rejected by the E2B v2 API even though Cube supports never-timing-out.
View example ↓Hide example ↑
import os
from e2b import Sandbox

sandbox = Sandbox.create(template=os.environ["CUBE_TEMPLATE_ID"], timeout=120)
try:
    connected = Sandbox.connect(sandbox.sandbox_id, timeout=60)
    print(connected.commands.run("echo connected").stdout)
finally:
    sandbox.kill()
Sandbox.list()
Page through sandboxes visible to the project.
Partial
Listing and the state/metadata filters work unchanged. The one difference is the result shape: Cube returns one plain list, so ordering and start-time/template filters are not available.
View example ↓Hide example ↑
from e2b import Sandbox

paginator = Sandbox.list(limit=10)
while paginator.has_next:
    for info in paginator.next_items():
        print(info.sandbox_id, info.state)
sandbox.get_info()
Read identity, state, resources, and timestamps.
Compatible
Core fields align, including the template name E2B reads. Cube additionally exposes disk size and finer-grained states.
View example ↓Hide example ↑
import os
from e2b import Sandbox

with Sandbox.create(template=os.environ["CUBE_TEMPLATE_ID"]) as sandbox:
    info = sandbox.get_info()
    print(info.sandbox_id, info.state, info.started_at)
sandbox.is_running()
Check whether a sandbox is currently reachable.
Compatible
Works the same as E2B — checks whether the sandbox is currently reachable.
View example ↓Hide example ↑
import os
from e2b import Sandbox

with Sandbox.create(template=os.environ["CUBE_TEMPLATE_ID"]) as sandbox:
    print("running:", sandbox.is_running())
sandbox.kill()
Permanently stop and remove a sandbox.
Partial
Destroys the sandbox. Not supported: returning False for a missing ID — Cube raises a not-found error instead.
View example ↓Hide example ↑
import os
from e2b import Sandbox

sandbox = Sandbox.create(template=os.environ["CUBE_TEMPLATE_ID"])
sandbox_id = sandbox.sandbox_id
removed = sandbox.kill()
print(sandbox_id, removed)
sandbox.pause()
Persist a sandbox so it can be resumed later.
Partial
Pauses and keeps memory. Not supported: keep_memory=False (filesystem-only pause) — Cube always snapshots memory.
View example ↓Hide example ↑
import os
from e2b import Sandbox

sandbox = Sandbox.create(template=os.environ["CUBE_TEMPLATE_ID"])
sandbox_id = sandbox.sandbox_id
sandbox.pause()  # Preserve state for a later resume.

resumed = Sandbox.connect(sandbox_id)
print(resumed.commands.run("echo resumed").stdout)
resumed.kill()
sandbox.set_timeout()
Replace the sandbox lifecycle timeout.
Partial
Replaces the current timeout. Not supported: negative values in the E2B API — Cube treats -1 as a never-expiring window, while E2B rejects it.
View example ↓Hide example ↑
import os
from e2b import Sandbox

with Sandbox.create(template=os.environ["CUBE_TEMPLATE_ID"], timeout=60) as sandbox:
    # Replace the current timeout with five minutes.
    sandbox.set_timeout(300)
    print(sandbox.get_info().end_at)
sandbox.update_network()
Atomically replace outbound network rules.
Partial
Replaces the whole policy. Not supported: egress_proxy, https_ports, and IAM transforms; Cube adds ordered L7 rules instead.
View example ↓Hide example ↑
import os
from e2b import Sandbox

with Sandbox.create(template=os.environ["CUBE_TEMPLATE_ID"]) as sandbox:
    # Omitted fields are cleared because this replaces the policy.
    sandbox.update_network({"deny_out": ["10.0.0.0/8"]})
    print("network policy updated")
sandbox.get_metrics()
Read recent CPU, memory, and disk samples.
Not available
Not implemented; Cube exports its own metrics through Cubelet.
View example ↓Hide example ↑
import os
from e2b import Sandbox

with Sandbox.create(template=os.environ["CUBE_TEMPLATE_ID"]) as sandbox:
    sandbox.commands.run("python -c 'sum(range(1000000))'")
    for sample in sandbox.get_metrics():
        print(sample)

Commands, files & PTY

10
sandbox.commands.run()
Run a shell command inside the sandbox.
Compatible
Command, cwd, environment, user, stdout/stderr, exit code, and execution timeout work through the compatible envd process protocol.
View example ↓Hide example ↑
import os
from e2b import Sandbox

with Sandbox.create(template=os.environ["CUBE_TEMPLATE_ID"]) as sandbox:
    result = sandbox.commands.run(
        "python -c 'print(6 * 7)'",
        timeout=30,
    )
    print(result.stdout, result.exit_code)
commands.connect()
Reconnect to a running background command.
Partial
Commands work normally. Not supported: reconnecting to a background command — Cube Commands exposes run only; reconnect through PTY instead.
View example ↓Hide example ↑
import os
from e2b import Sandbox

with Sandbox.create(template=os.environ["CUBE_TEMPLATE_ID"]) as sandbox:
    process = sandbox.commands.run("sleep 2; echo done", background=True)
    pid = process.pid
    process.disconnect()  # The process keeps running in the sandbox.
    result = sandbox.commands.connect(pid).wait()
    print(result.stdout)
commands.listkillsend_stdin
Inspect and control running processes.
Not available
Not exposed; use PTY control or commands.run instead.
View example ↓Hide example ↑
import os
from e2b import Sandbox

with Sandbox.create(template=os.environ["CUBE_TEMPLATE_ID"]) as sandbox:
    process = sandbox.commands.run("cat", background=True, stdin=True)
    sandbox.commands.send_stdin(process.pid, "hello\n")
    print([item.pid for item in sandbox.commands.list()])
    sandbox.commands.kill(process.pid)
files.readwritewrite_files
Transfer text or binary file content.
Compatible
Common text/binary transfer and batch-write shapes are supported over the compatible filesystem protocol.
View example ↓Hide example ↑
import os
from e2b import Sandbox
from e2b.sandbox.filesystem.filesystem import WriteEntry

with Sandbox.create(template=os.environ["CUBE_TEMPLATE_ID"]) as sandbox:
    sandbox.files.write("/tmp/one.txt", "one")
    sandbox.files.write_files([
        WriteEntry(path="/tmp/two.txt", data="two"),
        WriteEntry(path="/tmp/three.bin", data=b"three"),
    ])
    print(sandbox.files.read("/tmp/one.txt"))
files.listexistsremoverenamemake_dir
Manage files and directory structure.
Compatible
The common directory and file-management workflow is aligned and covered by dual-backend tests.
View example ↓Hide example ↑
import os
from e2b import Sandbox

with Sandbox.create(template=os.environ["CUBE_TEMPLATE_ID"]) as sandbox:
    sandbox.files.make_dir("/tmp/demo")
    sandbox.files.write("/tmp/demo/a.txt", "hello")
    print(sandbox.files.exists("/tmp/demo/a.txt"))
    print([entry.name for entry in sandbox.files.list("/tmp/demo")])
    sandbox.files.rename("/tmp/demo/a.txt", "/tmp/demo/b.txt")
    sandbox.files.remove("/tmp/demo")
files.get_info()
Read metadata for a file or directory.
Alternative
The capability exists under a different Cube Python name and returns a dict rather than E2B's typed object.
View example ↓Hide example ↑
import os
from e2b import Sandbox

with Sandbox.create(template=os.environ["CUBE_TEMPLATE_ID"]) as sandbox:
    sandbox.files.write("/tmp/info.txt", "hello")
    info = sandbox.files.get_info("/tmp/info.txt")
    print(info.name, info.type, info.path)
files.watch_dir()
Observe filesystem changes in a directory.
Partial
Streams directory changes. Not supported: the exact E2B handle lifecycle, event types, and callback API — the two SDKs differ here.
View example ↓Hide example ↑
import os
from e2b import Sandbox

with Sandbox.create(template=os.environ["CUBE_TEMPLATE_ID"]) as sandbox:
    sandbox.files.make_dir("/tmp/watched")
    watcher = sandbox.files.watch_dir("/tmp/watched")
    try:
        sandbox.files.write("/tmp/watched/new.txt", "hello")
        print(watcher.get_new_events())
    finally:
        watcher.stop()
sandbox.pty.*
Create and control an interactive terminal.
Compatible
Create, connect, resize, input, kill, disconnect, and wait are available. Callback and exception types remain SDK-specific.
View example ↓Hide example ↑
import os
from e2b import PtySize, Sandbox

with Sandbox.create(template=os.environ["CUBE_TEMPLATE_ID"]) as sandbox:
    terminal = sandbox.pty.create(PtySize(rows=24, cols=80))
    sandbox.pty.send_stdin(terminal.pid, b"echo hello from PTY\n")
    sandbox.pty.resize(terminal.pid, PtySize(rows=30, cols=100))
    sandbox.pty.kill(terminal.pid)
sandbox.git.*
Perform common Git operations in a sandbox.
Alternative
Cube Python has no high-level Git facade. Git installed in the template can be driven through the command API.
View example ↓Hide example ↑
import os
from e2b import Sandbox

with Sandbox.create(template=os.environ["CUBE_TEMPLATE_ID"]) as sandbox:
    # The base sandbox-code template does not include Git.
    sandbox.commands.run(
        "apt-get update -qq && apt-get install -y -qq git",
        timeout=120,
    )
    sandbox.git.clone(
        "https://github.com/octocat/Hello-World.git",
        path="/tmp/hello-world",
        depth=1,
    )
    print(sandbox.git.status("/tmp/hello-world"))
sandbox.run_code()
Execute stateful code and collect rich results.
Partial
Runs stateful code with rich results. Not supported: version-skewed pairings — the e2b core and e2b-code-interpreter must match.
View example ↓Hide example ↑
import os
from e2b_code_interpreter import Sandbox

# Install e2b-code-interpreter and use its matching version.
with Sandbox.create(template=os.environ["CUBE_TEMPLATE_ID"]) as sandbox:
    execution = sandbox.run_code("x = 6 * 7; x")
    print(execution.results[0].text)

Snapshots, volumes & templates

6
createlistdelete_snapshot
Create, discover, and delete persistent snapshots.
Partial
Create, list, and delete work, including by name. Not supported: paginator-style listing — Cube returns a list plus a next-token tuple.
View example ↓Hide example ↑
import os
from e2b import Sandbox

with Sandbox.create(template=os.environ["CUBE_TEMPLATE_ID"]) as sandbox:
    sandbox.files.write("/tmp/state.txt", "snapshot me")
    snapshot = sandbox.create_snapshot(name="docs-example")

paginator = Sandbox.list_snapshots(name="docs-example")
while paginator.has_next:
    print([item.snapshot_id for item in paginator.next_items()])

Sandbox.delete_snapshot(snapshot.snapshot_id)
sandbox.fork()
Branch one running sandbox into multiple copies.
Compatible
Native on Cube with the same semantics as E2B.
View example ↓Hide example ↑
import os
from e2b import Sandbox

with Sandbox.create(template=os.environ["CUBE_TEMPLATE_ID"]) as parent:
    parent.files.write("/tmp/shared.txt", "before fork")
    children = parent.fork(count=2, timeout=60)
    for child in children:
        if isinstance(child, Exception):
            print("fork failed:", child)
            continue
        print(child.files.read("/tmp/shared.txt"))
        child.kill()
Volume.createconnectlistdestroy
Manage persistent volumes independently of sandboxes.
Partial
CRUD and mounts work. Not supported: E2B-style driver names — Cube uses operator-installed drivers, and adds optional names and per-mount read-only mode.
View example ↓Hide example ↑
from uuid import uuid4
from e2b import Volume

volume = Volume.create(f"docs-{uuid4().hex[:8]}")
connected = Volume.connect(volume.volume_id)
print(connected.volume_id)
print([(item.volume_id, item.name) for item in Volume.list()])
Volume.destroy(volume.volume_id)
volume.read_filewrite_filelist
Access files directly through a volume service.
Not available
Cube has no standalone volume-content service; mount it and use sandbox.files.
View example ↓Hide example ↑
from uuid import uuid4
from e2b import Volume

volume = Volume.create(f"docs-{uuid4().hex[:8]}")
try:
    volume.write_file("/hello.txt", "hello", force=True)
    print(volume.read_file("/hello.txt"))
    print([entry.name for entry in volume.list("/")])
finally:
    Volume.destroy(volume.volume_id)
Template.build() fluent API
Define and build a reusable sandbox template.
Alternative
Not wire-compatible; Cube builds templates from OCI images with its own tooling.
View example ↓Hide example ↑
from uuid import uuid4
from e2b import Template

template = (
    Template()
    .from_python_image("3.12")
    .run_cmd("python --version")
)
# Building can take several minutes and creates a project template.
Template.build(template, f"docs-python-{uuid4().hex[:8]}")
Sandbox.create(template=snapshot_id)
Create or restore a sandbox from a reusable snapshot.
Partial
Both SDKs can create a new sandbox from a snapshot ID. With E2B snapshots are always portable across the hosted fleet; with Cube, cross-node placement needs an S3-backed, remotely ready snapshot on a host-compatible node — same-node restores work with local storage.
View example ↓Hide example ↑
import os
from e2b import Sandbox

with Sandbox.create(template=os.environ["CUBE_TEMPLATE_ID"]) as source:
    source.files.write("/tmp/state.txt", "portable state")
    snapshot = source.create_snapshot()

try:
    # E2B snapshots act as templates; any node can restore them.
    with Sandbox.create(template=snapshot.snapshot_id) as restored:
        print(restored.files.read("/tmp/state.txt"))
finally:
    Sandbox.delete_snapshot(snapshot.snapshot_id)

Platform services

4
sandbox.get_mcp_token()
Retrieve the token for an enabled MCP gateway.
Partial
Works with the Cube SDKs, which start the gateway inside the sandbox and return the URL and token. Not supported: the E2B SDK's own token endpoint — use the Cube SDKs for MCP.
View example ↓Hide example ↑
import os
from e2b import Sandbox

mcp = {
    "github/modelcontextprotocol/servers": {
        "run_cmd": "npx -y @modelcontextprotocol/server-everything"
    }
}
with Sandbox.create(template=os.environ["CUBE_TEMPLATE_ID"], mcp=mcp) as sandbox:
    print(sandbox.get_mcp_token())
Sandbox.create(iam=...)
Give a sandbox short-lived workload identity.
Not available
E2B workload identity is not implemented; Cube keeps credentials outside the guest instead.
View example ↓Hide example ↑
import os
from e2b import Sandbox, Secret

identity = Secret.iam_token(
    audience="sts.amazonaws.com",
    token_type="JWT-SVID",
)
with Sandbox.create(template=os.environ["CUBE_TEMPLATE_ID"], iam={"tokens": {"aws": identity}}) as sandbox:
    print(sandbox.sandbox_id)
Secret.*
Create, rotate, list, and destroy project secrets.
Not available
Cube has no E2B Secrets API; secrets belong to the deployment or CubeEgress.
View example ↓Hide example ↑
from uuid import uuid4
from e2b import Secret

name = f"docs-{uuid4().hex[:8]}"
created = Secret.create(name, "initial-value")
Secret.update(name, "rotated-value")
print(Secret.get_info(name))  # Values are write-only.
print(Secret.list(limit=10).next_items())
Secret.destroy(created.secret_id)
AsyncSandboxasync resources
Use sandbox resources from async Python code.
Not available
Cube Python is synchronous; use the native Node.js or Go SDKs for async code.
View example ↓Hide example ↑
import os
import asyncio
from e2b import AsyncSandbox

async def main():
    sandbox = await AsyncSandbox.create(template=os.environ["CUBE_TEMPLATE_ID"])
    try:
        result = await sandbox.commands.run("echo async")
        print(result.stdout)
    finally:
        await sandbox.kill()

asyncio.run(main())

Cube extensions

5
sandbox.rollback()
Restore a running sandbox to an earlier snapshot.
Cube extension
Cube restores filesystem and memory in place while retaining the sandbox ID. E2B has snapshots and forks but no equivalent in-place rollback method.
View example ↓Hide example ↑
from cubesandbox import Sandbox

with Sandbox.create() as sandbox:
    sandbox.files.write("/tmp/value.txt", "v1")
    snapshot = sandbox.create_snapshot()
    try:
        sandbox.files.write("/tmp/value.txt", "v2")
        sandbox.rollback(snapshot.snapshot_id)
        print(sandbox.files.read("/tmp/value.txt"))
    finally:
        Sandbox.delete_snapshot(snapshot.snapshot_id)
Volume.create(driver=...)VolumeMount(read_only=True)
Select a volume backend and control attachment mode.
Cube extension
The shared volume workflow is E2B-compatible; these two options are Cube-only: picking an operator-installed volume driver and making a single attachment read-only.
View example ↓Hide example ↑
from cubesandbox import Sandbox, Volume, VolumeMount

# CUBE_VOLUME_DRIVER must name a configured Cube volume plugin.
volume = Volume.create("docs-data", driver=os.environ["CUBE_VOLUME_DRIVER"])
try:
    with Sandbox.create(
        volume_mounts={"/data": VolumeMount(volume, read_only=True)}
    ) as sandbox:
        print(sandbox.files.list("/data"))
finally:
    Volume.destroy(volume.volume_id)
sandbox.update_network(rules=...)
Apply advanced ordered L7 egress actions.
Cube extension
Cube adds ordered L7 rules: allow or deny by host, port, or path, plus audit and header injection.
View example ↓Hide example ↑
from cubesandbox import Action, Match, Rule, Sandbox

rule = Rule(
    name="allow-example-api",
    match=Match(host="api.example.com", path="/v1/"),
    action=Action(allow=True, audit="metadata"),
)
with Sandbox.create() as sandbox:
    sandbox.update_network({"rules": [rule]})
Sandbox.create(distribution_scope=...)
Constrain where a sandbox may be scheduled.
Cube extension
Cube can restrict eligible compute nodes or pin a sandbox to one node. E2B does not expose equivalent placement control in its public SDK.
View example ↓Hide example ↑
from cubesandbox import Sandbox

# Use a compute-node ID or host IP reported by CubeOps.
with Sandbox.create(
    distribution_scope=[os.environ["CUBE_COMPUTE_NODE"]]
) as sandbox:
    print(sandbox.sandbox_id)
GET /v1/metrics/resource
Expose native sandbox resource metrics to Prometheus.
Cube extension
Cubelet exports host and guest resource metrics separately for Prometheus.
View example ↓Hide example ↑
import os
from urllib.request import urlopen

cubelet_url = os.environ.get("CUBELET_URL", "http://127.0.0.1:9998")
url = f'{cubelet_url.rstrip("/")}/v1/metrics/resource'
with urlopen(url, timeout=5) as response:
    print(response.read().decode())

03 · CUBE API

REST API compatibility

One level below the SDK: e2b client endpoints against CubeAPI paths, parameters, responses, and error codes.

Sandboxes

14
POST/v2/sandboxesDiffers

Missing secure/iam inputs; the response is otherwise aligned (alias included).

GET/v2/sandboxesDiffers

state/metadata filters work; order, start-time, and template filters are missing.

GET/sandboxes/{id}Aligned

All required fields present (endAt, alias, disk size).

DELETE/sandboxes/{id}Differs

Same route; e2b returns False on 404 while Cube raises not-found.

POST/v2/sandboxes/{id}/connectDiffers

Missing on_resume — restore always resumes the saved state.

POST/sandboxes/{id}/pauseIncompatible

keep_memory=false is rejected — pause always keeps the memory snapshot.

POST/sandboxes/{id}/timeoutAligned

Identical; -1 means never timing out.

POST/sandboxes/{id}/forkAligned

Identical per-fork results from one snapshot.

POST/sandboxes/{id}/snapshotsIncompatible

mode="filesystem" is rejected — snapshots always keep memory.

PUT/sandboxes/{id}/networkDiffers

Missing egress_proxy and https_ports.

GET/sandboxes/{id}/metricsMissing

No such route; use Cubelet metrics instead.

POST/sandboxes/{id}/resumeCube only

Cube only: explicit resume.

POST/sandboxes/{id}/rollbackCube only

Cube only: in-place rollback.

POST/sandboxes/{id}/cloneCube only

Cube only: clone a sandbox.

Snapshots

3
GET/snapshotsAligned

Name filter and paging work.

DELETE/templates/{id or name}Aligned

Deletes a snapshot by ID or name, returns bool; ambiguous names get 409.

DELETE/templates/{id}Aligned

Template deletion aligned.

Templates

10
GET/templatesDiffers

Flat list; missing public/builds fields.

GET/templates/aliases/{alias}Incompatible

Missing the aliases field; the e2b model fails to parse.

GET/templates/{id}Aligned

All fields present.

POST/templatesIncompatible

Different build models: e2b takes a Dockerfile DSL, Cube takes an image reference.

GET/v2/templatesMissing

No v2 template routes (tags).

POST/templates/tagsMissing

No tags model.

GET/templates/{id}/builds/{bid}/statusDiffers

Missing log_entries; adds progress/message.

GET/templates/{id}/builds/{bid}/logsCube only

Cube only: build logs.

POST/templates/{id}/rebuildCube only

Cube only: rebuild from the image.

PUT/templates/{id}/aliasCube only

Cube only: set alias.

Volumes

5
POST/volumesAligned

Aligned (name optional; response misses domain).

GET/volumesAligned

Aligned.

GET/volumes/{id}Aligned

Aligned (misses domain).

DELETE/volumes/{id}Aligned

Aligned; 404 returns False.

*/volumecontent/**Missing

The whole volume-content group (7 endpoints); mount the volume and use sandbox.files.

ENVD data plane

1
RPCprocess / filesystem / files / executeAligned

Commands, files, PTY, and code execution are all identical.

The data plane bypasses CubeAPI: CubeProxy forwards straight to envd inside the sandbox (compiled from upstream e2b-dev/infra), so request bodies, streaming frames, and error frames are identical; fixed-address traffic is routed via E2b-Sandbox-* headers.