SandboxSDK reference

SDK reference

The core surface of @tangle-network/sandbox. The npm package documents every option; this page covers what most builders reach for.

npm install @tangle-network/sandbox

Client

import { Sandbox } from "@tangle-network/sandbox";
 
const client = new Sandbox({
  apiKey: process.env.TANGLE_API_KEY!,
  baseUrl: process.env.SANDBOX_BASE_URL ?? "https://sandbox.tangle.tools",
  timeoutMs: 30000, // optional
});

client.create(options?)

Create a sandbox and get back a SandboxInstance. Common options:

const box = await client.create({
  name: "my-project",
  image: "node:20",
  backend: { type: "opencode" }, // coding harness; see supported harnesses below
  env: { NODE_ENV: "development" },
  resources: { cpuCores: 2, memoryMB: 4096, diskGB: 20 },
  maxLifetimeSeconds: 3600,
  idleTimeoutSeconds: 900,
  fromSnapshot: "snap_abc123", // restore a saved workspace (both fields required)
  fromSandboxId: "sandbox_abc123", // the sandbox that owns the snapshot
});

backend.type picks the coding harness. OpenCode is the default; Claude Code, Codex, and the other supported harnesses are selected the same way.

client.list(options?) · client.get(id) · client.usage()

const running = await client.list({ status: "running", limit: 10 });
const box = await client.get("sandbox_abc123");
const usage = await client.usage(); // activeSandboxes, computeMinutes

client.runBatch(tasks, options?)

Run one-shot tasks across freshly provisioned sandboxes in parallel. For coordinated multi-machine work with shared workspaces and policy caps, use fleets instead.

const result = await client.runBatch(
  [
    { id: "task-1", message: "Analyze code quality" },
    { id: "task-2", message: "Run the security scan" },
  ],
  { timeoutMs: 300000, scalingMode: "balanced" }, // fastest | balanced | cheapest
);
console.log(result.successRate);

Sandbox instance

box.exec(command, options?)

Run a shell command.

const result = await box.exec("npm install", {
  cwd: "/workspace",
  env: { CI: "true" },
  timeoutMs: 60000,
});
console.log(result.exitCode, result.stdout);

box.prompt(message, options?) · box.streamPrompt(message, options?)

Run one agent turn. prompt returns the result; streamPrompt yields events as they happen.

const result = await box.prompt("List the files and summarize the project");
 
for await (const event of box.streamPrompt("Fix the failing auth test")) {
  console.log(event);
}

box.task(message, options?)

A higher-level agent task (plan, edit, run, verify) over a single prompt.

const task = await box.task("Fix any failing tests and commit the changes");

Durable sessions

prompt and streamPrompt live and die with the call. For a run that must survive a client crash, a redeploy, or a browser reload, dispatch it with a stable sessionId and reconnect from a fresh process.

const { sessionId, alreadyExisted } = await box.dispatchPrompt(prompt, {
  sessionId, // derive this server-side; never accept a caller-chosen id
});
 
// From any process, follow the run or wait for the result:
for await (const event of box.session(sessionId).events()) {
  console.log(event);
}
const final = await box.session(sessionId).result();
const state = await box.session(sessionId).status();

The same sessionId is idempotent. A duplicate dispatch returns the in-flight or completed session instead of running the work twice, which makes it safe to retry a webhook or payment-triggered run.

GPU leases

Keep the base sandbox cheap and attach a GPU only around the step that needs it. Every lease takes a hard spend cap and lifetime.

const lease = await box.gpu.attach({
  accelerator: { kind: "nvidia-h100", count: 1 },
  maxSpendUsd: 5,
  maxLifetimeSeconds: 600,
});
try {
  await box.gpu.exec(lease.id, { command: "python train.py" });
} finally {
  await box.gpu.detach(lease.id);
}

Lifecycle

await box.stop(); // pause; resume later
await box.resume();
await box.delete(); // release the machine

Next