Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.sailresearch.com/llms.txt

Use this file to discover all available pages before exploring further.

Sailboxes are persistent Linux VMs managed by Sail. They are useful for running generated code, isolated agent workspaces, test suites, web servers, or commands that need a real Linux environment.
Sailboxes are currently in beta. APIs and operational behavior may change as we stabilize the product.
Sailboxes have a number of advantages over other sandboxing providers:
  • Run indefinitely without a fixed maximum lifetime.
  • Pause and resume sandbox state, including open network connections, for any duration. This allows agent harnesses to be quiesced without any additional work required.
  • Automatically sleep Sailboxes while waiting on Sail inference calls. You are only charged while your sandbox can actively be used.

Install

pip install sail-sdk
Set your API key before using the SDK:
export SAIL_API_KEY=sk_...

Create a sailbox

Create a Sail app namespace, then start a sailbox from the Debian arm64 image:
import sail

app = sail.App.find(name="example-app", mint_if_missing=True)

sb = sail.Sailbox.create(
    app=app,
    image=sail.Image.debian_arm64,
    name="sandbox-1",
    cpu=1,
    memory_mib=1024,
    disk_gib=8,
)

print(sb.sailbox_id)
print(sb.status)
Sailbox.create() returns after the VM is running. Pass cpu, memory_mib, and disk_gib to size the sailbox, and ingress_ports to expose services.
Sailboxes should use sail.Image.debian_arm64 or sail.Image.debian_arm. We have plans to support AMD64 images soon - please contact us if you would like us to prioritise this.
Reconnect to an existing sailbox by id with Sailbox.connect():
sb = sail.Sailbox.connect("sb_...")
connect() returns a full Sailbox handle that can run commands, read and write files, manage listeners, and make network requests. It verifies the current placement for a running sailbox and resumes a paused or sleeping sailbox before returning.

Run commands

exec() starts a shell command and returns a durable exec request. Call wait() to read stdout, stderr, and the return code.
result = sb.exec("echo hi", timeout=5).wait()

print(result.stdout)
print(result.stderr)
print(result.returncode)
Use cwd to run from a working directory. Use background=True for long-lived processes such as web servers.
sb.exec("python3 -m http.server 3000", background=True, cwd="/srv/app").wait()
Multiple exec requests can be active on a sailbox at the same time. Coordinate shared files, ports, and processes in your own commands when they overlap.

Read and write files

Use write() to upload bytes, strings, or file-like objects into the sailbox filesystem and read() to fetch regular files back as bytes. Paths must be absolute. Missing parent directories are created by default. Pass mode to set POSIX permission bits; when omitted, writes default to 0o644.
sb.write("/workspace/input.txt", "hello\n")

data = sb.read("/workspace/input.txt")
print(data.decode())

Run Python functions

Decorate a Python function with @sail.function() and pass it to exec() to run it inside the sailbox. For functions, exec() waits for completion and returns the function’s return value directly. Sail runs the function with the image’s python3.
@sail.function()
def add(x: int, y: int) -> int:
    return x + y

value = sb.exec(add, 2, 3, timeout=30)
print(value)  # 5
Python functions are currently supported only for sailboxes running custom images. We plan to remove this limitation shortly.
Function execution is synchronous. background=True is not supported for functions. Remote exceptions are raised as sail.SailboxFunctionError with the remote traceback attached. This beta path sends serialized function payloads and return values through the existing exec RPC. Keep arguments and return values small; for large dataframes or artifacts, write data from inside the sailbox and return a small reference.

Expose ports

Pass ingress_ports when creating the sailbox, start a service inside the VM, then fetch the listener URL.
sb = sail.Sailbox.create(
    app=app,
    image=sail.Image.debian_arm64,
    name="web-demo",
    ingress_ports=[3000],
)

sb.exec("python3 -m http.server 3000", background=True, cwd="/srv/app").wait()

listener = sb.listener(3000)
listener.wait(timeout=60)

print(listener.url)
Ports must be unique and between 1 and 65535. Ports 22 and 10000 are reserved by the platform.

Lifecycle

Sailboxes preserve their writable disk, in-memory state, and in-flight network requests across checkpoints and resumes.
sb.checkpoint()  # Snapshot while keeping the sailbox running
sb.pause()       # Checkpoint and pause until explicit resume
sb.sleep()       # Checkpoint and sleep until network ingress, exec, or resume
sb.resume()      # Resume a paused or sleeping sailbox
sb.terminate()   # Permanently destroy the sailbox
Call checkpoint() after important setup, such as installing packages or fetching remote data. On host failure, Sail restores from the most recent completed checkpoint and does not replay commands that ran after that checkpoint.

Sleep during inference

To automatically sleep a sailbox while a foreground Sail inference call is in flight, include its ID in the request with the X-SailboxId header. Sail will resume the sailbox after the inference call completes.
response = client.responses.create(
    model="zai-org/GLM-5",
    input="Summarize the current workspace state.",
    background=False,
    extra_headers={"X-SailboxId": sb.sailbox_id},
)

Custom images

Start from the arm64 Debian base image and add build steps:
image = (
    sail.Image.debian_arm64
    .apt_install("git", "curl")
    .pip_install("requests")
    .run_commands("python3 -m pip show requests >/tmp/requests.txt")
    .env({"APP_ENV": "demo"})
)

sb = sail.Sailbox.create(
    app=app,
    image=image,
    name="custom-image-demo",
    image_build_timeout=1800,
)
Image definitions are immutable; each helper returns a new definition. Supported helpers are apt_install, pip_install, run_commands, env, and build.