SandboxExamplesFleet examples

Fleet examples

Each TypeScript program is complete. Set TANGLE_API_KEY, install @tangle-network/sandbox, and run it with npx tsx <file>.mts. Each one deletes its fleet when it finishes. Model ids come from GET /v1/router-models with your Sandbox key, or the model list. The guide for all of them is Fleets.

Run four agents under one budget

Four agents with their own tasks share one sandbox and one budget.

import { Sandbox } from "@tangle-network/sandbox";
 
const client = new Sandbox({
  apiKey: process.env.TANGLE_API_KEY!,
  baseUrl: "https://sandbox.tangle.tools",
});
 
const fleet = await client.fleets.create({
  agents: [
    { agentId: "tests", task: "List the three slowest tests and why." },
    { agentId: "todos", task: "Find every TODO and group them by file." },
    { agentId: "deps", task: "Say what each dependency is used for." },
    { agentId: "entry", task: "Name the entry point and the modules it loads." },
  ],
  placement: { agentsPerSandbox: 4 },
  defaults: {
    git: { url: "https://github.com/tangle-network/sandbox-demo" },
    // Claude Code and Codex take a Router model the same way.
    backend: { type: "opencode", model: { model: "glm-5.3" } },
    maxLifetimeSeconds: 900,
  },
  budgetUsd: 1, // a charge past this is refused, mid-turn included
});
try {
  const results = await fleet.runAll();
  for (const r of results) console.log(r.agentId, r.status, r.result?.response);
  console.log(await fleet.spend());
} finally {
  await fleet.delete();
}

Prints each agent’s status and answer, then the budget: cap, spent, in flight and remaining.

Review five packages at once

One reviewer per package, each on its own sandbox. Findings arrive as each agent ends.

import { Sandbox } from "@tangle-network/sandbox";
 
const client = new Sandbox({
  apiKey: process.env.TANGLE_API_KEY!,
  baseUrl: "https://sandbox.tangle.tools",
});
 
const packages = ["api", "web", "worker", "cli", "shared"];
const fleet = await client.fleets.create({
  agents: packages.map((name) => ({
    agentId: name,
    task: `Review packages/${name} for unhandled promise rejections. ` +
      "Answer file:line per finding, or none.",
  })),
  placement: "dedicated",
  defaults: {
    git: { url: "https://github.com/tangle-network/sandbox-demo" },
    backend: { type: "codex" },
  },
  budgetUsd: 3,
});
try {
  const findings: Record<string, string> = {};
  for await (const event of fleet.run()) {
    if (event.type === "agent.started") console.log("started", event.agentId);
    if (event.type === "agent.finished") {
      const { agentId, result, status } = event.result;
      findings[agentId] = result?.response ?? status;
    }
    if (event.type === "fleet.finished") console.log(event.durationMs, event.spend);
  }
  console.table(findings);
} finally {
  await fleet.delete();
}

Prints a line as each agent starts, the run’s duration and spend, then a table of findings by package.

Translate a README into five languages

Each agent writes one file; the program collects the files from the agents’ sandboxes.

import { writeFile } from "node:fs/promises";
import { Sandbox } from "@tangle-network/sandbox";
 
const client = new Sandbox({
  apiKey: process.env.TANGLE_API_KEY!,
  baseUrl: "https://sandbox.tangle.tools",
});
 
const languages = { de: "German", fr: "French", ja: "Japanese", pt: "Portuguese", es: "Spanish" };
const fleet = await client.fleets.create({
  agents: Object.entries(languages).map(([code, name]) => ({
    agentId: code,
    task: `Translate README.md into ${name} and write it to README.${code}.md. Change nothing else.`,
  })),
  placement: "dedicated",
  defaults: {
    git: { url: "https://github.com/tangle-network/sandbox-demo" },
    // Claude Code and Codex take a Router model the same way.
    backend: { type: "opencode", model: { model: "glm-5.3" } },
  },
  budgetUsd: 2,
});
try {
  await fleet.runAll();
  const files = await fleet.collectArtifacts(
    fleet.agents.map((a) => ({
      machineId: a.machineId,
      path: `/home/agent/sandbox-demo/README.${a.agentId}.md`,
      label: a.agentId,
    })),
  );
  for (const file of files) {
    await writeFile(`README.${file.label}.md`, file.content);
    console.log(file.label, file.content.split("\n")[0]);
  }
} finally {
  await fleet.delete();
}

Writes README.de.md through README.es.md next to the program and prints each file’s first line.

Give each agent its own model

Cheap models read; a stronger one fixes.

import { Sandbox } from "@tangle-network/sandbox";
 
const client = new Sandbox({
  apiKey: process.env.TANGLE_API_KEY!,
  baseUrl: "https://sandbox.tangle.tools",
});
 
const fleet = await client.fleets.create({
  agents: [
    { agentId: "imports", model: "deepseek/deepseek-v4.1-flash", task: "List unused imports as file:line, or none." },
    { agentId: "docs", model: "deepseek/deepseek-v4.1-flash", task: "Write one paragraph per package into PACKAGES.md." },
    { agentId: "fix", model: "glm-5.3", task: "The test tagged timezone fails. Fix the cause; keep every other test green." },
  ],
  placement: "dedicated",
  defaults: {
    git: { url: "https://github.com/tangle-network/sandbox-demo" },
    // Claude Code and Codex take per-agent models the same way.
    backend: { type: "opencode" },
  },
  budgetUsd: 2,
});
try {
  for (const r of await fleet.runAll()) {
    console.log(r.agentId, r.model, r.status, r.costUsd?.toFixed(3), `${Math.round(r.durationMs / 1000)} s`);
  }
  console.log(await fleet.spend());
} finally {
  await fleet.delete();
}

