Sitelet https://createos.sh/docs/Sandbox/SDK/Reference/Sandbox/
Skip to content
LogoLogo

Sandbox

Sandbox is a stateful handle that owns one sandbox id and exposes every per-sandbox operation: command execution, file transfer, lifecycle transitions, ingress, egress, bandwidth, networks, disks, and SSH. You receive a handle from client.createSandbox() or client.getSandbox(); you can also use static helpers Sandbox.create() and Sandbox.connect() to skip constructing a client explicitly.

Mutating calls (lifecycle, patch, resize, …) refresh the handle's cached projection in place. Read the projection back via the data getter or convenience getters (id, status, ip, name).

Every method that reaches the control plane also throws CreateosSandboxServerError on a 5xx response and CreateosSandboxConnectionError on network failure. Per-method Throws lists only conditions specific to that call.


At a glance

  • Package: @nodeops-createos/sandbox (npm)
  • Import: import { createClient } from "@nodeops-createos/sandbox"
  • Base URL: https://api.sb.createos.sh (override with CREATEOS_SANDBOX_BASE_URL)
  • Auth: API key via the apiKey option or CREATEOS_SANDBOX_API_KEY

Static factories

Sandbox.create

static async create(
  request: CreateSandboxRequest,
  options?: CreateosSandboxClientOptions & CreateSandboxOptions,
): Promise<Sandbox>

Creates a sandbox without constructing a client first. Equivalent to new CreateosSandboxClient(options).createSandbox(request, options).

Parameters

NameTypeDescription
requestCreateSandboxRequestShape, rootfs, and other create-time fields. See Types.
options?CreateosSandboxClientOptions & CreateSandboxOptionsClient config (API key, base URL, hooks) merged with create options (wait, waitTimeoutMs).

Returns Promise<Sandbox>

Throws

Example

import { Sandbox } from "@nodeops-createos/sandbox";
 
const sandbox = await Sandbox.create({
  shape: "s-4vcpu-4gb",
  rootfs: "devbox:1",
});
try {
  const out = await sandbox.runCommand("node", ["--version"]);
  console.log(out.result.stdout);
} finally {
  await sandbox.destroy();
}

Sandbox.connect

static async connect(
  id: string,
  options?: CreateosSandboxClientOptions & RequestOptions,
): Promise<Sandbox>

Connects to an existing sandbox by id without constructing a client first. Equivalent to new CreateosSandboxClient(options).getSandbox(id, options).

Parameters

NameTypeDescription
idstringSandbox id (e.g. "sb-01h…").
options?CreateosSandboxClientOptions & RequestOptionsClient config merged with per-request options.

Returns Promise<Sandbox>

Throws

Example

import { Sandbox } from "@nodeops-createos/sandbox";
 
const sandbox = await Sandbox.connect("sb-01h…");
console.log(sandbox.status);

Properties

Getters over the handle's cached SandboxView projection. Call refresh() to re-sync from the server.

GetterTypeDescription
idstringSandbox id.
statusSandboxStatusCurrent lifecycle state: creating | running | pausing | paused | resuming | forking | error | destroying | destroyed | failed.
ipstring | undefinedVM private IP. undefined while the sandbox is still creating.
namestring | undefinedOptional user-supplied name.
dataSandboxViewThe full last-known projection. Returns the live internal object. Treat as read-only.
filesSandboxFilesFile transfer namespace. See Sandbox Files.

SandboxView additionally carries: vcpu, mem_mib, disk_mib, created_at, ingress_enabled, ingress_url_template?, running_at?, destroyed_at?, spawn_ms?, shape?, rootfs?, region?, egress?, envs?, ssh_pubkeys?, created_by?, bandwidth_ingress_bytes?, paused_at?, last_resumed_at?, forked_from?, auto_pause_after_seconds?.

Commands

For reconnectable commands and PTYs, use sandbox.processes. For desktop control, use sandbox.computer with a desktop-capable image.

runCommand

async runCommand(
  cmd: string,
  args?: string[],
  options?: ExecOptions,
): Promise<ExecResponse>

Runs a command to completion and returns its buffered output. ExecOptions is an alias for RequestOptions: pass timeoutMs, signal, retry, or headers to control the request.

Parameters

