API reference

Sandbox

The main client — sandbox(), resume(), restoreSnapshot(), connect(), and sandboxes management.

import { Sandbox } from "@alineo-labs/sandbox";

Constructor

new Sandbox(options: SandboxClientOptions)

SandboxClientOptions

OptionTypeRequiredDescription
baseUrlstringYesOpenSandbox server URL, e.g. "http://localhost:8080"
apiKeystringNoOpenSandbox API key. Empty string for local dev with no auth.
adapterIStorageAdapterYesStorage adapter for the run ledger
maxConcurrencynumberNoMax simultaneous active sandboxes. Omit for no limit.
useServerProxybooleanNoRoute execd and proxy traffic through the server. Required when the server runs in Docker via alineo init. Defaults to false.
credentialBrokerCredentialBrokerNoBackend for sb.credentials.*. Defaults to OpenSandboxCredentialBroker (@alineo-labs/vault) — see Credentials.
const client = new Sandbox({
  baseUrl: process.env.OPEN_SANDBOX_URL ?? "http://localhost:8080",
  apiKey: process.env.OPEN_SANDBOX_API_KEY ?? "",
  adapter: new SQLiteAdapter("./ledger.db"),
  maxConcurrency: 10,
});

Methods

sandbox()

await client.sandbox(opts: SandboxOptions): Promise<SandboxHandle>

Creates a container, waits until it reaches Running state, and returns a live SandboxHandle object. Writes a sandbox.created event to the ledger.

If maxConcurrency is set, awaits a slot before creating the container. The slot is released when sb.close() is called.

See Sandboxes for SandboxOptions reference.

const sb = await client.sandbox({
  image: "ubuntu:22.04",
  resources: { cpu: "500m", memory: "512Mi" },
  name: "my-run",
});
try {
  await sb.exec("echo hello").pipe(process.stdout);
} finally {
  await sb.close();
}

resume()

await client.resume(
  sandboxId: string,
  opts?: { tag?: string; resolveCredential?: CredentialResolver },
): Promise<SandboxHandle>

Restores a sandbox session from its last checkpoint (or the checkpoint matching opts.tag, if given):

  1. Reads the ledger to find the last sandbox.checkpoint_created event (or the last one matching opts.tag)
  2. Creates a new container from the snapshot
  3. Populates a replay cache from execs that completed before the checkpoint
  4. Re-registers any credentials the sandbox had bound (see Credentials) — opts.resolveCredential supplies values that can't be re-derived automatically
  5. Returns a SandboxHandle — pre-checkpoint execs return cached results; later execs run live

Throws SandboxClientError (404) if the session is not found or has no matching checkpoint. Throws SandboxError if a bound credential can't be resolved.

const sbResume = await client.resume(originalSandboxId);
try {
  await sbResume.exec("pip install -q requests").pipe(process.stdout); // replayed
  await sbResume.exec("python3 script.py").pipe(process.stdout); // live
} finally {
  await sbResume.close();
}

// Resume from a specific named checkpoint instead of the most recent one:
const sbTagged = await client.resume(originalSandboxId, { tag: "after-apt" });

restoreSnapshot()

await client.restoreSnapshot(
  snapshotId: string,
  name: string,
  resources: { cpu: string; memory: string; gpu?: string },
): Promise<SandboxHandle>

Creates a fresh sandbox from a snapshot ID without exec replay — unlike resume(), the new sandbox starts with a clean exec history; nothing from the ledger is replayed. Use this when you want to restore a checkpointed environment and run new commands from scratch, rather than continue exactly where the checkpoint left off.

This is also what sb.fork() uses under the hood — see Forking sandboxes for the relationship between checkpoint(), fork(), resume(), and restoreSnapshot().

const snapshotId = await sb.checkpoint();
await sb.close();

// Later — restore and run fresh commands:
const sb2 = await client.restoreSnapshot(snapshotId, "my-sandbox", {
  cpu: "500m",
  memory: "256Mi",
});
await sb2.exec("npm test");
await sb2.close();

connect()

