Launch an isolated cloud sandbox, run real commands, stream output, move files, open a preview URL, and tear everything down from Python.
pip install createos-sandboxPython 3.10 or newer is required.
The distribution is named createos-sandbox; Python code imports createos.
from createos import Client, CreateSandboxRequest, RunCommandRequest
with Client(api_key="your-api-key") as client:
sandbox = client.create_sandbox(
CreateSandboxRequest(
name="hello-python",
shape="s-4vcpu-4gb",
rootfs="devbox:1",
)
)
try:
response = sandbox.run_command(
RunCommandRequest(
command="sh",
arguments=[
"-c",
'printf "Python says hello from $(uname -m)\\n"',
],
)
)
print(response.result.standard_output, end="")
finally:
sandbox.destroy()Python says hello from x86_64
Do not commit a real API key to source control; inject it through your application's secret manager. You can configure the endpoint, default request timeout, and retry policy when constructing the client:
from createos import Client, RetryOptions
client = Client(
api_key=api_key,
base_url="http://localhost:8080",
timeout=30,
retry=RetryOptions(max_retries=3, base_delay=0.25, max_delay=10),
)Timeout and retry delays are in seconds.
As an alternative, Client() reads CREATEOS_API_KEY and
CREATEOS_SANDBOX_BASE_URL. Explicit constructor arguments take precedence.
The owner can create one token for a sandbox. Creation and rotation return the plaintext token once; inspection returns only a redacted hint.
created = sandbox.create_access_token()
worker = sandbox.with_access_token(created.token)
result = worker.run_command(RunCommandRequest(command="echo", arguments=["hello"]))
print(result.result.standard_output)
metadata = sandbox.get_access_token()
print(metadata.token_hint)
replacement = sandbox.rotate_access_token()
# Give replacement.token to the worker instead of the old token.
sandbox.disable_access_token()Use the owner's handle to manage tokens. A delegated handle can operate its bound sandbox, including commands, files, processes, computer use, pause, resume, and destroy; it cannot manage tokens or account resources. Creating another enabled token returns HTTP 409; rotation requires an existing token. Disabling is idempotent. Revocation is immediate in the home region and propagates asynchronously to other regions.
- CreateOS Sandbox overview explains the sandbox model, lifecycle, networking, storage, and isolation.
- CreateOS Sandbox documentation contains the REST API reference and product guides.
CLAUDE.mdis the agent guide: repository conventions plus the generated cross-repo mesh block.- Runnable examples demonstrate complete SDK workflows.
- The public Python API is typed and documented with Python docstrings.
- Contributing guide documents development checks and commit conventions.
Long-running commands do not need to disappear behind a buffered HTTP call:
import sys
from createos import ExecStreamEventType, RunCommandRequest
request = RunCommandRequest(
command="sh",
arguments=[
"-c",
'for n in 1 2 3; do echo "step $n"; sleep 1; done',
],
)
with sandbox.stream_command(request) as stream:
for event in stream:
if event.type is ExecStreamEventType.STDOUT:
print(event.data, end="")
elif event.type is ExecStreamEventType.STDERR:
print(event.data, end="", file=sys.stderr)
elif event.type is ExecStreamEventType.EXIT:
print(f"exit code: {event.exit_code}")Stopping early is safe: leaving the with block closes the response body and
releases the underlying HTTP connection.
sandbox.files.upload(
"/workspace/config.json",
b'{"mode":"production"}',
)
with sandbox.files.download("/workspace/config.json") as download:
contents = download.read()upload() also accepts a binary file-like object, allowing large files to be
transferred without reading them all into memory first.
For large transfers, override the timeout for that operation without changing the client's default timeout:
from createos import RequestOptions
transfer_options = RequestOptions(timeout=30 * 60)
sandbox.files.upload(
"/workspace/archive.tar",
source,
options=transfer_options,
)
with sandbox.files.download(
"/workspace/archive.tar",
options=transfer_options,
) as download:
consume(download)The timeout applies to connection-pool waits and to each connect, read, and write operation. For downloads, the configured read timeout remains active until the body reaches EOF or the stream is closed. Uploads are not retried because an arbitrary file-like object may not be safe to replay after a partial write.
Managed processes are resources rather than fragile terminal sessions. Start one, reconnect from its output sequence, send input or signals, and wait for either the leader or its complete process tree:
from createos import (
ManagedProcessCreateRequest,
ManagedProcessWaitOptions,
ManagedProcessWaitScope,
)
process = sandbox.processes.create(
ManagedProcessCreateRequest(
command="sh",
arguments=["-c", "sleep 1; echo managed process finished"],
)
)
finished = sandbox.processes.wait(
process.process_id,
ManagedProcessWaitOptions(
scope=ManagedProcessWaitScope.TREE,
wait_timeout=30,
),
)Create a sandbox with ingress enabled, wait for the server to listen, then ask the instance for its public URL:
from createos import CreateSandboxRequest, ManagedProcessCreateRequest
sandbox = client.create_sandbox(
CreateSandboxRequest(
shape="s-4vcpu-4gb",
rootfs="devbox:1",
ingress_enabled=True,
)
)
sandbox.processes.create(
ManagedProcessCreateRequest(
command="python3",
arguments=[
"-m",
"http.server",
"8080",
"--bind",
"0.0.0.0",
],
)
)
sandbox.wait_for_port(8080, host="127.0.0.1", timeout=15)
print(sandbox.preview_url(8080))Account-level services are initialized by Client:
templates = client.templates
networks = client.networks
disks = client.disks
custom_templates = templates.list()
print(
f"{len(custom_templates)} templates ready; "
f"networks={type(networks).__name__} disks={type(disks).__name__}"
)Instance-level services are initialized when a sandbox handle is created or retrieved:
sandbox.files
sandbox.processes
sandbox.computer.mouse
sandbox.computer.keyboard
sandbox.computer.windows
sandbox.computer.screensCreate an overlay network, attach a running sandbox, and inspect the resulting membership. Cleanup runs in reverse order, so the sandbox detaches before the network is deleted:
from createos import NetworkCreateRequest
network = client.networks.create(NetworkCreateRequest(name="agent-mesh"))
try:
sandbox.attach_network(network.id)
try:
connected = client.networks.get(network.id)
for member in connected.members:
print(
f"sandbox={member.sandbox_id} "
f"private-ip={member.ip_address} "
f"status={member.status}"
)
finally:
sandbox.detach_network(network.id)
finally:
client.networks.delete(network.id)sandbox.pause().wait_until_paused()
clone = sandbox.fork()
try:
sandbox.resume().wait_until_running()
finally:
clone.destroy()
sandbox.destroy()The SandboxInstance handle safely caches the latest server projection.
Lifecycle mutations and refresh() update it, while id, name, status,
ip_address, and data provide safe reads.
Build a sandbox root filesystem from a Dockerfile, follow its build logs, and wait until the template is ready before creating a sandbox from its ID. See the custom template example for the complete workflow and cleanup.
The desktop root filesystem supports screenshots, mouse and keyboard control, clipboard access, and temporary noVNC connections. The desktop example exercises these operations.
from createos import APIError, OperationTimeout
try:
sandbox.wait_until_running()
except APIError as error:
print(
f"HTTP {error.status_code}, code={error.code}, "
f"request={error.request_id}"
)
except OperationTimeout:
# A lifecycle or readiness wait exhausted its budget.
passGET, HEAD, PUT, and DELETE requests are retried for transient network failures
and retryable server responses. HTTP 429 and 503 are retried for every method.
Configure the client with RetryOptions, or disable retries for one request
with RequestOptions(disable_retry=True).
Runnable examples live under examples/:
- Hello world
- HTTP execution server
- Command streaming
- Files and snapshots
- Ingress preview
- Private overlay network
- Custom template
- Managed process lifecycle
- Desktop and noVNC
Together these examples cover command execution, file transfer, streaming, ingress, snapshots, networking, templates, managed processes, and desktop use.
Create a virtual environment and install the development dependencies:
python -m venv .venv
.venv/bin/pip install -e '.[dev]'Run the same checks used while developing the SDK:
.venv/bin/ruff format --check src tests examples
.venv/bin/ruff check src tests examples
.venv/bin/mypy src/createos --ignore-missing-imports
.venv/bin/pytest --cov=createos --cov-fail-under=70The project follows the Google Python Style Guide. Formatting, import ordering, public docstrings, and static analysis are enforced through the project configuration.
GitHub Actions runs these quality checks, tests Python 3.10 through 3.14, builds both package distributions, and verifies that the generated wheel imports.
Commits follow Conventional Commits. See CONTRIBUTING.md for accepted types, examples, and the checks to run before opening a pull request.
src/createos/client.py client configuration and account-level operations
src/createos/instance.py stateful sandbox lifecycle and command operations
src/createos/services.py files, processes, desktop, templates, disks, networks
src/createos/models.py public requests, responses, options, and enums
src/createos/_transport.py HTTP, authentication, retries, and JSend handling
src/createos/_streams.py NDJSON, SSE, command, process, and binary streams
examples/ runnable Python programs
tests/ mocked API contract tests
CreateOS is an execution and governance platform for AI agents and applications. Learn more about isolated Firecracker-based workloads on the CreateOS Sandbox product page.
This SDK is available under the MIT License.