shardflux
Python client for Shardflux: cloud computers for AI agents.
Open a persistent workspace by key, run commands in it, read and write its files, suspend it when idle, resume it later with its disk and memory intact, and fork it.
Early access. Shardflux is in early access. The API is versioned (
/v1), but this client is below 1.0: a minor release may contain breaking changes.
- Python 3.10 or later; one dependency (
httpx). - Typed (
py.typed). - Retries, idempotency keys, operation polling and tool-token refresh are handled for you.
Install
pip install shardflux
Quick start
Create a project API key in the Shardflux console (sfk_<key id>_<secret>). API keys are server
credentials; keep them out of client-side code.
from shardflux import Shardflux
sf = Shardflux() # reads SHARDFLUX_API_KEY; or Shardflux(api_key="...")
# Creates the workspace on first use; afterwards reconnects (or resumes) the same one.
ws = sf.open(key="customer-42/main", template="python-node-browser")
result = ws.exec("python3 -c 'print(40 + 2)'")
print(result.exit_code, result.stdout) # 0 42
ws.files.write("/home/user/notes.txt", "hello from Python\n")
print(ws.files.read_text("/home/user/notes.txt"))
ws.suspend()
open() waits until the workspace is running. Opening the same key again never resets it: files,
installed packages and running processes are still there.
Configuration
| Argument | Environment variable | Default |
|---|---|---|
api_key |
SHARDFLUX_API_KEY |
required |
base_url |
SHARDFLUX_API_URL |
https://api.shardflux.dev |
timeout |
30.0 seconds per request |
|
max_retries |
2 (safe or idempotent requests only) |
|
http_client |
a new httpx.Client (pass your own for proxies or custom transports) |
Shardflux is a context manager (with Shardflux() as sf: ...); close() closes the HTTP client
it created.
Commands
r = ws.exec("pip install requests && python3 app.py", cwd="/home/user/project", env={"DEBUG": "1"}, timeout=600)
r = ws.exec(["python3", "-V"]) # a list runs as argv, without a shell
r.exit_code, r.stdout, r.stderr, r.timed_out, r.ok
A string runs through bash -lc; a list runs as argv. timeout (seconds) is enforced inside the
workspace. Pass on_output=lambda stream, chunk: ... to receive output as it arrives. If the
connection drops, exec resumes the output from byte offsets; it never starts the command twice.
Ctrl-C cancels the command in the workspace.
Files
ws.files.write("/home/user/data.bin", b"\x00\x01\x02", create_parents=True)
data = ws.files.read("/home/user/data.bin") # bytes, the whole file
text = ws.files.read_text("/home/user/notes.txt")
ws.files.list("/home/user") # {"entries": [...], "truncated": False}
ws.files.stat("/home/user/notes.txt")
ws.files.remove("/home/user/data.bin")
Writes are atomic and durable: they are acknowledged after the file and its directory are fsynced.
Lifecycle
ws.suspend(wait=True) # memory and processes are checkpointed
ws.resume(wait=True) # or open() the key again
copy = ws.fork("customer-42/experiment") # waits until the fork is running
copy.delete() # tool access ends at once; keys are never reused
for w in sf.workspaces.list_all(key_prefix="customer-42/"):
print(w.key, w.state)
page = sf.workspaces.list(limit=50) # page.data, page.next_cursor
suspend, resume, snapshot and delete return the Operation; with wait=True they wait
for it to finish. Waiting polls with backoff (250 ms doubling to 5 s, ±20 % jitter). If timeout
(default 300 s) passes first, OperationTimeoutError is raised and the operation keeps running
server side: sf.workspaces.wait_for_operation(err.operation_id) waits again.
Errors
All errors derive from ShardfluxError.
ShardfluxApiError: the API or the workspace refused the request. It mirrors the error envelope:code,message,request_id,retryable, plusstatus,details,operation_idandretry_after.OperationFailedError: an awaited operation endedfailedorcanceled(error_code,operation).OperationTimeoutError: waiting gave up; the operation continues (operation_id).ShardfluxProtocolError: a response was not the documented shape.
from shardflux import ShardfluxApiError
try:
sf.open(key="customer-42/main", template="python-node-browser")
except ShardfluxApiError as err:
print(err.code, err.message, err.request_id, err.retryable)
Treat unknown error codes as generic errors: show message, and use retryable.
Anything else
sf.me() returns the API key's organization and project. sf.request(method, path, ...) calls
any /v1 route with the client's authentication, retries and error handling. The TypeScript SDK
(npm install @shardflux/sdk) covers the full API, including agent tool definitions for model
providers.
License
Apache-2.0
Release files for shardflux 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| shardflux-0.1.0.tar.gz | 32.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| shardflux-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 58.9 kB