await client.connect(
  sandboxId: string,
  name: string,
  opts?: { resources?: { cpu: string; memory: string; gpu?: string } },
): Promise<SandboxHandle>

Attaches to an already-Running sandbox by ID, no snapshot or ledger replay involved — the container must already be running (throws SandboxClientError (409) otherwise). Use this to reconnect to a live sandbox created outside the current process, e.g. from a saved sandboxId.

opts.resources is only needed if you intend to call .fork() on the returned SandboxHandle afterwards — the control API doesn't echo back a running sandbox's own resource limits, so there's no way to discover them here; without it, .fork() is unavailable on the returned object.

// In a new process, reconnect to a sandbox started earlier:
const sb = await client.connect(savedSandboxId, "my-sandbox");
const { stdout } = await sb.exec("cat /results.txt");
await sb.close();

sandboxes

client.sandboxes: {
  list(opts?: ListSandboxOptions): Promise<SandboxDetails[]>
  listByName(name: string, opts?: ListSandboxOptions): Promise<SandboxDetails[]>
  get(name: string, sandboxId: string): Promise<SandboxDetails | null>
  delete(name: string, sandboxId: string): Promise<void>
}

Access to the ledger's session history.

// List all sessions, newest first
const all = await client.sandboxes.list();

// Filter
const running = await client.sandboxes.list({ status: SandboxStatus.Running, limit: 20 });

// By name
const named = await client.sandboxes.listByName("my-ci-job");

// Single session
const session = await client.sandboxes.get("my-job", sandboxId);

// Delete
await client.sandboxes.delete("my-job", sandboxId);

ListSandboxOptions

OptionTypeDescription
statusSandboxStatusFilter by status: "running" or "completed"
limitnumberMax results to return
beforenumberReturn only sessions started before this Unix timestamp (ms)

SandboxHandle class

See SandboxHandle below for the object returned by sandbox() and resume().

SandboxHandle methods

MethodReturnsDescription
sb.exec(cmd, opts?)ExecHandleRun a shell command
sb.execCode(code, opts?)ExecHandleRun code via the interpreter
sb.proxy(port)Promise<{ url, headers }>Get a proxied URL for an in-sandbox port
sb.metrics()Promise<{ cpu, memory, timestamp }>Current CPU and memory usage
sb.writeFile(path, content)Promise<void>Write a UTF-8 file into the container
sb.readFile(path)Promise<string>Read a file from the container as a string
sb.moveFile(from, to)Promise<void>Move or rename a file
sb.deleteFile(path)Promise<void>Delete a file
sb.createDirectory(path)Promise<void>Create a directory (and parents)
sb.deleteDirectory(path)Promise<void>Delete a directory
sb.getFileInfo(path)Promise<FileInfo>File metadata: size, type, mode, timestamps
sb.replaceInFiles(replacements)Promise<void>In-place substring replacement across files
sb.transfer(path, target)Promise<void>Copy a file to another SandboxHandle instance
sb.searchFiles(pattern, path?)Promise<string[]>Search for files matching a glob
sb.listDirectory(path, opts?)Promise<FileInfo[]>List directory entries with metadata
sb.checkpoint(name?)Promise<string>Snapshot the container state, returns the snapshot ID
sb.listCheckpoints()Promise<CheckpointInfo[]>All checkpoints for this sandbox
sb.fork(tag?, runId?, opts?)Promise<SandboxHandle>Snapshot and return an independent copy
sb.close()Promise<void>Delete the container and release resources

sb.credentials

sb.credentials: {
  set(name: string, value: string, binding: CredentialBinding, source?: CredentialSource): Promise<void>
  patch(name: string, changes: Partial<{ value: string; binding: CredentialBinding }>): Promise<void>
  remove(name: string): Promise<void>
  listBindings(): Promise<Array<{ name: string; binding: CredentialBinding }>>
}

Register, update, remove, and list credentials injected into this sandbox's outbound requests — requires the sandbox to have been created with credentialProxy: true. See Credentials.

SandboxHandle properties

PropertyTypeDescription
sb.sandboxIdstringOpenSandbox container ID
sb.namestringUser-provided name or auto-generated