Skip to main content

Python SDK for the Sail sandbox platform

Project description

sail-sdk

Python SDK for Sail sailboxes.

Install

pip install sail-sdk
uv add sail-sdk

Configure

The SDK reads configuration from environment variables:

export SAIL_API_KEY=sk_...

By default the SDK talks to production:

  • API: https://api.sailresearch.com
  • Sailbox scheduler: sailbox-scheduler.sailresearch.com:443

For dev, set:

export SAIL_MODE=dev

You can also override endpoints directly:

export SAIL_API_URL=https://dev.sailresearch.com
export SAIL_SCHEDULER_URL=sailbox-scheduler.dev.sailresearch.com:443

Create A Sailbox

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=512,
)

print(sb.sailbox_id)
print(sb.status)
print(sb.worker_address)

Sailbox.create returns after the VM is running. Supported create arguments are:

  • app: a sail.App from App.find
  • image: a sail.Image value or a built custom image
  • name: sailbox name
  • cpu: vCPU count, default 1
  • memory: memory in MiB, default 512
  • ingress_ports: optional list of guest ports to expose

AMD64 image values still exist in the SDK for compatibility, but new sailboxes currently must use arm64 images. The scheduler rejects AMD64 sailbox create and image build requests.

Exec

result = sb.exec("echo hi", timeout=5).wait()

print(result.stdout)
print(result.stderr)
print(result.returncode)

timeout is the command runtime budget in seconds. Omit it to let the command run without an SDK-provided runtime limit.

Background exec starts a detached process and waits only for the launcher shell:

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

Only one exec request may run at a time for a sailbox. If another exec is already active, the SDK raises sail.SailboxExecAlreadyRunningError.

Networking

Expose guest ports when creating the sailbox:

sb = sail.Sailbox.create(
    app=app,
    image=sail.Image.debian_arm64,
    name="sandbox-net",
    ingress_ports=[3000],
)

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

listener = sb.listener(3000)
print(listener.url)
print(listener.route_status)

Use listeners() to list every exposed port:

for listener in sb.listeners():
    print(listener.port, listener.url, listener.route_status)

Use request() to ask the worker proxy to make an outbound HTTP request on behalf of the sailbox:

req = sb.request(
    "POST",
    "https://example.com/api",
    json={"hello": "world"},
    idempotency_key="example-1",
)

completed = req.wait()
print(completed.status)
if completed.response:
    print(completed.response.status_code)
    print(completed.response.text)

idempotency_key is required for request(). data and json are mutually exclusive.

Lifecycle

sb.checkpoint()  # durably checkpoint while keeping the sailbox running
sb.stop()        # checkpoint and stop
sb.start()       # resume a stopped sailbox
sb.terminate()   # permanently terminate

After stop(), exec() raises SailboxExecutionError until start() succeeds.

Custom Images

Start from the arm64 Debian base image, add build steps, then call build():

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"})
)

built_image = image.build(timeout=1800)

sb = sail.Sailbox.create(
    app=app,
    image=built_image,
    name="custom-image-demo",
)

Supported image build helpers:

  • apt_install(*packages)
  • pip_install(*packages)
  • run_commands(*commands)
  • env(dict[str, str])
  • build(timeout=1800)

Images

Current image properties:

arm64_image = sail.Image.debian_arm64
arm_image = sail.Image.debian_arm

Compatibility aliases still present but currently rejected by the scheduler for sailbox create and image build:

amd64_image = sail.Image.debian_amd64
amd_image = sail.Image.debian_amd

Errors

Common SDK exceptions:

  • sail.SailboxCreationError
  • sail.SailboxExecutionError
  • sail.SailboxExecAlreadyRunningError
  • sail.SailboxExecRequestNotFoundError
  • sail.SailboxTerminatedError
  • sail.ImageBuildError

Examples

  • examples/sailbox_smoke.py: start an arm64 Debian sailbox and run exec commands.
  • examples/sailbox_custom_image.py: build an arm64 custom image with apt_install, pip_install, run_commands, and env, then launch a sailbox from it.

Publishing

Build a distributable package locally from the repo root:

just python-sdk-build

Publish from a developer machine with a PyPI token:

export UV_PUBLISH_TOKEN=pypi-...
just python-sdk-publish

The repository also includes a GitHub Actions release workflow at .github/workflows/python-sdk-publish.yml. It publishes when you push a tag like python-sdk-v0.1.0, after verifying that the tag version matches sail.__version__.

Recommended setup:

  1. Create the sail-sdk project on PyPI.
  2. Configure PyPI Trusted Publishing for this GitHub repository and the python-sdk-publish.yml workflow.
  3. Bump sdk/python/src/sail/__about__.py.
  4. Push a matching tag: git tag python-sdk-v0.1.0 && git push origin python-sdk-v0.1.0

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

sail_sdk-0.1.2.tar.gz (29.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

sail_sdk-0.1.2-py3-none-any.whl (28.9 kB view details)

Uploaded Python 3

File details

Details for the file sail_sdk-0.1.2.tar.gz.

File metadata

  • Download URL: sail_sdk-0.1.2.tar.gz
  • Upload date:
  • Size: 29.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.7 {"installer":{"name":"uv","version":"0.11.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for sail_sdk-0.1.2.tar.gz
Algorithm Hash digest
SHA256 d7eb69a1ae2df68a34d0b6ca922fb705d1b9fb390450c7d4718d3f1466edee4a
MD5 096b70b9c22c57f1f9bf0433a8cc1b4d
BLAKE2b-256 2663c70d1ea8c1bd6d6e67774880476f79cdce2d7a311cf50ac66927b4cecb4e

See more details on using hashes here.

File details

Details for the file sail_sdk-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: sail_sdk-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 28.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.7 {"installer":{"name":"uv","version":"0.11.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for sail_sdk-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 adfbfb0b139223b1a8a5626dfd27d8268d234fbb7750dbf7e71e02229776a54b
MD5 636f18a9165d148f40da62c89b3fcaa7
BLAKE2b-256 855e7d487bd9e1e538a25742709a7955c6f2f236a9e2872f9075b848adaca2db

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page