Official Python SDK for xShellz sandboxes - throwaway, gVisor-isolated Linux boxes you can run commands in.
Project description
xshellz
Official Python SDK for xShellz sandboxes: throwaway, gVisor-isolated Linux boxes you can spawn and run commands in from your own program - in three lines.
pip install xshellz
from xshellz import Sandbox
with Sandbox.create() as sbx:
result = sbx.run("python3 -c 'print(6*7)'")
print(result.stdout) # 42
# the box is destroyed when the block exits
Each sandbox is a real Linux box (root shell, package manager, network) running
under gVisor kernel isolation. Spawning is synchronous -
Sandbox.create() returns once the box is running, typically in a few seconds.
Authentication
The SDK authenticates with an xShellz personal access token (PAT) carrying the
read and write scopes:
- Create a token from your xShellz dashboard
(Settings -> API tokens), or via the API:
POST /v1/auth/tokens. - Export it:
export XSHELLZ_API_KEY="your-token"
or pass it explicitly: Sandbox.create(api_key="your-token").
Config precedence: explicit argument > XSHELLZ_API_KEY / XSHELLZ_API_URL
environment variables > default (https://api.xshellz.com/v1).
To target a staging or self-hosted control plane:
export XSHELLZ_API_URL="https://api.staging.example.com/v1"
Usage
Run commands
with Sandbox.create(name="build-box") as sbx:
r = sbx.run("apt-get update && apt-get install -y jq", timeout=300)
print(r.exit_code, r.stdout, r.stderr)
# A non-zero exit code does NOT raise - it's data:
r = sbx.run("false")
assert r.exit_code == 1
# cwd and env:
sbx.run("make test", cwd="/srv/app", env={"CI": "1"})
# Stream long-running output as it arrives:
sbx.run("npm run build", on_stdout=print, on_stderr=print)
Files (SFTP)
sbx.write_file("/tmp/config.json", b'{"debug": true}')
data: bytes = sbx.read_file("/tmp/config.json")
sbx.upload("local.txt", "/tmp/remote.txt")
sbx.download("/tmp/remote.txt", "out.txt")
Lifecycle
sbx.uuid # sandbox id
sbx.ssh_host # e.g. "shellus1.xshellz.com"
sbx.ssh_port # e.g. 42001
sbx.ssh_command # ready-to-copy "ssh -p 42001 root@..."
sbx.status # "running", "stopped", ...
sbx.detach() # keep the box alive after the `with` block
sbx.kill() # destroy the box explicitly
sbx.start() # resume an idle-stopped box
# Re-attach later (persist sbx.private_key_openssh + sbx.uuid for this):
sbx = Sandbox.connect(uuid, private_key=saved_private_key)
# Enumerate your sandboxes:
for info in Sandbox.list():
print(info.uuid, info.status)
Typed errors
from xshellz import AuthError, QuotaError, Sandbox, SandboxNotRunningError
try:
sbx = Sandbox.create()
except QuotaError:
# plan limit reached - attach to the existing box instead
existing = Sandbox.list()[0]
sbx = Sandbox.connect(existing.uuid, private_key=saved_key)
except AuthError as e:
print(e) # missing/invalid token, scope, or account verification
XshellzError- base class for everything the SDK raisesAuthError- 401/403: bad or missing token, scopes, account gatesQuotaError- plan sandbox limit reached / plan has no sandbox entitlementSandboxNotRunningError- operation needs arunningboxCommandTimeoutError-run(timeout=...)exceededApiError- any other 4xx/5xx (carries.status_codeand.body)
How it works
- Control plane: HTTPS to
api.xshellz.com/v1(create / list / start / destroy), authenticated by your PAT. - Data plane: SSH directly to the box as
root.Sandbox.create()generates an in-memory ed25519 keypair per sandbox; the private key never leaves your process and the server never sees it - only the public half is installed in the box'sauthorized_keys. - Host keys are auto-accepted. Sandbox host keys are generated at spawn
time, so there is no out-of-band fingerprint to pin. If your threat model
requires host-key verification, connect manually with your own SSH tooling
using
sbx.ssh_command.
v0 limits
- Free tier: 1 concurrent sandbox. A second
Sandbox.create()raisesQuotaErrorwhile one exists - useSandbox.list()+Sandbox.connect()to attach to the existing box, orkill()it first. Paid plans raise the limit. - Free boxes idle-stop after ~30 minutes. The box (its
/homeand your key) is preserved; callsbx.start()to resume it. - Sandbox creation is throttled to 10 requests/minute per account.
Development
python3 -m venv .venv && . .venv/bin/activate
pip install -e ".[dev]"
ruff check .
pytest
Local development (Docker)
No local Python needed — run the full lint + test suite in a container
(python:3.12-slim, pip cache persisted in a named volume):
docker compose run --rm test
The repo is mounted at /work; the container installs the package with the
[dev] extra, then runs ruff check . and pytest. Your host .venv/ is
masked inside the container, so host and container environments never mix.
License
MIT
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 xshellz-0.1.0.tar.gz.
File metadata
- Download URL: xshellz-0.1.0.tar.gz
- Upload date:
- Size: 17.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e35d01f60d84d181e931ea8fe07a6abe9ba4e79573c760653256b9e988761432
|
|
| MD5 |
b090de45122e6b23c4a0917fb9e8901a
|
|
| BLAKE2b-256 |
088b96f911bdfc84d354c1fdd48c81d449036926f2bedd7b72189f6257c25feb
|
Provenance
The following attestation bundles were made for xshellz-0.1.0.tar.gz:
Publisher:
release.yml on xshellz/xshellz-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
xshellz-0.1.0.tar.gz -
Subject digest:
e35d01f60d84d181e931ea8fe07a6abe9ba4e79573c760653256b9e988761432 - Sigstore transparency entry: 2187368089
- Sigstore integration time:
-
Permalink:
xshellz/xshellz-python@f14309d74d1438460c526f47600a5ed304912521 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/xshellz
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@f14309d74d1438460c526f47600a5ed304912521 -
Trigger Event:
push
-
Statement type:
File details
Details for the file xshellz-0.1.0-py3-none-any.whl.
File metadata
- Download URL: xshellz-0.1.0-py3-none-any.whl
- Upload date:
- Size: 16.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
66c87a37bd0f996205d7c607cec14e34fe8e1bcdf5afbe01ae4cab96bd464d1d
|
|
| MD5 |
0828453beffa44297dc3a7e3bfdf75f6
|
|
| BLAKE2b-256 |
cc7469f3c13c57df4bc458a6c8b8318337e93ffbf80bb245726a94743e844bd4
|
Provenance
The following attestation bundles were made for xshellz-0.1.0-py3-none-any.whl:
Publisher:
release.yml on xshellz/xshellz-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
xshellz-0.1.0-py3-none-any.whl -
Subject digest:
66c87a37bd0f996205d7c607cec14e34fe8e1bcdf5afbe01ae4cab96bd464d1d - Sigstore transparency entry: 2187368102
- Sigstore integration time:
-
Permalink:
xshellz/xshellz-python@f14309d74d1438460c526f47600a5ed304912521 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/xshellz
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@f14309d74d1438460c526f47600a5ed304912521 -
Trigger Event:
push
-
Statement type: