Isorun Docs
SDKs

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

Terminal
npm install isorun

Authenticate

Terminal
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

TypeScript
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

TypeScript
new Isorun({ apiKey?: string })
OptionDefaultNotes
apiKeyISORUN_API_KEY envThrows if neither is set.

Properties

  • apiUrl: string, the resolved runner endpoint, useful when building external URLs.

Methods

MethodReturnsDescription
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()voidRelease the connection pool so the process can exit cleanly.

create(options?)

TypeScript
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().

TypeScript
const profiles = await isorun.networkProfiles()
// [{ name: 'openai', description?, allow: string[], deny: string[] }, ...]

usage()

Live usage and cost summary for the account.

TypeScript
const u = await isorun.usage()
// { activeSandboxes, historySandboxes, activeCostCents, historyCostCents,
//   totalCostCents, cpuSeconds, memSeconds, asOf }

history()

Past (destroyed) sandbox runs, newest first.

TypeScript
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?)

TypeScript
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)

TypeScript
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()

TypeScript
const meta = await sandbox.info()
// { id, status, image, vcpus, memMiB, diskMiB, createMs, createdAt }

snapshot() · isorun.restore(id)

TypeScript
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?)

TypeScript
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()

TypeScript
await sandbox.hibernate() // pauses; releases active runtime resources
// ... later ...
await sandbox.resume()    // back to running, same id, same state

Filesystem, memory, and processes survive.

Established outbound TCP connections don't survive hibernate. Reconnect any long-lived connection after resume().

setTimeout(seconds)

TypeScript
await sandbox.setTimeout(900) // extend auto-destroy timer

Use as a keep-alive when handing the sandbox to a long-running workflow.

url(port, path?)

TypeScript
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()

TypeScript
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.

TypeScript
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:

Terminal
npm install @anthropic-ai/sdk

Environment variable

VariablePurpose
ISORUN_API_KEYAPI 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() in finally.
  • 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

On this page