Skip to main content
Install thunder-sandbox, then import it under the short thunder alias.
The same Client, Sandbox, and Process classes support synchronous and asynchronous applications. Every blocking operation has an awaitable _async twin, such as Sandbox.create_async(), sandbox.exec_async(), and process.wait_async(). Properties such as id, status, and returncode remain synchronous.

Sandbox.create

Starts a sandbox and returns immediately. If command arguments are supplied, it waits for the sandbox and starts that command before returning.
Signature
string
Optional command and arguments to start once the sandbox is running.
string
Optional label, unique among live sandboxes. Use the returned id to address the sandbox.
Mapping[str, str | None]
Environment variables set for SSH sessions. Entries whose value is None are omitted. Names must match [A-Za-z_][A-Za-z0-9_]*.
int | None
default:"300"
Sandbox lifetime in seconds, measured from creation. Use None to disable automatic expiry.
integer
default:"4"
Number of vCPUs.
integer
default:"32"
Memory in GiB.
integer
default:"50"
Ephemeral disk size in GiB.
GPUType
GPU type, such as thunder.GPUType.H100. Supply it together with gpu_count.
integer
Number of GPUs. Currently, sandboxes support one GPU. Supply it together with gpu_type. Contact us if you are interested in larger configurations.
boolean
default:"false"
Blocks outbound internet access. Choose either this option or an allowlist.
Sequence[str]
IPv4 CIDRs the sandbox may reach.
Sequence[str]
DNS names the sandbox may resolve. Use *.example.com for subdomains.
Client
Reuse an existing authenticated client.
SSH authentication uses an organization certificate as described in SSH authentication. Public internet access is allowed by default. Private, metadata, and other sandbox networks remain blocked, and inbound access is limited to SSH.
CIDR and domain rules are independent: when both are restricted, a connection must pass both controls. A bare domain matches exactly; use *. for its subdomains.

Sandbox.update_network_policy

Replaces the complete outbound policy of a running sandbox. It accepts the same network options as Sandbox.create.
Signature
None leaves that policy dimension unrestricted, while an empty sequence blocks it. The call returns after Thunder accepts the new policy; enforcement on the sandbox node converges asynchronously. Established connections may remain open after a policy is tightened.

Sandbox.from_id

Retrieves a sandbox by its permanent API ID.
Signature
Use IDs when storing or reconnecting to a sandbox. Names are reusable labels.

Sandbox.from_name

Finds the live sandbox with the given name. It raises NotFoundError when no live sandbox has that name and ConflictError if the name is ambiguous.
Signature
Names are unique only while a sandbox is live and may be reused after it stops. Prefer Sandbox.from_id when you know the ID. Sandbox handles expose these properties:

SSH authentication

The SDK authenticates your machine with one Ed25519 key and a short-lived SSH certificate scoped to your organization. The private key remains on your machine. The API signs its public half, and every sandbox in the organization trusts that authority, so you can reconnect to existing sandboxes from any authenticated machine. The credential is created lazily on the first SSH operation, reused across sandboxes, and renewed automatically before expiry. The SDK caches it under ~/.thunder/sandbox_keys/ by default:
Set TNR_HOME to move the cache. When the cache directory is unwritable, the SDK holds the key and certificate in memory for command execution and file transfers. sandbox.ssh exposes the host, port, user, and cached credential paths. sandbox.ssh_command returns a tuple suitable for subprocess or shell display, including the private key, certificate, and options required for short-lived hosts:
The command uses the cached files, so run at least one SDK SSH operation such as exec, upload, or download before shelling out. Manual SSH requires a writable cache directory. Because nodes reuse forwarded ports, the generated command sends host-key records to /dev/null; the SDK pins a sandbox’s host key in memory for the life of the process.

Sandbox.wait_until_ready

Polls with jittered backoff until the sandbox reports ready. Transient connection, service, and rate-limit errors are retried for a short grace period. It raises SandboxFailedError for a terminal sandbox and SandboxTimeoutError at the deadline.

Sandbox.refresh

Fetches the current sandbox state and updates the handle in place.

Sandbox.poll

Checks whether the sandbox or its main command has finished without blocking. It returns None while running, 0 when stopped successfully, or 1 when the sandbox failed.

Sandbox.wait

Waits for the command passed to Sandbox.create(*args) or, when no command was provided, for the sandbox to stop.
Signature
A deadline raises SandboxTimeoutError.

Sandbox.exec

Starts a command over SSH. Pass the executable and each argument separately.
Signature
string
required
Command followed by its arguments.
float | None
Default timeout used by process.wait().
string
Remote working directory.
Mapping[str, str | None]
Variables for this command. A None value unsets a variable.
boolean
default:"true"
Returns text streams when true and byte streams when false.
boolean
default:"false"
Requests a pseudo-terminal for interactive commands.
The returned Process exposes id, stdin, stdout, stderr, returncode, poll(), wait(), and terminate(). wait() drains both output streams into preserving buffers, so stdout and stderr remain readable after the process finishes. A process wait deadline raises asyncio.TimeoutError; Sandbox.wait() converts a timeout from the command passed to Sandbox.create(*args) into SandboxTimeoutError. stdin sends input to the remote command. write() sends data and handles backpressure, while close() sends EOF without terminating the process. Some commands, including cat, keep waiting until stdin is closed.
With text=True, streams read and write strings. With text=False, they use bytes. Set pty=True for programs which require terminal behavior; ordinary machine-driven input should use the default pipe. terminate() stops the remote command while the sandbox continues running.

Sandbox.upload

Uploads a local file or directory over the sandbox’s authenticated SSH connection.
Signature
Set recursive=True when uploading a directory.

Sandbox.download

Downloads a remote file or directory over the sandbox’s authenticated SSH connection.
Signature
Set recursive=True when downloading a directory.

Sandbox.terminate

Stops the sandbox and destroys its filesystem. If the sandbox is still being created, timeout controls how long to wait for it to become stoppable. Use None to wait indefinitely.
Signature

Client.from_cli

Creates an authenticated client from the Thunder CLI configuration.
For headless use, set TNR_API_TOKEN. TNR_API_URL overrides the API endpoint, and TNR_HOME overrides the directory containing CLI state and the shared sandbox SSH credential. Use the client as a context manager to close it automatically:

Client.create_sandbox

Creates a sandbox using this client’s authentication and configuration. It accepts the same arguments as Sandbox.create.

Client.get_sandbox

Retrieves a sandbox by its permanent API ID.

Client.get_sandbox_by_name

Finds a live sandbox by its reusable name. Prefer Client.get_sandbox when you know the ID.

Client.list_sandboxes

Iterates over active sandboxes by default. Results are newest first, and pagination is automatic. Pass "all" for complete history or one of "created", "ready", "finished", or "failed" for a single lifecycle status.
Signature

Client.close

Closes the client. Later API calls through that client raise ConnectionError.
Async methods have the same behavior and options as their synchronous twins and return the same public object types. Stream operations also use the _async suffix.
Async stdin follows the same pattern:
Clients support both synchronous and asynchronous context managers. Async sandbox listings are async iterators:
All SDK errors inherit from ThunderError.API-backed errors expose the HTTP status, machine-readable code, and optional retry_after value.