NameTypeDescription
cmdstringExecutable name or absolute path.
args?string[]Argument list. Default [].
options?ExecOptionsPer-request options (timeout, signal, retry).

Returns Promise<ExecResponse>: { result: ExecResult; exec_ms: number } where ExecResult is { stdout, stderr, exit_code, error? }.

Throws

Example

const { result } = await sandbox.runCommand("uname", ["-a"]);
console.log(result.stdout, result.exit_code);

streamCommand

async *streamCommand(
  cmd: string,
  args?: string[],
  options?: ExecOptions,
): AsyncGenerator<ExecStreamEvent>

Runs a command and yields discriminated union events that arrive over an NDJSON stream. Switch on event.type to handle each variant. Streaming requests are not retried.

Parameters

NameTypeDescription
cmdstringExecutable name or absolute path.
args?string[]Argument list. Default [].
options?ExecOptionsPer-request options.

Returns AsyncGenerator<ExecStreamEvent>

ExecStreamEvent union:

| { type: "stdout";    data: string }
| { type: "stderr";    data: string }
| { type: "exit";      exitCode: number }
| { type: "error";     message: string }
| { type: "heartbeat" }

Throws: same as runCommand.

Example

for await (const event of sandbox.streamCommand("tail", [
  "-f",
  "/var/log/syslog",
])) {
  switch (event.type) {
    case "stdout":
      process.stdout.write(event.data);
      break;
    case "stderr":
      process.stderr.write(event.data);
      break;
    case "exit":
      console.log("exit code:", event.exitCode);
      break;
    case "error":
      console.error("agent error:", event.message);
      break;
    case "heartbeat":
      /* keepalive */ break;
  }
}

sh

async sh(
  script: string,
  options?: ExecOptions & { label?: string },
): Promise<ExecResponse>

Runs a shell script via bash -lc and throws on non-zero exit. Use this instead of runCommand when a failure should abort the caller without inspecting exit codes by hand.

Parameters

NameTypeDescription
scriptstringShell script. Pipes, redirection, globbing, and && chains work.
options.label?stringTag included in the thrown error message.
Other optionsExecOptionstimeoutMs, signal, retry, headers.

Returns Promise<ExecResponse>

Throws

Example

await sandbox.sh("apt-get update -qq && apt-get install -y curl", {
  label: "apt",
  timeoutMs: 300_000,
});
const { result } = await sandbox.sh("curl -s https://api.ipify.org");
console.log(result.stdout);

Files

File transfer operations live on the files accessor, which returns a SandboxFiles instance scoped to this sandbox.

sandbox.files.upload("/path/in/sandbox", data);
sandbox.files.download("/path/in/sandbox");

See Sandbox Files for full signatures.

Lifecycle

pause

async pause(options?: RequestOptions): Promise<this>

Snapshots the sandbox to storage. The handle is updated to the pausing/paused projection. Combine with waitUntilPaused() to block until the snapshot completes.

Parameters: options?: RequestOptions (signal, headers, timeoutMs, retry).

Returns Promise<this>

Throws

Example

await sandbox.pause();
await sandbox.waitUntilPaused();

resume

async resume(options?: RequestOptions): Promise<this>

Restores a paused sandbox. The handle is updated to the resuming/running projection. Combine with waitUntilRunning() to block until the VM is ready.

Parameters: options?: RequestOptions.

Returns Promise<this>

Throws

Example

await sandbox.resume();
await sandbox.waitUntilRunning();

fork

async fork(request?: ForkSandboxRequest, options?: RequestOptions): Promise<Sandbox>

Clones a paused sandbox into a new independent sandbox. Returns a handle to the clone.

Parameters

NameTypeDescription
request?ForkSandboxRequestFork overrides (see below).
options?RequestOptionsPer-request options.

ForkSandboxRequest fields (all optional):

FieldTypeDescription
start_paused?booleanKeep the fork paused instead of auto-resuming.
ssh_pubkeys?string[]Override authorized SSH keys on the clone.
egress?string[]Override egress allowlist on the clone.
ingress_enabled?booleanEnable/disable ingress on the clone.
envs?Record<string, string>A nonempty map replaces the inherited environment map. Omit or send an empty map to inherit it.

Some SDK versions expose bandwidth_quota_bytes in the fork type, but the server rejects it with 400, including zero. Omit it and use rechargeBandwidth() after the child is running. A fork does not inherit S3 disk attachments; attach disks after it reaches running.

