box for the client and sandbox for a sandbox returned by
box.sandboxes.create() or box.sandboxes.get().
Configure the client
lithosbox python to use the key you saved during installation.
For other Python environments, provide LITHOSBOX_TOKEN through the environment
or pass token= to the client. Keep credentials outside your source code.
Keep a client open while you use its sandbox handles. Call
box.close() when
finished, or use with LithosBox() as box:. Closing the client does not delete its
sandboxes.
For asynchronous code, use AsyncLithosBox, async with, and await:
Create and find sandboxes
create
box.sandboxes.create()
Returns a Sandbox. Choose at most one of image, template, or snapshot_id.
Omit all three to use the default environment.
Template and snapshot creates use the source’s CPU and memory configuration.
The SDK reuses the same sandbox ID during retries within a create call. If a call
fails without a response, inspect existing sandboxes before making a new create call.
A handle exposes
sandbox.id and sandbox.info, including its state, image, CPU,
and memory configuration. sandbox.info.datasets lists the attached datasets in
order (an empty list when there are none); sandbox.info.dataset is the first, or an
empty string. sandbox.info.allow_egress lists the sandbox’s allowed destinations
(an empty list when it has none). sandbox.info.timeout_s and sandbox.info.expires_unix_ns
report its lifetime and when it ends (both 0 when it has none). with box.sandboxes.create() as sandbox: deletes the
sandbox when the block ends.
Commands, sessions, and files
run
sandbox.run(command, *, background=False, stdin=None, stream=False, timeout=None)
Returns an ExecResult with stdout, stderr, and exit_code. Call .check() to
raise on a nonzero exit code. stdout_truncated, stderr_truncated, and truncated
indicate output limits were reached.
With
background=True, the result reports startup status. No process ID is
returned. Redirect output to a file and check the job’s eventual exit status
separately.
Foreground completion does not guarantee every child process has exited. Use
background mode explicitly for servers and workers. Synchronous commands allow
about 110 seconds; each output stream is limited to 16 MiB. Sandboxes below 1 GiB
RAM can truncate earlier, as can text that expands when JSON-encoded. Check the
truncation flags before using the result. See Run commands.
With stream=True, iterate the returned ExecStream (async for on AsyncSandbox).
Each ExecEvent has a kind: output (fd is stdout or stderr, data is raw
bytes, seq and ts order it), gap (output the sandbox dropped before this reader
asked for it, seq through gap_to), and finally exit (exit_code, reason:
exited, killed, timeout, oom, sandbox_gone or lost). The stream reconnects
on its own. stream.kill() stops the command; stream.exec_id and stream.next_seq
let sandbox.exec(exec_id=..., from_seq=..., stream=True) resume it elsewhere.
sandbox.exec(args, stream=True) is the argument-list form.
session
sandbox.session(session_id=None)
Returns a Session that keeps its working directory, environment variables, and
shell state between commands.
Use
with sandbox.session() as session: to close the shell when the block ends.
In the async client, session() is the one factory you do not await —
create() is awaited, session() is not, and the session’s own calls are:
sandbox.run().
A sandbox supports up to 256 concurrent sessions. See
Keep shell state for an example.
files
sandbox.files
Writes allow up to 4 MiB per call. Reads allow approximately 16 MiB of text or
12 MiB of binary data. Use larger-file transfers
for files beyond those limits.
write() does not append.
Public endpoints
sandbox.expose(port, public_port=None) returns IngressInfo. Its id identifies
the endpoint and its url is the public HTTPS address. Use the assigned public
port by leaving public_port unset.
Start an HTTP server on the specified sandbox port before using the URL. Remove
an endpoint with box.ingress.delete(endpoint.id). List endpoints with
sandbox.ingress() (SDK 0.6.9 and later), in the console, or with
GET /vms/{id}/ingress.
See Expose a web service for a complete example.
Outbound network
set_egress
sandbox.set_egress(*, disable_internet=False, allow_egress=None)
Replaces the sandbox’s outbound network policy and returns the refreshed handle.
The arguments are the whole policy; nothing is merged with the previous one.
Connections the new policy no longer allows are closed. An archived sandbox
applies the policy when it is unarchived. Entries follow the same rules as
create(allow_egress=...); an invalid entry raises InvalidRequestError naming it.
SDK 0.10.0 and later. See Limit outbound network access.
Lifecycle and checkpoints
See Manage sandbox lifecycle for when to use each action.
snapshot
sandbox.snapshot(*, leave_asleep=False, wait_durable=False, timeout=120)
Returns SnapshotInfo, including id, vm_id, state, and durable. The
sandbox keeps running by default. leave_asleep=True lets it rest after the
checkpoint; the next command or file operation wakes it automatically.
Use wait_durable=True to wait until saving completes, with timeout in seconds.
A timeout does not cancel saving. Restore with box.snapshots.restore(snapshot);
it accepts either a snapshot object or its ID and returns a new Sandbox.
fork
sandbox.fork(n=None, *, timeout_s=None)
Without n, return one independent Sandbox. With n, return a list of that many
copies; n=1 returns a one-element list. Up to 16 copies can be requested at once.
timeout_s gives each copy its own lifetime; a copy
never takes its parent’s (SDK 0.10.2 and later).
Copies include files and running processes. Fork between commands and reconnect
external services independently in each copy. See Save, restore, fork.
diff
box.snapshots.diff(a, b, *, content=False)
Returns what changed from snapshot a to snapshot b (snapshot objects or IDs).
It is read from the two snapshots, so nothing runs in either sandbox and either
may already be deleted. Use any two of your snapshots: before and after a step,
two forks, or two different sandboxes.
With
content=True, modified files also carry content: unified-diff hunks
for text, changed_ranges for binary files. A diff usually takes under 3
seconds. A 409 saying a snapshot must finish uploading means it is not yet
reachable where the diff runs; retry in a few seconds. A diff that has to fetch
more than about 2 GiB of changed disk from storage (the two snapshots on
different hosts, or on none) can run past the 120-second request limit; diff
nearer snapshots.
merge
sandbox.merge(source, base, *, on_conflict="fail", dry_run=False)
Applies to this running sandbox the file changes that turned snapshot base
into snapshot source, compared three ways with the sandbox’s own changes since
base. It merges files: contents, directories, symlinks, mode, and owner. It
does not merge memory or processes.
A path changed differently on both sides is a conflict; files merge whole, and a
SQLite database is one file. on_conflict="fail" applies nothing if there is any
conflict, "skip" applies everything else, and "theirs" takes the source’s
version. dry_run=True returns the plan and changes nothing.
The sandbox is snapshotted before anything changes. When something was applied,
the report’s pre_merge_snapshot_id restores the sandbox to undo the merge.
A merge writes at most 256 MiB of file content; a larger one returns
409.
Hard links arrive as separate copies, modification times become the time of the
merge, and extended attributes and sparse holes are not kept. See
Save, restore, fork.
Activity, logs, and metrics
Recent metrics cover approximately two hours at 30-second intervals. Historical
metrics use minute intervals and remain available for archived and deleted
sandboxes.
measured=false identifies a missing measurement. System logs and
recent metrics are unavailable while archived.
Recent CPU samples report milliseconds used over interval_s. Divide cpu_ms by
interval_s * 1000 * cpus for a fraction of allocated CPU capacity. Historical
points use util_seconds for the measured duration; do not assume every point
contains a full minute of measurements.
See Monitor and troubleshoot for examples.
Templates, registries, and exports
Registry credentials can also use
secret= or ECR role settings: kind="ecr-assume-role",
role_arn, and external_id. Export file links are temporary; download before their
expiry. See HTTP API for export fields.
Existing aliases include exec, exec_background, stop/start, branch, and
files.ls. The guides use run, archive/unarchive, fork, and files.list.
Errors
OrganizationFrozenError and the cpu_cap, ram_cap, and storage_cap kinds
require SDK 0.7.1 or later. Earlier versions raise a plain LithosBoxError with
status 402 for a frozen organization and report every 403 quota as kind="cap".
SandboxStoppedError subclasses ConflictError; SandboxUnhealthyError
subclasses ServerError, so a broad except ServerError catches it.
Error classes are available from lithosbox.errors. API errors expose status
and body where a response is available. SandboxStoppedError is a subclass
of ConflictError and the same class as SandboxArchivedError.
box.rate.acquire and box.rate.ops expose rate-limit information from the
client’s recent responses. They may be None before the first response. Treat the
values as advisory and follow retry_after on rate-limit errors. See
Limits and HTTP status codes.