TypeScript SDK
Official Node.js client for sandbox lifecycle, command execution, file I/O, snapshots, fork, hibernate, and port exposure.
The isorun package is the canonical client for the Isorun API. ESM only, Node 20+.
Install
npm install isorunAuthenticate
export ISORUN_API_KEY="isorun_live_..."The runner endpoint is derived from the region segment in your key (isorun_live_us_... → https://run-us.isorun.ai), so there's nothing to configure.
Quickstart
import { Isorun } from 'isorun'
const isorun = new Isorun()
const sandbox = await isorun.create({ image: 'node:22-slim' })
try {
const { stdout } = await sandbox.exec('node -v')
console.log(stdout) // v22.x.x
} finally {
await sandbox.destroy()
}Isorun
new Isorun({ apiKey?: string })| Option | Default | Notes |
|---|---|---|
apiKey | ISORUN_API_KEY env | Throws if neither is set. |
Properties
apiUrl: string, the resolved runner endpoint, useful when building external URLs.
Methods
| Method | Returns | Description |
|---|---|---|
create(options?) | Promise<Sandbox> | Boot a new sandbox. |
get(id) | Promise<Sandbox | null> | Look up an existing sandbox; null on 404. |
list() | Promise<Sandbox[]> | All active sandboxes for the API key. |
restore(snapshotId) | Promise<Sandbox> | Restore from a snapshot. |
listSnapshots() | Promise<Snapshot[]> | List your snapshots. |
deleteSnapshot(id) | Promise<void> | Delete one snapshot. |
networkProfiles() | Promise<NetworkProfile[]> | List the named egress profiles available on the runner. |
usage() | Promise<UsageSummary> | Live usage and cost summary for the account. |
history() | Promise<SandboxHistoryEntry[]> | Past (destroyed) sandbox runs, newest first. |
close() | void | Release the connection pool so the process can exit cleanly. |
create(options?)
const sandbox = await isorun.create({
image: 'python:3.12-slim', // any supported OCI image; default: 'node:22-slim'
vcpus: 1, // default 1
memMiB: 1024, // default 1024
diskMiB: 4096, // scratch disk; wiped on destroy
timeoutSec: 300, // auto-destroy after N idle seconds
})networkProfiles()
Lists the named egress profiles you can pass as networkProfile on create().
const profiles = await isorun.networkProfiles()
// [{ name: 'openai', description?, allow: string[], deny: string[] }, ...]usage()
Live usage and cost summary for the account.
const u = await isorun.usage()
// { activeSandboxes, historySandboxes, activeCostCents, historyCostCents,
// totalCostCents, cpuSeconds, memSeconds, asOf }history()
Past (destroyed) sandbox runs, newest first.
const runs = await isorun.history()
// [{ id, image, vcpus, memMiB, createMs, createdAt, destroyedAt,
// uptimeMs, cpuMs, memPeakBytes, costCents }, ...]Sandbox
A Sandbox is the handle to a running microVM.
Properties
id: string, unique sandbox ID (run...).createMs: number, server-side create duration in ms.image: string, resolved image name.
Methods
exec(command, timeoutSec?)
const { exitCode, stdout, stderr } = await sandbox.exec('pytest -q', 180)
if (exitCode !== 0) console.error(stderr)Runs command in the guest. timeoutSec defaults to 30. Stdout and stderr are buffered and returned together.
writeFile(path, content) · readFile(path) · readdir(path)
await sandbox.writeFile('/app/config.json', JSON.stringify({ env: 'prod' }))
const text = await sandbox.readFile('/app/config.json')
const entries = await sandbox.readdir('/app')content accepts a string or Buffer. readFile returns UTF-8.
info()
const meta = await sandbox.info()
// { id, status, image, vcpus, memMiB, diskMiB, createMs, createdAt }snapshot() · isorun.restore(id)
const snap = await sandbox.snapshot()
// later, or elsewhere:
const restored = await isorun.restore(snap.id)snap is { id, runId, sizeBytes, createdAt }. Snapshots persist until deleteSnapshot().
fork(count?)
const children = await sandbox.fork(5) // 5 clones of the running sandbox
await Promise.all(children.map((c) => c.exec('python3 evaluate.py')))Each child inherits filesystem + memory state at fork time and runs independently. Default count is 1.
hibernate() · resume()
await sandbox.hibernate() // pauses; releases active runtime resources
// ... later ...
await sandbox.resume() // back to running, same id, same stateFilesystem, memory, and processes survive.
Established outbound TCP connections don't survive hibernate. Reconnect any long-lived connection after resume().
setTimeout(seconds)
await sandbox.setTimeout(900) // extend auto-destroy timerUse as a keep-alive when handing the sandbox to a long-running workflow.
url(port, path?)
const cdp = sandbox.url(9222)
const api = sandbox.url(8080, '/health')Returns the public HTTPS URL that proxies to a port your in-sandbox service is listening on. Synchronous, no network call.
url() returns the address but does no network I/O. The *.isorun.app URL embeds the sandbox's unguessable run ID and is itself the credential, so no header is needed. Treat the URL as a secret.
destroy()
const stats = await sandbox.destroy()
// { status, cpuMs, memPeakBytes, uptimeMs, costCents }Frees the sandbox, returns measured usage. Billing is computed from uptimeMs.
Claude Managed Agents
The SDK ships a self-hosted adapter for Anthropic Claude Managed Agents. Each Anthropic session is bound to its own sandbox for the lifetime of the session.
import { Isorun } from 'isorun'
import { runOrchestrator } from 'isorun/claude-agents/orchestrator'
await runOrchestrator({
isorun: new Isorun(),
environmentId: 'env_...', // from Anthropic Console
environmentKey: 'sk-ant-oat01-...', // self-hosted environment key
image: 'docker.io/isorun/claude-agents:0.4.3',
vcpus: 2,
memMiB: 4096,
})@anthropic-ai/sdk is an optional peer dependency, install it if you use this entry point:
npm install @anthropic-ai/sdkEnvironment variable
| Variable | Purpose |
|---|---|
ISORUN_API_KEY | API key (used when not passed to the constructor). |
Errors
All methods throw on non-2xx responses. The error message includes the HTTP status and the first 200 bytes of the response body, so you can distinguish 401 from 429 from 500 without extra plumbing.
Production checklist
- Always call
destroy()infinally. - Set explicit
exec()timeouts. - Log sandbox IDs alongside your request / job IDs for correlation.
- Call
isorun.close()to release the pool when your process exits.
Next steps
- Create and execute, the default runtime loop.
- Lifecycle and hibernation, the full state model behind these methods.
- API reference, the underlying REST endpoints.