Returns Promise<Sandbox>: a handle to the new sandbox.

Throws

Example

await sandbox.pause();
await sandbox.waitUntilPaused();
const clone = await sandbox.fork({ start_paused: false });
console.log(clone.id);

destroy

async destroy(options?: RequestOptions): Promise<DestroyedResponse>

Destroys the sandbox. The call returns when the row reaches destroying or destroyed; reclamation is async. Use waitUntilDestroyed() to block until fully reclaimed.

Parameters: options?: RequestOptions.

Returns Promise<DestroyedResponse>: { id: string; status: "destroying" | "destroyed" }.

Throws

Example

await sandbox.destroy();
await sandbox.waitUntilDestroyed();

resize

async resize(diskMib: number, options?: RequestOptions): Promise<ResizeSandboxResponse>

Grows the overlay disk to diskMib. The value must exceed the current disk size. Shrinking is not supported.

Parameters

NameTypeDescription
diskMibnumberNew overlay disk size in MiB. Must be greater than the current size.
options?RequestOptionsPer-request options.

Returns Promise<ResizeSandboxResponse>: { id: string; disk_mib: number }.

Throws

Example

await sandbox.resize(4096); // grow overlay to 4 GiB

setAutoPause

async setAutoPause(seconds: number | null, options?: RequestOptions): Promise<this>

Sets or clears the idle auto-pause timeout. When set, the control plane pauses the sandbox after seconds of no detected activity. Pass null to disable. The handle is updated in place.

Parameters

NameTypeDescription
secondsnumber | nullIdle timeout in seconds (60-86400), or null to disable.
options?RequestOptionsPer-request options.

Returns Promise<this>

Throws

Example

await sandbox.setAutoPause(600); // pause after 10 min idle
await sandbox.setAutoPause(null); // disable

waitUntilRunning

async waitUntilRunning(options?: WaitOptions): Promise<this>

Polls until status === "running". Aborts early on terminal failure states including destroying/destroyed.

Parameters: options?: WaitOptions:

FieldTypeDescription
timeoutMs?numberWait budget in ms. Default 120000.
signal?AbortSignalCancels the wait.
request?RequestOptionsPer-poll request options (headers, retry, per-request timeout).

Returns Promise<this>

Throws

Example

await sandbox.resume();
await sandbox.waitUntilRunning({ timeoutMs: 60_000 });

waitUntilPaused

async waitUntilPaused(options?: WaitOptions): Promise<this>

Polls until status === "paused". Aborts early on terminal failure states including destroying/destroyed.

Parameters: options?: WaitOptions.

Returns Promise<this>

Throws: same as waitUntilRunning.

Example

await sandbox.pause();
await sandbox.waitUntilPaused();

waitUntilDestroyed

async waitUntilDestroyed(options?: WaitOptions): Promise<this>

Polls until status === "destroyed". destroying is treated as an intermediate step and does not abort the wait.

Parameters: options?: WaitOptions.

Returns Promise<this>

Throws

Example

await sandbox.destroy();
await sandbox.waitUntilDestroyed();

Ingress & preview

setIngress

async setIngress(enabled: boolean, options?: RequestOptions): Promise<this>

Enables or disables HTTP ingress. The handle is updated with the patched projection. After enabling, use previewurl() to build the public URL.

Parameters

NameTypeDescription
enabledbooleantrue to enable, false to disable.
options?RequestOptionsPer-request options.

Returns Promise<this>

Throws

Example

await sandbox.setIngress(true);
console.log(sandbox.previewUrl(8080));

waitForPortReady

async waitForPortReady(
  port: number,
  options?: WaitOptions & { intervalMs?: number; host?: string },
): Promise<this>

