VSwarm Python SDK
The VSwarm Python SDK provides typed, asynchronous access to VSwarm workspaces, sandboxes, processes, browser sessions, traces, artifacts, and runtime APIs.
Install the published SDK from PyPI:
pip install vswarm
For local VSwarm monorepo development, install this SDK in editable mode:
pip install -e "sdks/python[test]"
The Python SDK is distributed under the Apache License 2.0. That license applies to this SDK distribution; it does not change the licensing or visibility of the VSwarm server, gateway, deployment, or other private monorepo components.
Recommended browser sandbox flow:
from vswarm import Admission, BrowserPolicy, RequestOptions, Viewport, VSwarmClient
async with VSwarmClient(base_url="http://127.0.0.1:8080", token="secret") as client:
async with client.browser.session(
template="browser-chromium",
policy=BrowserPolicy(allowed_domains=["example.com"]),
viewport=Viewport(width=1440, height=900),
admission=Admission.fail_fast(),
) as browser:
obs = await browser.observe_for_agent(screenshot=True, compact_elements=True)
await browser.click(
obs.element(text="Go"),
observe_after=True,
observation={"include": {"screenshot": True, "dom": True}},
)
This is the primary SDK UX: the SDK asks VSwarm to create an owned browser session, the server creates or claims the sandbox, and cleanup is automatic on success, error, or cancellation. If the server has a compatible warm browser-chromium sandbox available, this path can avoid cold container startup. client.browser_session(...) remains as a compatibility alias for the same owned workflow.
Production services that create a session in one request and destroy it later can use detached owned session creation while still relying on SDK cleanup semantics:
browser = await client.browser.create_session(
template="browser-chromium",
policy=BrowserPolicy(allowed_domains=["example.com"]),
viewport=Viewport(width=1440, height=900),
admission=Admission.queue(timeout_seconds=30),
options=RequestOptions(request_id="agent-task-create-123"),
)
try:
obs = await browser.observe_for_agent(
options=RequestOptions(request_id="agent-task-observe-123"),
)
finally:
await browser.cleanup(missing_ok=True)
RequestOptions.request_id sets X-VSwarm-Request-ID for correlation. It does not imply
idempotency.
Workspace and sandbox creation support explicit, persisted idempotency keys. Reusing a key
with equivalent normalized input returns the original resource with idempotent_replay=true;
reusing it with different input raises VSwarmConflictError with code
idempotency_conflict. This makes a caller-controlled retry after an ambiguous transport
failure safe:
from vswarm import SandboxCreateRequest, WorkspaceCreateRequest
async with VSwarmClient(
base_url="http://vswarm.internal:8080",
token="secret",
connect_timeout=10,
timeout=60,
) as client:
workspace = await client.workspaces.create(
WorkspaceCreateRequest(
client_action_id="my-service:operation-123:workspace",
source={"type": "empty"},
)
)
sandbox = await client.sandboxes.create(
SandboxCreateRequest(
client_action_id="my-service:operation-123:sandbox",
template="base-ubuntu",
workspace={"id": workspace.id, "mount_path": "/workspace", "mode": "read_write"},
)
)
Product backends that act for an end user must use a separate delegation
credential. Configure the server with VSWARM_DELEGATED_ACTOR_TOKEN, keep that
secret out of browsers, and pass it alongside project and user. This
hardened delegation boundary requires VSwarm Python SDK 0.1.3 or newer:
client = VSwarmClient(
base_url="http://vswarm.internal:8080",
token="api-secret",
delegated_actor_token="product-backend-secret",
project="project-1",
user="user-1",
)
VSwarm rejects actor headers that are not accompanied by the delegation credential; possession of the general API token alone never grants identity impersonation.
The SDK does not retry creates automatically. Callers should retry only operations carrying a stable idempotency key, and should keep retry counts bounded.
Advanced lifecycle control is still available when a caller needs to attach browser sessions to a long-lived sandbox:
sandbox = await client.sandboxes.create(
SandboxCreateRequest(template="browser-chromium")
)
browser = await sandbox.browser.sessions.create(policy=BrowserPolicy(block_localhost=True))
try:
obs = await browser.observe()
await browser.action("click", target={"selector": "button"})
finally:
await browser.close()
await sandbox.destroy()
One-shot run execution uses the canonical runs namespace:
result = await client.runs.execute(
template="code-runner-multilang",
profile="python",
files={"/workspace/main.py": "print(input())"},
stdin="hello",
timeout_seconds=20,
)
Run-scoped trace context is available through the canonical traces namespace and the client.trace(...) async context manager:
async with VSwarmClient(base_url="http://127.0.0.1:8080", token="secret") as client:
async with client.trace(name="browser-login-task", capture_profile="debug", client_run_id="eval-42") as trace:
await trace.event("client.agent.step.started", {"step": "open-login"}, step_id="step-open-login")
async with client.browser.session(template="browser-chromium", trace=trace) as browser:
obs = await browser.observe_for_agent()
await browser.click(obs.element(text="Sign in"), observe_after=True)
await trace.download_bundle("vswarm-trace-browser-login-task.zip")
While a trace context is active, the SDK propagates X-VSwarm-Trace-ID, X-VSwarm-Client-Run-ID, and optional step/parent headers on VSwarm calls. Client-side events stay under client.* ownership and are stored alongside VSwarm runtime/browser/artifact events in the same ordered trace.
Available SDK surface:
client.system.info()client.require_contract(...)VSwarmClient.browser_capacity()VSwarmClient.reconcile_browser()client.browser.session(...)client.browser.create_session(...)client.browser.capacity()client.browser.reconcile()client.browser.attach(...)client.browser_session(...)client.runs.execute(...)client.trace(...)client.traces.create/list/get/events/artifacts/export/download_bundle(...)client.templates.list()andclient.templates.get(name)client.sandboxes.create(...),get(id), anddestroy(id)client.runtime_leases.create/list/get/reconcile(...)- runtime lease
renew/activity/checkpoint/hibernate/resumemethods and typed variants client.snapshots.create/list/get/restore(...)and typed variantssandbox.exec(...)sandbox.files.list/read/write(...)sandbox.browser.sessions.create(...)andsandbox.browser.create_session(...)- typed
browser.observe(...)returningBrowserObservation browser.observe_for_agent(...)- typed helpers:
browser.navigate,click,double_click,hover,fill,type,press,scroll,drag,select_option,wait,get_text,find_text,extract_page,extract_section,capture_page,query_elements,screenshot,upload_file,evaluate - typed
browser.act(...)for browser action objects - raw
browser.action(...)escape hatch browser.batch(...)browser.actions()andbrowser.observations()browser.cleanup(missing_ok=True),browser.close(missing_ok=True), and publicbrowser.sandbox_id/browser.session_idobservation.compact_elements()andobservation.element(...)browser.latest_screenshot_base64(observation)client.artifacts.get(id),download_bytes(id), anddownload_base64(id)
Workspace capability contract
await client.system.info() returns the server's typed version and enabled
feature set. Applications that depend on a specific runtime contract should
call await client.require_contract(...) explicitly during startup.
Workspace resources expose one canonical method per operation. Those methods
return detached, recursively immutable response models; the former raw mapping
methods and _typed twins are not part of the 0.1.5 API.
Runtime leases and snapshots
A workspace is durable state and may exist with zero live compute. A runtime lease is the authoritative allocation of live compute for that workspace. Checkpoint commits an immutable snapshot without releasing compute; hibernate quiesces runtime resources, commits the snapshot, and only then releases compute. Resume restores into a new runtime generation:
from vswarm import RuntimeActionRequest, RuntimeCreateRequest, WorkspaceCreateRequest
workspace = await client.workspaces.create(
WorkspaceCreateRequest(source={"type": "empty"})
)
lease = await workspace.create_runtime_lease(
RuntimeCreateRequest(
template="base-ubuntu",
client_action_id="task-42:create-runtime",
idle_ttl_seconds=1800,
hard_ttl_seconds=28800,
)
)
snapshot = await lease.checkpoint(
RuntimeActionRequest(
client_action_id="task-42:checkpoint",
expected_runtime_generation=lease.model.runtime_generation,
)
)
hibernated = await lease.hibernate(
RuntimeActionRequest(
client_action_id="task-42:hibernate",
expected_runtime_generation=lease.model.runtime_generation,
)
)
resumed = await lease.resume(
RuntimeActionRequest(client_action_id="task-42:resume")
)
Use a stable client action ID only for retries of the same normalized request.
Changing a request while reusing an action ID returns
idempotency_conflict. Snapshot restore verifies both archive and manifest
checksums before replacing workspace data. Old runtime-scoped resource IDs do
not control the new generation.
Reconnecting to a PTY
Install the optional stream dependency with pip install "vswarm[pty]". The
stream descriptor keeps the API bearer credential in WebSocket headers rather
than adding it to the URL:
sandbox = await client.sandboxes.get("sbx_123")
stream = await sandbox.pty.stream("pty_123", offset=last_offset)
async with stream:
async for frame in stream:
if frame["gap"]:
print("terminal replay was truncated")
consume(frame["data"])
last_offset = frame["next_offset"]
The stream also exposes versioned input, resize, signal, and close
controls. Create a fresh stream with the last acknowledged offset after a
transport disconnect; a WebSocket disconnect does not terminate the
authoritative PTY session.
ProcessClient.restart_group performs an identity-preserving, generation-fenced,
idempotent server-side restart. The SDK parser supports runtime-state contract
version 4, including aggregate version and
runtime_generation_version fields.
Request helpers build detached payloads and do not mutate caller-owned command, intent, endpoint, metadata, or options mappings.
Runtime leases and snapshots are reported as supported in workspace.v1.
Read-only leases remain unavailable until every runtime backend can enforce a
read-only workspace mount. Worker administration, deployment administration,
and billing remain outside this SDK contract.
The default transport uses httpx.AsyncClient lazily. Tests and downstream apps can inject a fake async transport with a compatible request(...) method.
browser.observe_for_agent(...) is the bounded prompt/multimodal path. It sends server-side limits for max_elements, max_dom_bytes, and max_screenshot_bytes, requests compact elements, and only asks for screenshot base64 when screenshot_base64=True.
Browser actions return BrowserActionResult objects for page-state failures as well as successes. Recoverable failures such as stale_element_ref, selector_not_found, action_timeout, and policy_blocked are exposed through result.code, result.message, and result.recoverable.
Admission and capacity
Browser sessions support typed admission options:
async with client.browser.session(
template="browser-chromium",
admission=Admission.fail_fast(),
) as browser:
...
async with client.browser.session(
template="browser-chromium",
admission=Admission.queue(timeout_seconds=30),
) as browser:
...
Capacity can be inspected before or after requests:
capacity = await client.browser.capacity(template="browser-chromium")
print(capacity.available_slots)
print(capacity.raw.get("warm_pool_ready"))
Capacity failures expose retry metadata when the server provides it:
from vswarm import VSwarmCapacityError
try:
async with client.browser.session(admission=Admission.fail_fast()) as browser:
...
except VSwarmCapacityError as exc:
print(exc.retry_after_seconds)
print(exc.capacity)
Run the live local browser smoke test against a running VSwarm API:
PYTHONPATH=sdks/python python sdks/python/scripts/live_browser_smoke.py --api http://127.0.0.1:8080
Compatibility and releases
Workspace file changes use the bounded durable SSE stream rather than polling:
from vswarm import WorkspaceFileEventSubscribeRequest
request = WorkspaceFileEventSubscribeRequest(
sandbox_id="sbx_123",
runtime_generation="generation-4",
after_sequence=17,
)
async for item in client.events.subscribe_workspace_files(request):
print(item)
The iterator closes the response on completion, cancellation, and contract
failure. EventStreamResyncRequired tells consumers to refresh their bounded
workspace projection before resuming.
The SDK requires Python 3.10 or newer. The public API remains provisional while
the SDK is on the 0.x release line, so consumers should pin an explicitly
tested range. Releases may remove provisional compatibility surfaces when the
replacement server/SDK contract is made mandatory; those removals are called
out in the changelog.
Use an explicit contract requirement when an application must fail closed against an incompatible VSwarm server:
from vswarm import ContractRequirement, VSwarmClient
async with VSwarmClient(base_url="https://api.example.com", token="secret") as client:
await client.require_contract(ContractRequirement(
minimum_api_version="0.2.0",
runtime_state_contract_version="4",
required_features=frozenset({"runtime_leases", "snapshots"}),
))
License
The VSwarm Python SDK is licensed under the Apache License 2.0. This SDK license does not apply to the private VSwarm server or other monorepo components.
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 vswarm-0.1.12.tar.gz.
File metadata
- Download URL: vswarm-0.1.12.tar.gz
- Upload date:
- Size: 94.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
673709ad757e659b45853ae4144c4c40473493714edf94cd67cc42d5ede46036
|
|
| MD5 |
2322d12a383639feeacc1596046bd136
|
|
| BLAKE2b-256 |
5061bc87b448371ac2a6f0f02cdf20d76a8118700b4e6cc23d31a066a8bb8ee9
|
Provenance
The following attestation bundles were made for vswarm-0.1.12.tar.gz:
Publisher:
python-sdk-release.yml on akshaypainjane/vswarm
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
vswarm-0.1.12.tar.gz -
Subject digest:
673709ad757e659b45853ae4144c4c40473493714edf94cd67cc42d5ede46036 - Sigstore transparency entry: 2489117389
- Sigstore integration time:
-
Permalink:
akshaypainjane/vswarm@25c72969e3803b7e40fda3113e885f202d73e420 -
Branch / Tag:
refs/tags/python-sdk-v0.1.12 - Owner: https://github.com/akshaypainjane
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-sdk-release.yml@25c72969e3803b7e40fda3113e885f202d73e420 -
Trigger Event:
push
-
Statement type:
File details
Details for the file vswarm-0.1.12-py3-none-any.whl.
File metadata
- Download URL: vswarm-0.1.12-py3-none-any.whl
- Upload date:
- Size: 84.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7abc0731196120ab931a4ba7601b50ca03c2bea0d29429aceeaeede7b2110281
|
|
| MD5 |
281c75111d7a0439ef0be410b10b280f
|
|
| BLAKE2b-256 |
d49e13d73517ec4af161d3e7f5d0869c6806051ddb174d11bc590583436330af
|
Provenance
The following attestation bundles were made for vswarm-0.1.12-py3-none-any.whl:
Publisher:
python-sdk-release.yml on akshaypainjane/vswarm
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
vswarm-0.1.12-py3-none-any.whl -
Subject digest:
7abc0731196120ab931a4ba7601b50ca03c2bea0d29429aceeaeede7b2110281 - Sigstore transparency entry: 2489117412
- Sigstore integration time:
-
Permalink:
akshaypainjane/vswarm@25c72969e3803b7e40fda3113e885f202d73e420 -
Branch / Tag:
refs/tags/python-sdk-v0.1.12 - Owner: https://github.com/akshaypainjane
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-sdk-release.yml@25c72969e3803b7e40fda3113e885f202d73e420 -
Trigger Event:
push
-
Statement type: