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.
For dev or staging, set SAIL_MODE:
export SAIL_MODE=staging # or dev
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_mib=1024,
)
print(sb.sailbox_id)
print(sb.status)
print(sb.worker_address)
Sailbox.create returns after the VM is running. Supported create arguments are:
app: asail.AppfromApp.findimage: asail.Imagevalue or a built custom imagename: sailbox namecpu: vCPU count, default1memory_mib: memory in MiB, default1024disk_gib: writable disk size in GiB, default1ingress_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.
Daemon Sailboxes
Use Sailbox.create_daemon when the sailbox should start and manage one long-running process. Daemon sailboxes support lifecycle operations, listeners, and outbound requests, but public exec() is disabled after the daemon is registered.
import sail
app = sail.App.find(name="daemon-demo", mint_if_missing=True)
sb = sail.Sailbox.create_daemon(
app=app,
image=sail.Image.debian_arm64,
name="daemon-1",
command="python3 -m http.server 3000",
can_checkpoint_cmd="true",
checkpoint_poll_frequency_s=5,
min_checkpoint_cooldown_s=30,
ingress_ports=[3000],
)
print(sb.sailbox_id)
print(sb.daemon_pgid)
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)
listener.wait(timeout=60)
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() and ensures only a single request is sent from the client side. data and json are mutually exclusive.
You can refresh, wait for, or cancel a tracked request:
req.refresh()
req.wait(timeout=30)
req.cancel()
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
amd64_image = sail.Image.debian_amd64
amd_image = sail.Image.debian_amd
Common SDK exceptions:
sail.SailErrorsail.SailboxErrorsail.SailboxCreationErrorsail.SailboxExecutionErrorsail.SailboxExecAlreadyRunningErrorsail.SailboxExecRequestNotFoundErrorsail.SailboxTerminatedErrorsail.SailboxWorkerLostErrorsail.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 withapt_install,pip_install,run_commands, andenv, 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:
- Create the
sail-sdkproject on PyPI. - Configure PyPI Trusted Publishing for this GitHub repository and the
python-sdk-publish.ymlworkflow. - Bump
sdk/python/src/sail/__about__.py. - Push a matching tag:
git tag python-sdk-v0.1.0 && git push origin python-sdk-v0.1.0
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file sail_sdk-0.1.3.tar.gz.
File metadata
- Download URL: sail_sdk-0.1.3.tar.gz
- Upload date:
- Size: 32.7 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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fe98ca3f279224f4ff9644aa416c84e683f852045bbb55173b9cb0e727bad411
|
|
| MD5 |
0c33fd0251ec87f2631f0d8e45a62b60
|
|
| BLAKE2b-256 |
1f956b2788a23d653b3e143aec6264fbf17d850356c4b2d27c628a96a1c23dee
|
File details
Details for the file sail_sdk-0.1.3-py3-none-any.whl.
File metadata
- Download URL: sail_sdk-0.1.3-py3-none-any.whl
- Upload date:
- Size: 31.0 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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1e6a4a04659dbc7b96520bceba0281fc1fe15f209e108ee70bcf1ac7919e69b9
|
|
| MD5 |
f668185d9f05242989001b152b08bc2a
|
|
| BLAKE2b-256 |
9f59241c141f4d54ee0ad16945353324b7f4509893d509ba9b2b4fb0ebd1efeb
|