Polls a TCP port from inside the sandbox (via bash's /dev/tcp shim) until something is listening. Resolves once the port accepts a connection; throws CreateosSandboxTimeoutError if the budget runs out. Requires bash and GNU timeout in the rootfs (both present in the default rootfs).

Parameters

NameTypeDescription
portnumberPort to probe (1-65535).
options.timeoutMs?numberWait budget in ms. Default 30000.
options.intervalMs?numberPoll interval in ms. Default 200.
options.host?stringHost to probe inside the sandbox. Default "127.0.0.1".
options.signal?AbortSignalCancels the wait.
options.request?RequestOptionsPer-poll request options.

Returns Promise<this>

Throws

Example

await sandbox.runCommand("sh", ["-c", "python3 -m http.server 8080 &"]);
await sandbox.waitForPortReady(8080, { timeoutMs: 10_000 });
console.log("server is up");

previewUrl

previewUrl(port: number, options?: { scheme?: "http" | "https" }): string

Builds the public ingress URL for a port. Only available when the sandbox was created with ingress_enabled: true (or enabled later via setIngress(true)). Synchronous, no network call.

Parameters

NameTypeDescription
portnumberIn-guest port to route to (1-65535).
options.scheme?"http" | "https"URL scheme. Default "https". Pass "http" when the TLS certificate is not yet provisioned.

Returns string: fully-qualified public URL.

Throws CreateosSandboxError: port invalid or ingress not enabled.

Example

await sandbox.setIngress(true);
const url = sandbox.previewUrl(3000);
// TLS cert may lag on fresh hostname — force http:
const plain = sandbox.previewUrl(3000, { scheme: "http" });

Egress & bandwidth

getEgress

getEgress(options?: RequestOptions): Promise<EgressView>

Returns the current egress allowlist and counters. EgressView.egress is [] when all egress is allowed.

Parameters: options?: RequestOptions.

Returns Promise<EgressView>: { id: string; egress: string[] }.

Throws

Example

const { egress } = await sandbox.getEgress();
console.log(egress); // ["api.openai.com:443"]

setEgress

setEgress(rules: string[] | null, options?: RequestOptions): Promise<EgressView>

Replaces the egress allowlist. null or [] means allow all egress.

Parameters

NameTypeDescription
rulesstring[] | nullhost:port allow rules, or null/[] to allow all.
options?RequestOptionsPer-request options.

Returns Promise<EgressView>

Throws

Example

await sandbox.setEgress(["api.openai.com:443", "registry.npmjs.org:443"]);
await sandbox.setEgress(null); // allow all

getBandwidth

getBandwidth(options?: RequestOptions): Promise<BandwidthView>

Returns the current bandwidth quota and usage.

Parameters: options?: RequestOptions.

Returns Promise<BandwidthView>:

FieldTypeDescription
idstringSandbox id.
quota_bytesnumberTotal transferable quota. -1 = unmetered.
used_bytesnumberEgress bytes billed against the quota.
ingress_bytesnumberInbound bytes (observed, not enforced).
remaining_bytesnumberBytes left before capping.
cappedbooleantrue once quota is exhausted and egress is blocked.

Throws

Example

const bw = await sandbox.getBandwidth();
console.log(bw.used_bytes, "/", bw.quota_bytes);

rechargeBandwidth

rechargeBandwidth(addBytes: number, options?: RequestOptions): Promise<BandwidthView>

Tops up the bandwidth quota by addBytes. Use this when BandwidthView.capped is true or you want to pre-purchase headroom. Note: bandwidth_quota_bytes is not settable at create time (the server rejects non-zero values); grow it post-create with this method.

Parameters

NameTypeDescription
addBytesnumberBytes to add to the quota.
options?RequestOptionsPer-request options.

Returns Promise<BandwidthView>: updated quota state.

Throws

Example

await sandbox.rechargeBandwidth(10 * 1024 * 1024 * 1024); // +10 GiB

Networks

attachNetwork

attachNetwork(networkId: string, options?: RequestOptions): Promise<OKResponse>

Attaches the sandbox to an overlay network.

Parameters

NameTypeDescription
networkIdstringNetwork id (e.g. "net_01h…").
options?RequestOptionsPer-request options.

Returns Promise<OKResponse>: { ok: boolean }.

Throws

Example

await sandbox.attachNetwork("net_01h…");

detachNetwork

detachNetwork(networkId: string, options?: RequestOptions): Promise<OKResponse>

Detaches the sandbox from an overlay network.

Parameters

NameTypeDescription
networkIdstringNetwork id to detach from.
options?RequestOptionsPer-request options.

Returns Promise<OKResponse>

Throws

Example

await sandbox.detachNetwork("net_01h…");

Disks

listDisks

listDisks(options?: RequestOptions): Promise<SandboxDiskView[]>

Lists all disks attached to the sandbox with per-attachment mount status. Fetches all pages before returning.

Parameters: options?: RequestOptions.

Returns Promise<SandboxDiskView[]> where each entry has:

FieldTypeDescription
disk_idstringdisk_<ulid> id.
namestringDisk name.
kindDiskKindDisk kind.
configDiskConfigDisk config.
mount_pathstringAbsolute guest path.
sub_path?stringBucket sub-folder exposed at mount_path.
mount_statusDiskMountStatusCurrent mount state.
mount_error?stringFailure detail when the server returns mount_status: "failed". See the type compatibility note.

Throws

Example

const disks = await sandbox.listDisks();
for (const d of disks) {
  console.log(d.disk_id, d.mount_path, d.mount_status);
}

iterateDisks

iterateDisks(options?: RequestOptions): AsyncGenerator<SandboxDiskView>

Streams disks one page at a time. Prefer over listDisks() when the attached disk count may be large.

Parameters: options?: RequestOptions.

Returns AsyncGenerator<SandboxDiskView>

Example

for await (const d of sandbox.iterateDisks())
  console.log(d.disk_id, d.mount_path);

attachDisk

attachDisk(opts: AttachDiskOptions, options?: RequestOptions): Promise<OKResponse>

Live-attaches a registered disk into a running sandbox. The server rejects with 409 if it is not running. For a paused sandbox, resume and wait for running before attaching. For a fork, wait for the child to run and attach its disks. CreateSandboxRequest.disks applies only when creating a sandbox.

Parameters

NameTypeDescription
opts.diskIdstringA disk_<ulid> id or the user-scoped disk name.
opts.mountPathstringAbsolute path inside the guest, e.g. /mnt/data.
opts.subPath?stringBucket sub-folder to expose at mountPath.
options?RequestOptionsPer-request options.

Returns Promise<OKResponse>

Throws

Example

await sandbox.attachDisk({ diskId: "shared-data", mountPath: "/mnt/data" });

detachDisk

detachDisk(opts: DetachDiskOptions, options?: RequestOptions): Promise<DiskDetachedResponse>

Detaches a disk from this sandbox. mountPath is required because the same disk may be mounted at multiple paths (the composite key is (sandbox, disk, mountPath)). Bucket contents are untouched.

Parameters

NameTypeDescription
opts.diskIdstringA disk_<ulid> id or the user-scoped disk name.
opts.mountPathstringAbsolute path where the disk is currently mounted.
options?RequestOptionsPer-request options.

Returns Promise<DiskDetachedResponse>: { detached: boolean }.

Throws

Example

await sandbox.detachDisk({ diskId: "shared-data", mountPath: "/mnt/data" });

SSH

addSSHPubkeys

addSSHPubkeys(keys: string[], options?: RequestOptions): Promise<AddSSHPubkeysResponse>

Adds OpenSSH public keys to this sandbox's authorized set. Keys already present are de-duplicated server-side. Works on a live (running) sandbox, unlike CreateSandboxRequest.ssh_pubkeys which is set only at create time.

Parameters

NameTypeDescription
keysstring[]OpenSSH public key strings (e.g. "ssh-ed25519 AAAA…").
options?RequestOptionsPer-request options.

Returns Promise<AddSSHPubkeysResponse>: { count: number }, the total authorized keys after the add.

Throws

Example

const pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA…";
const { count } = await sandbox.addSSHPubkeys([pubkey]);
console.log(`${count} key(s) authorized`);

Introspection

refresh

async refresh(options?: RequestOptions): Promise<this>

Re-fetches the sandbox projection and updates this handle in place. Use after an out-of-band mutation or to verify state before acting.

Parameters: options?: RequestOptions.

Returns Promise<this>

Throws

Example

await sandbox.refresh();
console.log(sandbox.status);

toJSON

toJSON(): SandboxView

Returns the last-known sandbox projection. Called automatically by JSON.stringify. No network call.

Returns SandboxView

Example

console.log(JSON.stringify(sandbox, null, 2));

For file transfer operations on the sandbox filesystem, see Sandbox Files.

See also

  • Client: createSandbox, getSandbox, listSandboxes, and the sub-API namespaces.
  • Errors: full error class hierarchy.
  • Types: all wire types and option interfaces.
  • Sub-APIs: TemplatesApi, NetworksApi, DisksApi.