little big brain
Product / Sandboxes

Run code in a sandbox.
One call. A record of every run.

A sandbox is an isolated workspace with its own disk and no network. Send code and input. Get a result and a record.

Join the waitlist

Capacity is limited. We tell you when a place opens.

One call
// In your product, a model writes this code.
const code = `
def run(input, config):
    return sum(input)
`;

const { result } = await lbb.sandboxes.run({ code, input: [1, 2, 3] });
// result is 6
# In your product, a model writes this code.
code = """
def run(input, config):
    return sum(input)
"""

result = lbb.sandboxes.run(code=code, input=[1, 2, 3]).result
# result is 6
The sandbox is destroyed when the run ends. Its record is kept.
One call.

Send code and input. Get back the result and the id of its record.

No network.

A sandbox has no network device. No credential enters it.

Every run is a record.

The record shows what ran, on which inputs, with which result.

[01] The parts

Six parts, each with a name.

Every level of use writes the same records.

sandbox · sbx_

An isolated workspace with its own disk and no network. It lives for one call, or until you end it.

command · cmd_

One process, or one call of run(input, config), inside a sandbox. Its record keeps the status, exit code and output.

template · sbt_

A saved version of a base image, code and limits. Each save is a new version.

workspace · /workspace

The files of a sandbox. They stay between commands and end with the sandbox.

keep · POST /v1/files

Keep a workspace file as a File of the graph. It stays after the sandbox ends.

base templates

lbb/python, lbb/node and lbb/shell. Python 3.13, Node 24, and bash with jq.

[02] The ladder

Start with one call.
Climb when you need more.

Each level builds on the one before. Every level writes the same records.

  1. Level 1One callsandboxes.run({ code, input })
  2. Level 2A templatesandboxes.run({ template, input })
  3. Level 3The full APIsandboxes.scoped(spec, fn)
  4. Level 4A workflow stepThe same calls, inside a workflow
Level 1

One call.

Send code and input. The call returns the result. The sandbox ends with the run.

  • Python 3.13 has numpy, pandas, pyarrow and more built in.
  • A run that raises an error returns ok as false. The traceback is in the command output.
  • A retry with the same key never runs the code twice.
sandboxes.run
const code = `
def run(input, config):
    return sum(input)
`;

const run = await lbb.sandboxes.run({ code, input: [1, 2, 3] });
run.ok;       // true when the code exited with code 0
run.result;   // 6
run.command;  // "cmd_…", the record of this run
code = """
def run(input, config):
    return sum(input)
"""

run = lbb.sandboxes.run(code=code, input=[1, 2, 3])
run.ok        # True when the code exited with code 0
run.result    # 6
run.command   # "cmd_…", the record of this run
Level 2

A template.

Save the code, limits and default config under a name. Each save is a new version.

  • A call names the template and runs its newest version.
  • Change the code and the callers stay as they are.
  • The record names the exact version that ran.
sandboxes.templates.create
await lbb.sandboxes.templates.create({
  name: "normalize",
  base: "lbb/python",
  code,
  limits: { memoryMib: 2048 },
  commandTimeoutMs: 60_000,
  config: { unit: "cm" },
});

await lbb.sandboxes.run({ template: "normalize", input: [1, 2, 3] });
lbb.sandboxes.templates.create(
    name="normalize",
    base="lbb/python",
    code=code,
    limits={"memory_mib": 2048},
    timeout_ms=60_000,
    config={"unit": "cm"},
)

lbb.sandboxes.run(template="normalize", input=[1, 2, 3])
Level 3

The full API.

Sandboxes, commands and files. Own the life of a sandbox, or let a block own it.

  • scoped makes a sandbox and gives you its handle. It destroys the sandbox at the end, also after an error.
  • Read, write and list files. Start any command with argv.
  • Stop a sandbox and resume it. A stopped sandbox keeps its disk.
sandboxes.scoped
const csv = "1,2\n3,4\n";
const countLines = `
def run(input, config):
    return len(open(input["file"]).read().splitlines())
`;
const upperPy = `
print(open("data.csv").read().upper())
`;

const out = await lbb.sandboxes.scoped({}, async (sb) => {
  await sb.files.write("data.csv", csv);
  await sb.files.write("upper.py", upperPy);
  const rows = await sb.run({ code: countLines, input: { file: "data.csv" } });
  const upper = await sb.commands.create({
    argv: ["python", "upper.py"],
    waitMs: 30_000,
  });
  return { lines: rows.result, upper: upper.stdout.tail };
});
csv = "1,2\n3,4\n"
count_lines = """
def run(input, config):
    return len(open(input["file"]).read().splitlines())
"""
upper_py = """
print(open("data.csv").read().upper())
"""

with lbb.sandboxes.scoped() as sb:
    sb.files.write("data.csv", csv)
    sb.files.write("upper.py", upper_py)
    rows = sb.run(code=count_lines, input={"file": "data.csv"})
    upper = sb.commands.create(argv=["python", "upper.py"], wait_ms=30_000)
    out = {"lines": rows["result"], "upper": upper["stdout"]["tail"]}
sandboxes.create
const sb = await lbb.sandboxes.create({ expiresInSeconds: 600 });
await sb.files.write("data.csv", csv);
await sb.stop();    // the disk stays
await sb.resume();
await sb.delete();
sb = lbb.sandboxes.create({"expires_in_seconds": 600})
sb.files.write("data.csv", csv)
sb.stop()     # the disk stays
sb.resume()
sb.delete()
Level 4

