Skip to main content
Images define the root filesystem a Sailbox boots from: start from a base image, optionally chain build steps, and pass the result to Sailbox.create. @sail.function additionally lets Python ship a local function into a Sailbox and run it as if it were local. See the Images guide for a task-oriented walkthrough.

Base images

The devbox images are the Debian base plus a baked development layer: Node LTS with npm, build-essential compilers, the OS libraries editor remote servers need, the claude and codex CLIs, and common developer tools (jq, gh, fd, fzf, uv, mise, tmux, git-lfs, and more). They boot fast because the whole layer ships prebuilt, and uv/mise lazy-install further language toolchains on demand. The trade-off is that they are prebuilt only: builder methods such as apt_install and pip_install are rejected on a devbox base. Use a debian base when you need custom build steps. Devbox images also have a working clipboard. During sail box shell, Ctrl+V puts your local clipboard on the guest’s clipboard. Pasting a screenshot into claude or codex works exactly as it does on your own machine, and text copied inside the guest is copied back to your local clipboard. In Python, sail.Image.debian_arm64 and debian_amd64 (aliases debian_arm / debian_amd) pin the image to your local Python version so @sail.function can deserialize local bytecode.

The image builder

An image definition is an immutable value. Builder methods return a new definition, so you chain them and either pass the result straight to Sailbox.create (which builds it for you) or call build() to build eagerly.

apt_install

Adds a step that installs Debian packages with apt. Requires at least one non-empty package name.

pip_install

Adds a step that installs Python packages with pip. Requires at least one non-empty package name.

run_commands

Adds one build step per shell command, in order. Each command must be non-empty.

add_local_file

Bakes the contents of one local file into the image at remote_path. Only the file’s content hash, target path, and mode identify the image, so a one-byte change forces a rebuild. Raises an invalid-argument error if the source is missing, the path is invalid, or the file exceeds the 5 GiB single-file limit.

add_local_dir

Bakes a local directory into the image at remote_path. Each regular file is hashed and uploaded; per-file modes come from the local stat. Symlinks are skipped. ignore takes gitignore-style patterns, or point at an existing ignore file (such as .gitignore) instead. remote_path must be absolute.

env

Sets environment variables baked into the image. Requires at least one non-empty key.

build

Builds the image and blocks until it is ready, returning a built definition you can create Sailboxes from. timeout bounds the whole pipeline (local file uploads and the build) and must be > 0. Raises an image-build error if the build fails and a timeout error if it does not finish within timeout.
You rarely need to call build() yourself: passing an unbuilt definition to Sailbox.create builds it first (bounded by image_build_timeout).

@sail.function

Python only.
Decorates a Python function so it can run inside a Sailbox via Sailbox.exec. The decorator returns a SailFunction; calling it locally still invokes the original function unchanged.
When you pass a SailFunction to exec, the call blocks and returns the function’s return value directly (not a ExecProcess). The SDK serializes the function plus its arguments, runs it with the image’s python3, and returns the deserialized result. Constraints:
  • Function execution is synchronous; background=True is not supported.
  • The Sailbox’s python3 must match your local Python major.minor, because the serialized bytecode is version-sensitive. This is why the debian bases pin the local version.
  • Imported third-party packages are referenced by name, so they must exist in the Sailbox environment.
  • Keep arguments and return values small; write large artifacts from inside the Sailbox and return a small reference instead.
Raises sail.SailboxFunctionError (with the remote error_type, traceback, stdout, stderr attached) when the function raises remotely, and sail.SailboxFunctionSerializationError if the payload or result cannot be serialized or the runtime cannot be prepared. See Errors.

SailFunction

The wrapper returned by @sail.function. You normally don’t construct it directly. Calling a SailFunction locally is identical to calling the wrapped function. Async functions, async generators, and generator functions are rejected at decoration time with TypeError.