Leap0

Sandboxes

What a sandbox is, how it behaves, and which endpoints you use to manage and invoke it.

A sandbox is an isolated runtime environment. Create one from a template, invoke it over HTTP or WebSocket, then delete it when you are done.

Why use sandboxes?

Sandboxes exist for security. They let agents execute arbitrary code, access files, and use the network without compromising your credentials, local files, or host system. This isolation is essential when agents run autonomously.

Isolation and security

Every sandbox runs in its own Firecracker microVM:

  • Firecracker is launched with the Jailer for additional process and filesystem isolation.
  • Sandboxes run on the Linux 6.1 LTS kernel.
  • Each sandbox gets dedicated network boundaries with egress policy enforcement. Control outbound access with network_policy.

See Firewall for egress configuration details.

Lifecycle

A sandbox can move through seven states:

  • snapshotting means the sandbox VM state and memory are being captured for a snapshot.
  • paused means the sandbox has been checkpointed and its compute is no longer running.
  • unpausing means Leap0 is restoring a paused sandbox back to running.

Auto-resume

Paused sandboxes automatically resume when they receive any request (invoke, filesystem, git, etc.). The caller does not need to explicitly resume the sandbox. Leap0 handles it transparently.

Create a sandbox

Set auto_pause to true if you want Leap0 to pause the sandbox when its timeout is reached.

from leap0 import Leap0Client, NetworkPolicyMode

client = Leap0Client()
sandbox = client.sandboxes.create(
    vcpu=2,
    memory=2048,
    timeout=30,
    auto_pause=True,
    env_vars={
        "NODE_ENV": "production",
    },
    network_policy={
        "mode": NetworkPolicyMode.CUSTOM,
        "allow_cidrs": ["1.2.3.4/32"],
    },
)

print(sandbox.id, sandbox.state)
import { Leap0Client, NetworkPolicyMode } from "leap0";

const client = new Leap0Client();
const sandbox = await client.sandboxes.create({
  vcpu: 2,
  memory: 2048,
  timeout: 30,
  autoPause: true,
  envVars: {
    NODE_ENV: "production",
  },
  networkPolicy: {
    mode: NetworkPolicyMode.CUSTOM,
    allowCidrs: ["1.2.3.4/32"],
  },
});

console.log(sandbox.id, sandbox.state);
await client.close();

Get a sandbox

Returns the sandbox status, resource configuration, and current state.

from leap0 import Leap0Client

client = Leap0Client()
sandbox = client.sandboxes.create()
print(sandbox.id, sandbox.state, sandbox.vcpu, sandbox.memory)
import { Leap0Client } from "leap0";

const client = new Leap0Client();
const sandbox = await client.sandboxes.get("<sandbox_id>");

console.log(sandbox.id, sandbox.state, sandbox.vcpu, sandbox.memory);
await client.close();

Invoke a sandbox

Send any HTTP or WebSocket request directly to the sandbox host. Whatever your app serves inside the sandbox is reachable.

By default, traffic is routed to the port defined by the template image's PORT environment variable. If your app serves on a different port, append -<port> to the sandbox subdomain.

Port routing

Only one port can be reached per request. To target a specific port, append -<port> to the sandbox subdomain (e.g. sbx-abc123-3000). If no port suffix is set, traffic routes to the port from the template's PORT environment variable.

Examples:

  • Default port from image metadata: https://sbx-abc123.sandbox.leap0.dev/health
  • Explicit port routing: https://sbx-abc123-3000.sandbox.leap0.dev/health

HTTP

import os

import httpx
from leap0 import Leap0Client

API_KEY = os.environ["LEAP0_API_KEY"]

client = Leap0Client()
sandbox = client.sandboxes.create()
response = httpx.get(
    sandbox.invoke_url("/<your-path>"),
    headers={"authorization": API_KEY},
)

response.raise_for_status()
print(response.text)
import { Leap0Client } from "leap0";
import WebSocket from "ws";

const apiKey = process.env.LEAP0_API_KEY ?? "<your-api-key>";
const client = new Leap0Client();
const sandbox = await client.sandboxes.get("<sandbox_id>");

const res = await fetch(sandbox.invokeUrl("/<your-path>"), {
  headers: { authorization: apiKey },
});

console.log(await res.text());
await client.close();

Server-Sent Events

import os

import httpx
from leap0 import Leap0Client

API_KEY = os.environ["LEAP0_API_KEY"]

client = Leap0Client()
sandbox = client.sandboxes.create()
with httpx.stream(
    "GET",
    sandbox.invoke_url("/<your-path>"),
    headers={
        "authorization": API_KEY,
        "Accept": "text/event-stream",
    },
) as response:
    response.raise_for_status()
    for line in response.iter_lines():
        if line:
            print(line)
import { Leap0Client } from "leap0";

const apiKey = process.env.LEAP0_API_KEY ?? "<your-api-key>";
const client = new Leap0Client();
const sandbox = await client.sandboxes.get("<sandbox_id>");

// EventSource does not support custom headers.
// Use fetch + ReadableStream to send an Authorization header.
const res = await fetch(sandbox.invokeUrl("/<your-path>"), {
  headers: {
    authorization: apiKey,
    Accept: "text/event-stream",
  },
});

const reader = res.body.getReader();
const decoder = new TextDecoder();
let buf = "";

while (true) {
  const { value, done } = await reader.read();
  if (done) break;
  buf += decoder.decode(value, { stream: true });
  const lines = buf.split("\n");
  buf = lines.pop();
  for (const line of lines) {
    if (line.startsWith("data: ")) {
      console.log(line.slice(6));
    }
  }
}

await client.close();

WebSocket

import asyncio
import os

import websockets
from leap0 import Leap0Client

API_KEY = os.environ["LEAP0_API_KEY"]

client = Leap0Client()
sandbox = client.sandboxes.create()

async def connect() -> None:
    async with websockets.connect(
        sandbox.websocket_url("/<your-path>"),
        additional_headers={"authorization": API_KEY},
    ) as ws:
        await ws.send("hello")
        response = await ws.recv()
        print(response)

asyncio.run(connect())
import { Leap0Client } from "leap0";

const apiKey = process.env.LEAP0_API_KEY ?? "<your-api-key>";
const client = new Leap0Client();
const sandbox = await client.sandboxes.get("<sandbox_id>");

const ws = new WebSocket(sandbox.websocketUrl("/<your-path>"), {
  headers: { authorization: apiKey },
});

await new Promise((resolve, reject) => {
  ws.on("open", () => ws.send("hello"));
  ws.on("message", (data) => {
    console.log(data.toString());
    ws.close();
  });
  ws.on("close", resolve);
  ws.on("error", reject);
});

await client.close();

Pause a sandbox

Pause a running sandbox. The VM state, memory, and disk are captured and uploaded, the sandbox is marked as paused, and the VM is terminated. The sandbox can later be resumed automatically when it receives a request.

from leap0 import Leap0Client

client = Leap0Client()
sandbox = client.sandboxes.create()
sandbox.pause()
print(sandbox.state)
import { Leap0Client } from "leap0";

const client = new Leap0Client();
const sandbox = await client.sandboxes.get("<sandbox_id>");

await sandbox.pause();
console.log(sandbox.state);
await client.close();

Delete a sandbox

from leap0 import Leap0Client

client = Leap0Client()
sandbox = client.sandboxes.create()
sandbox.delete()
import { Leap0Client } from "leap0";

const client = new Leap0Client();
await client.sandboxes.delete("<sandbox_id>");
await client.close();

Was this page helpful?

On this page