Prints each agent’s model, status, cost and duration, then the fleet’s spend. costUsd is set because each agent is alone on its sandbox.

Shard a test suite across machines

No agents: five machines run one test file each, at the same time.

import { Sandbox } from "@tangle-network/sandbox";
 
const client = new Sandbox({
  apiKey: process.env.TANGLE_API_KEY!,
  baseUrl: "https://sandbox.tangle.tools",
});
 
const files = ["cli", "dates", "format", "primes", "validate"];
const fleet = await client.fleets.create({
  machines: files.map((name) => ({ machineId: name })),
  defaults: { git: { url: "https://github.com/tangle-network/sandbox-demo" } },
});
try {
  const started = performance.now();
  const results = await Promise.all(
    files.map((name) => fleet.exec(name, `node --test test/${name}.test.js 2>&1 | tail -4`)),
  );
  files.forEach((name, i) =>
    console.log(name, results[i].exitCode === 0 ? "pass" : "FAIL", results[i].stdout.trim().split("\n").at(-1)),
  );
  console.log(`${Math.round(performance.now() - started)} ms for all five`);
} finally {
  await fleet.delete();
}

Prints pass or FAIL per file with the last line of its output, then the total time.

Stop everyone at a soft spending cap

The platform refuses any charge past budgetUsd. To stop earlier, watch spend() and cancel.

import { Sandbox } from "@tangle-network/sandbox";
 
const client = new Sandbox({
  apiKey: process.env.TANGLE_API_KEY!,
  baseUrl: "https://sandbox.tangle.tools",
});
 
const ideas = ["a lookup table", "a streaming parser", "fewer allocations",
  "worker threads", "WebAssembly", "a hand written tokenizer"];
const fleet = await client.fleets.create({
  agents: ideas.map((idea) => ({
    task: `Make bench/parse.js faster with ${idea}. Report the speedup.`,
  })),
  placement: "dedicated",
  defaults: {
    git: { url: "https://github.com/tangle-network/sandbox-demo" },
    backend: { type: "claude-code" },
  },
  budgetUsd: 5,
});
 
const softCapUsd = 1;
async function checkSpend() {
  const { spentUsd } = await fleet.spend();
  if (spentUsd < softCapUsd) return;
  clearInterval(watch);
  const { interrupted } = await fleet.cancel();
  console.log(`$${spentUsd.toFixed(2)} spent, ${interrupted} agents stopped`);
}
const watch = setInterval(() => void checkSpend().catch(console.error), 5_000);
 
try {
  const results = await fleet.runAll();
  for (const r of results) console.log(r.agentId, r.status, r.costUsd);
} finally {
  clearInterval(watch);
  await fleet.delete();
}

Prints how much was spent and how many agents were stopped once spend passes the soft cap, then each agent’s status: completed, cancelled or budget_exhausted.

Run a command across machines from Python

A coordinator and two workers under a create-time policy. Python fleets run commands; agent fleets with budgets are TypeScript and CLI only.

import os
import time
 
from tangle_sandbox import (
    CreateSandboxFleetWithCoordinatorOptions,
    CreateSandboxOptions,
    FleetExecDispatchOptions,
    FleetRetryPolicy,
    Sandbox,
    SandboxFleetMachineSpec,
    SandboxFleetPolicy,
    SandboxResources,
)
 
with Sandbox(api_key=os.environ["TANGLE_API_KEY"], base_url="https://sandbox.tangle.tools") as client:
    fleet = client.fleets.create_with_coordinator(
        CreateSandboxFleetWithCoordinatorOptions(
            fleet_id=f"research-{int(time.time())}",
            defaults=CreateSandboxOptions(environment="universal", max_lifetime_seconds=30 * 60),
            policy=SandboxFleetPolicy(
                max_machines=3,
                max_concurrent_creates=2,
                max_total_cpu=6,
                max_total_memory_mb=12_288,
                max_spend_usd=2,
                allow_accelerators=False,
            ),
            coordinator=SandboxFleetMachineSpec(
                machine_id="coordinator",
                options=CreateSandboxOptions(resources=SandboxResources(cpu_cores=1, memory_mb=1024)),
            ),
            workers=[
                SandboxFleetMachineSpec(
                    machine_id=f"worker-{n}",
                    options=CreateSandboxOptions(resources=SandboxResources(cpu_cores=2, memory_mb=4096)),
                )
                for n in (1, 2)
            ],
        )
    )
    try:
        results = fleet.dispatch_exec(
            "printf '%s\\n' \"$HOSTNAME ready\"",
            FleetExecDispatchOptions(
                machines=fleet.ids,
                max_concurrent=2,
                retry=FleetRetryPolicy(attempts=2),
                timeout_ms=30_000,
            ),
        )
        for result in results:
            output = result.get("result", {}).get("stdout") if result.get("ok") else result.get("error")
            print(f"{result['machineId']}: {output}")
        print(fleet.usage())
    finally:
        fleet.delete()

Install the tangle-sandbox package. Prints one ready line per machine, then the fleet’s usage.

Next