SDK reference
The Hotcell TypeScript SDK (@hotcell/sdk), Python SDK (hotcell on PyPI) and Mastra provider: clients, sandbox methods, sessions and code contexts.
Both SDKs are thin clients for the REST API. The TypeScript SDK has no runtime dependencies and mirrors the Cloudflare Sandbox SDK surface. The Python SDK uses only the standard library and mirrors the TypeScript SDK in snake_case.
| TypeScript | Python | |
|---|---|---|
| Package | @hotcell/sdk |
hotcell |
| Install | npm install @hotcell/sdk |
pip install hotcell |
| Runtime | Node.js 18+ | Python 3.9+ |
Connecting
import { HotcellClient } from "@hotcell/sdk";
const client = new HotcellClient({ endpoint: "http://127.0.0.1:4750", apiKey: process.env.HOTCELL_API_KEY });
from hotcell import HotcellClient
client = HotcellClient(endpoint="http://127.0.0.1:4750", api_key=None)
Both resolve settings in the same order:
- The explicit
endpointand API key arguments. HOTCELL_ENDPOINT(defaulthttp://127.0.0.1:4750) andHOTCELL_API_KEY.- For a loopback endpoint only, the key the local daemon generated in
${HOTCELL_HOME:-~/.hotcell}/api-key.
The key is sent as Authorization: Bearer <key>.
TypeScript
HotcellClient
| Method | Returns | Description |
|---|---|---|
getSandbox(id?, options?) |
Sandbox |
Attach to an existing sandbox by id, or create one when id is omitted. |
list() |
SandboxInfo[] |
All sandboxes. |
health() |
{ ok, driver, version? } |
GET /healthz. |
info() |
DaemonInfo |
Driver, available drivers, default image, ports, providers, cost rates, auth. |
capacity() |
CapacitySnapshot |
Memory and CPU budget, committed, available, how many more fit, warm-pool spares. |
listBackups() |
BackupInfo[] |
All backups. |
deleteBackup(backupId) |
void |
Delete a backup. |
CreateOptions
| Field | Type | Description |
|---|---|---|
image |
string |
OCI image. |
driver |
string |
container, firecracker or applevz. |
env |
Record<string, string> |
Sandbox env. |
labels |
Record<string, string> |
Labels. |
persist |
boolean |
Back /workspace with a volume. Default true. |
sleepAfter |
number |
Idle auto-pause in ms; 0 disables. |
egress |
boolean | EgressPolicy |
Wire the gateway; pass a policy to scope the token. |
egressSpendCapUsd |
number |
Per-sandbox LLM spend ceiling. |
setup |
string[] |
Commands run once, in order, after start. |
repo, repoRef |
string |
Clone a repo into /workspace. |
branch |
string |
New branch after the clone; "auto" names it. |
networked |
boolean |
Firecracker only: NAT network interface. |
memoryMb, cpus, pidsLimit |
number |
Hard caps. |
detach |
boolean |
Provision in the background; getSandbox still resolves only when the sandbox is running. |
onStatus |
(status, info) => void |
Called on each status or phase change during a detached create. |
EgressPolicy fields: expiresAt, ttlMs, spendCapUsd, rateLimit: { calls?, tokens?, windowMs }, models, providers.
Sandbox
| Method | Description |
|---|---|
id, status, getInfo() |
Identity and the last-known SandboxInfo. |
exec(cmd, { cwd?, env?, sessionId?, onOutput? }) |
Run to completion. Returns { stdout, stderr, exitCode, success }. |
execStream(cmd, options) |
Async generator of { type: "stdout" | "stderr", data } and { type: "exit", exitCode }. |
stop(), start(), pause() |
Lifecycle. |
destroy() |
Destroy the sandbox and its volume. |
writeFile(path, content, { mode? }), readFile(path) |
UTF-8 file I/O. |
mkdir(path, { parents? }), listFiles(path) |
Directories. |
watch(path = "/workspace", { intervalMs? }) |
Async generator of { type: "created" | "modified" | "deleted", path }. |
startProcess(cmd, { cwd?, env? }), listProcesses() |
Background processes. |
killProcess(procId, signal?) |
Default SIGTERM. |
streamLogs(procId, { follow? }) |
Async generator of log strings. |
waitForPort(port, { timeoutMs?, intervalMs?, host? }) |
Resolves true when listening. |
exposePort(port, { token? }), unexposePort(port), listExposedPorts() |
Preview URLs. |
setEnvVars(env), getEnvVars() |
Sandbox env. |
createSession({ id?, cwd?, env? }), listSessions() |
Sessions. |
createCodeContext({ language? }), listCodeContexts() |
Code interpreter contexts. |
runCode(code, { context?, language?, timeoutMs? }) |
Run a cell. Returns { stdout, stderr, results, error }. |
createBackup(), restoreBackup(backupId), listBackups() |
Workspace backups. |
metrics(), metricsHistory() |
{ status, live, usage, cost } and recent samples. |
createEgressToken(policy?), listEgressTokens(), revokeEgressToken(token) |
Gateway tokens. |
Session and CodeContext
| Class | Methods |
|---|---|
Session |
sessionId, exec, execStream, setEnvVars, destroy |
CodeContext |
contextId, language, runCode(code, { timeoutMs? }), destroy |
Errors
A non-2xx response throws Error("hotcell <METHOD> <path> -> <status>: <body>"). If the daemon can't be reached, the error has code: "DAEMON_UNREACHABLE".
Example
const sandbox = await client.getSandbox(undefined, {
repo: "https://github.com/me/app",
setup: ["npm install"],
egress: { spendCapUsd: 5, models: ["gpt-4o"] },
detach: true,
onStatus: (s, info) => console.log(s, info.statusReason),
});
const ctx = await sandbox.createCodeContext({ language: "python" });
await ctx.runCode("x = 21");
console.log((await ctx.runCode("x * 2")).results[0].text); // "42"
await sandbox.destroy();
Python
from hotcell import HotcellClient
client = HotcellClient()
sandbox = client.get_sandbox(repo="https://github.com/me/app", setup=["pip install -e ."], detach=True)
result = sandbox.exec("python3 -c 'print(2 + 2)'")
print(result.stdout, result.exit_code) # "4\n" 0
sandbox.write_file("/workspace/hi.txt", "hello")
m = sandbox.metrics()
print(m.cost.total, m.usage.cpu_seconds)
sandbox.destroy()
HotcellClient
| Method | Description |
|---|---|
get_sandbox(id=None, *, image, env, labels, persist, sleep_after, egress, setup, repo, repo_ref, memory_mb, cpus, pids_limit, detach, on_status) |
Attach by id or create. All keyword arguments are optional. |
list() |
All sandboxes. |
health(), info() |
Daemon health and info as dicts. |
list_backups(), delete_backup(backup_id) |
Backups. |
A module-level get_sandbox(client, id=None, **options) matches the Cloudflare getSandbox shape.
Sandbox
id, status, info, exec, exec_stream, stop, start, destroy, metrics, metrics_history, write_file, read_file, mkdir, list_files, watch, start_process, list_processes, kill_process, stream_logs, wait_for_port, expose_port, unexpose_port, list_exposed_ports, set_env_vars, get_env_vars, create_session, list_sessions, create_backup, restore_backup, list_backups, create_code_context, list_code_contexts, run_code, create_egress_token, list_egress_tokens, revoke_egress_token.
Session: session_id, exec, exec_stream, set_env_vars, destroy. CodeContext: run_code, destroy.
A non-2xx response raises HotcellError.
Differences from the TypeScript SDK
In the current source, the Python SDK doesn't expose:
driver,branch,networkedoregress_spend_cap_usdonget_sandbox. Sandboxes use the daemon default driver.- An egress policy object.
egressis a boolean, andcreate_egress_token()takes no policy. pause()orcapacity().
Use the REST API or the TypeScript SDK for those.
Mastra
@hotcell/mastra provides HotcellSandbox, a Mastra Workspace sandbox provider. Use it where you would use E2BSandbox or ModalSandbox.
import { Agent, Workspace } from "@mastra/core";
import { HotcellSandbox } from "@hotcell/mastra";
const agent = new Agent({
name: "coder",
model: "openai/gpt-5",
workspace: new Workspace({ sandbox: new HotcellSandbox({ repo: "https://github.com/me/app" }) }),
});
await agent.generate("Add a /health route and run the tests.");
HotcellSandboxOptions: endpoint, apiKey, image, egress, repo, repoRef, setup, memoryMb, cpus, pidsLimit, sandboxId.
Source: packages/sdk, sdk/python, packages/mastra.