A workflow step.

Move the same code into a workflow handler. The outer call changes. The inner calls stay as written.

  • Each call becomes a checkpointed step with a stable key.
  • A command runs once for one key, also after a worker crash.
  • The workflow's budget counts the run. The command record is its receipt.
[03] With the rest of Little Big Brain

Part of your workflows.
Part of your graph.

A sandbox belongs to one graph. What it holds and what it keeps stay inside that graph.

A step of a workflow

  • Code runs as a checkpointed step of a workflow.
  • Each call is authorized by a short-lived grant for that attempt.
  • A template step, Run code, takes code and a config.

An agent step that runs code

  • An agent gets a code tool and a workspace to read, write and run.
  • The agent reads each result as untrusted text.
  • Code output reaches the graph only as proposed writes that we check, or as Review items.

Files into the graph

  • Import a File of the graph into a workspace.
  • Keep a workspace file as a File. It names its sandbox as its origin.
  • A template can copy Files into the workspace when a sandbox starts.
Two routes
PUT /v1/sandboxes/files/content
    ?graph=main
    &sandbox=sbx_…
    &path=data/units.csv
    &source_sha256=3fa2…
Idempotency-Key: 4c1e…
POST /v1/files
    ?graph=main
    &source_sandbox=sbx_…
    &source_path=out/report.md
Idempotency-Key: 4c1e…

Results with provenance

  • Every run writes a sandbox record and a command record.
  • The command record keeps the status, exit code and times. It keeps the head and tail of the output.
  • Values of env and stdin are never stored. The record keeps the names of env and the size of stdin.
  • A run that a workflow starts also names its workflow, run and step.
[04] On its own

Use it with no workflow.
From your code or from an agent.

You need an environment and one graph. You do not need search or workflows to start.

HTTP

Every route takes the graph. A call that runs code needs an Idempotency-Key.

TypeScript and Python

The same calls, in two SDKs. Python has a sync client and an async client.

MCP

Three tools. One reads, one writes, and one asks a person before it destroys a sandbox.

Read the guide
Four ways in
POST /v1/sandboxes?graph=main
Idempotency-Key: sum-a
Content-Type: application/json

{"run": {"code": "def run(input, config):\n    return sum(input)",
         "input": [1, 2, 3]},
 "wait_ms": 30000}
import { LbbClient } from "@littlebigbrain/client";

const lbb = new LbbClient({
  baseUrl: process.env.ENDPOINT_URL!,
  apiKey: process.env.API_KEY!,
  graph: "main",
});
const { result } = await lbb.sandboxes.run({ code, input: [1, 2, 3] });
import os
from lbb import LbbClient

lbb = LbbClient(
    os.environ["ENDPOINT_URL"],
    api_key=os.environ["API_KEY"],
    graph="main",
)
result = lbb.sandboxes.run(code=code, input=[1, 2, 3]).result
lbb_sandboxes_manage
  action=run
  code="def run(input, config):\n    return sum(input)"
  input=[1,2,3]
Cleanup functions

Write a function that normalizes a sheet. Save it as a template. Call it from anywhere.

Checks on model output

A model writes a script that checks the sums of a table. Run it with no network.

Repair loops

An agent edits a file, runs the tests and repairs the code.

Report files

Code writes a report. Keep it as a File of the graph.

Capacity is limited. We tell you when a place opens.

Join the waitlist
[05] Isolation

A microVM for each sandbox.
No network. No credential.

A sandbox is a microVM with its own kernel, a workspace disk and no network.

  • Each sandbox is its own microVM, with its own kernel and disk.
  • A sandbox has no network device.
  • No credential enters a sandbox.
  • Limits cap CPU, memory, processes and I/O.
  • A sandbox reaches one channel to its host, for commands and files.
One host with three microVMsLittle Big Brain sends commands and files to a host agent. The host agent reaches three microVMs, each over one channel. Each microVM has its own kernel and workspace disk, and no network. Little Big Brainrecords, receipts, grants commands and files HostHost agent one channel each microVMown kernelworkspace diskno networkmicroVMown kernelworkspace diskno networkmicroVMown kernelworkspace diskno network
[06] FAQ

Questions about sandboxes.

Can I use sandboxes today?

Capacity is limited. Join the waitlist, and we tell you when a place opens.

Does a sandbox have network access?

No. A sandbox has no network device. Python has numpy, pandas and other packages built in.

What happens when a call is sent twice?

A command never runs twice for one key. A call that runs code needs an Idempotency-Key. The SDKs send one for you.

What does a run record?

The record keeps the status, exit code and times. It keeps the head and tail of each output stream.

How long are records kept?

A sandbox and its commands stay for 30 days after the sandbox ends. The output of a one-call run stays for 7 days.

Which languages can I run?

Python 3.13, Node 24 and bash. Each is a base template: lbb/python, lbb/node and lbb/shell.

Can an agent run code in a sandbox?

Yes, through the MCP tools. lbb_sandboxes_manage runs code, and lbb_sandboxes_delete asks a person before it destroys a sandbox.

What does it cost?

We send pricing with your invitation.

Waitlist

Places open as capacity grows.

Capacity is limited. Tell us what you would run. We write to you when a place opens.

We use your email to tell you when a place opens. See the Privacy Policy.