Skip to main content

Python SDK for VoidRun AI Sandbox

Project description

VoidRun Python SDK

Python client for VoidRun AI sandboxes: run commands, manage files, use pseudo-terminals, stream output, and execute multi-language code in isolated environments.

The high-level API is aligned with the official TypeScript SDK (create_sandbox, list_sandboxes, remove_sandbox, Sandbox.run_code, CodeExecutionResult, and shared defaults).

PyPI version License: MIT

Table of contents

Features

  • Sandbox lifecycle: Create, list, fetch, start/stop/pause/resume, and remove sandboxes (sync and async).
  • Shell execution: exec with optional ExecRequest; SSE streaming via exec_stream.
  • Code interpreter: run_code / interpreter.run return a structured CodeExecutionResult (stdout, stderr, success, exit_code, results, logs).
  • Files: Create, upload, download, list, move, copy, compress, extract, permissions, search, disk usage.
  • File watching: WebSocket-backed directory watches (async).
  • PTY: Ephemeral and persistent terminal sessions, resize, run_command with prompt detection.
  • Background commands: Run, list, attach, wait, kill long-running processes.

Requirements

  • Python 3.9+
  • Dependencies: see pyproject.toml (Pydantic v2, httpx, urllib3, websockets, python-dotenv, etc.).

Installation

pip install voidrun

With Poetry:

poetry add voidrun

From this repository (editable install for development):

cd py-sdk
pip install -e .

Configuration

VoidRun and AsyncVoidRun require an API key. The API base URL defaults to the hosted endpoint (DEFAULT_API_BASE_URL, aligned with the TypeScript SDK and OpenAPI servers). Set VR_API_URL or API_URL, or pass base_url=, only for self-hosted deployments.

Constructor

from voidrun import VoidRun

vr = VoidRun(
    api_key="your-api-key",  # optional if VR_API_KEY / API_KEY is set
)

Environment variables

Variable Purpose
VR_API_KEY or API_KEY API key (required unless passed to the constructor).
VR_API_URL or API_URL (Self-hosted only.) Overrides the default API base URL.

Defaults (aligned with TypeScript SDK)

Exported from voidrun:

Constant Value Meaning
DEFAULT_API_BASE_URL https://platform.void-run.com/api Default API host when VR_API_URL / API_URL are unset.
DEFAULT_SANDBOX_IMAGE "code" Default image id when creating a sandbox without image=.
DEFAULT_SANDBOX_CPU 1 Default CPU count.
DEFAULT_SANDBOX_MEM 1024 Default memory in MB.

For self-hosted VoidRun, set VR_API_URL (or API_URL) to your instance’s API root (including /api if that is how your server is mounted).

Quick start

Synchronous (recommended shape)

from voidrun import VoidRun

vr = VoidRun()  # uses VR_API_KEY; default base URL unless VR_API_URL / API_URL is set

sandbox = vr.create_sandbox(mem=1024, cpu=1)

result = sandbox.exec('echo "Hello from VoidRun"')
# Exec returns VoidRunResponse whose .data is ExecResponseData
print(result.data.stdout)

sandbox.remove()

Async

import asyncio
from voidrun import AsyncVoidRun

async def main():
    async with AsyncVoidRun() as vr:
        sandbox = await vr.create_sandbox(mem=1024, cpu=1)
        result = sandbox.exec('echo "Hello"')
        print(result.data.stdout)
        await sandbox.remove_async()

asyncio.run(main())

Context managers (auto cleanup)

Sync: exiting the block calls remove(). Async: __aexit__ calls remove_async().

with vr.create_sandbox() as sandbox:
    print(sandbox.id)
async with await vr.create_sandbox() as sandbox:
    print(sandbox.id)

Parity with the TypeScript SDK

Use the same mental model as @voidrun/sdk (or the internal TS client):

TypeScript (concept) Python
createSandbox VoidRun.create_sandbox / await AsyncVoidRun.create_sandbox
getSandbox get_sandbox
listSandboxes list_sandboxesListSandboxesResult
removeSandbox remove_sandbox or sandbox.remove()
sandbox.runCode sandbox.run_code
CodeExecutionResult CodeExecutionResult (Pydantic model)
CodeInterpreter CodeInterpreter (alias: Interpreter on sandbox.interpreter)

Listing sandboxes returns a ListSandboxesResult with:

  • .sandboxes: list of Sandbox instances
  • .meta: ListSandboxesMeta (total, page, limit, total_pages)

Core concepts

VoidRun / AsyncVoidRun

Recommended methods

  • create_sandbox(...)Sandbox
  • get_sandbox(sandbox_id)Sandbox
  • list_sandboxes(page=..., limit=...)ListSandboxesResult
  • remove_sandbox(sandbox_id)None

AsyncVoidRun exposes the same names with await and provides aclose() (and async with support) to shut down the thread pool used for API calls.

Keyword aliases

Create options accept both snake_case and camelCase where noted in code (e.g. env_vars / envVars, org_id / orgId).

Sandbox

Notable attributes: id, name, cpu, mem, org_id, status, env_vars, image, region, ref_id, auto_sleep, disk_mb, created_at, created_by.

Sub-clients:

  • .fs: file operations
  • .pty: pseudo-terminal
  • .interpreter: CodeInterpreter
  • .commands: background processes

Lifecycle:

  • start, stop, pause, resume (and *_async variants where applicable)
  • remove() / remove_async(): delete sandbox on the API
  • delete() / delete_async(): deprecated aliases for remove

info() returns self (same idea as TS sandbox.info()).

Code execution and interpreter

sandbox.exec

Accepts a command string, or keyword command=, or a full ExecRequest:

from voidrun.api_client.models.exec_request import ExecRequest

r = sandbox.exec("uname -a")
r = sandbox.exec(command="pwd", cwd="/tmp", timeout=60)
r = sandbox.exec(ExecRequest(command="ls", cwd="/"))

Return type: VoidRunResponse[ExecResponseData]: the API’s outer ExecResponse envelope is unwrapped so r.data is ExecResponseData (stdout / stderr / exit_code):

print(r.data.stdout, r.data.stderr, r.data.exit_code)

Streaming (exec_stream)

Provide callbacks for SSE events (on_stdout, on_stderr, on_exit, on_error).

Interpreter and run_code

sandbox.interpreter is a CodeInterpreter. Both interpreter.run(...) and sandbox.run_code(...) return CodeExecutionResult directly (no .data nesting):

result = sandbox.run_code("print(2 + 2)", language="python")
print(result.stdout.strip())   # "4"
print(result.success)

result = sandbox.interpreter.run("console.log(1+1)", language="javascript")

Supported languages (typical): python, javascript, typescript, node, bash, sh (as supported by your VoidRun deployment).

Background commands

run_result = sandbox.commands.run(
    "sleep 5 && echo done",
    {"DEBUG": "true"},
    "/tmp",
    0,
)
print(run_result.data.pid)

sandbox.commands.list()
sandbox.commands.connect(pid, on_stdout=..., on_stderr=..., on_exit=...)
sandbox.commands.wait(pid)
sandbox.commands.kill(pid)

Response shapes follow the generated OpenAPI models; access fields via .data on VoidRunResponse where applicable.

File system

sandbox.fs.create_file("/tmp/hello.txt")
sandbox.fs.upload_file("/tmp/hello.txt", "Hello, World!")
sandbox.fs.upload_file_from_path("/tmp/remote.txt", "/local/file.txt")

data = sandbox.fs.download_file("/tmp/hello.txt")
sandbox.fs.delete_file("/tmp/hello.txt")

result = sandbox.fs.list_files("/tmp")
files = result.data

sandbox.fs.stat_file("/tmp/hello.txt")
sandbox.fs.create_directory("/tmp/mydir")
sandbox.fs.move_file("/tmp/a.txt", "/tmp/b.txt")
sandbox.fs.copy_file("/tmp/a.txt", "/tmp/copy.txt")
sandbox.fs.change_permissions("/tmp/a.txt", "755")

sandbox.fs.head_tail("/tmp/log.txt", head=True, lines=10)
sandbox.fs.search_files("/tmp", "*.txt")
sandbox.fs.disk_usage("/tmp")

archive = sandbox.fs.compress_file("/tmp", "tar.gz")
sandbox.fs.extract_archive("/tmp/archive.tar.gz", "/tmp/extracted")

File watching (async)

import asyncio
from voidrun import AsyncVoidRun

async def watch_tmp():
    async with AsyncVoidRun() as vr:
        sandbox = await vr.create_sandbox()

        watcher = await sandbox.fs.watch(
            "/app",
            recursive=True,
            on_event=lambda evt: print(evt.get("path"), evt.get("type")),
            on_error=lambda err: print("watch error:", err),
        )

        await asyncio.sleep(60)
        watcher.close()
        await sandbox.remove_async()

asyncio.run(watch_tmp())

Pseudo-terminal (PTY)

Ephemeral session

import asyncio
from voidrun import AsyncVoidRun

async def ephemeral():
    async with AsyncVoidRun() as vr:
        sandbox = await vr.create_sandbox()
        pty = await sandbox.pty.connect(
            on_data=lambda data: print(data, end=""),
            on_error=lambda err: print("PTY error:", err),
        )
        pty.send_input('echo "Hello"\n')
        await asyncio.sleep(2)
        await pty.close()
        await sandbox.remove_async()

asyncio.run(ephemeral())

Persistent session

async def persistent():
    async with AsyncVoidRun() as vr:
        sandbox = await vr.create_sandbox()
        response = sandbox.pty.create_session()
        session_id = response.data.data.session_id

        pty = await sandbox.pty.connect(
            session_id=session_id,
            on_data=lambda data: print(data, end=""),
        )
        pty.send_input('echo "Hello"\n')
        await pty.close()

        reconnected = await sandbox.pty.connect(
            session_id=session_id,
            on_data=lambda data: print(data, end=""),
        )
        await reconnected.close()

        sandbox.pty.delete_session(session_id)
        await sandbox.remove_async()

Helpers

# After connect(...)
output = await pty.run_command("ls -la", timeout=5000, prompt="# ")
await pty.resize(80, 24)

sandbox.pty.list()
sandbox.pty.delete_session(session_id)

API reference (summary)

Exports (from voidrun import ...)

VoidRun, AsyncVoidRun, Sandbox, CodeInterpreter, Interpreter (alias), CodeExecutionResult, ListSandboxesResult, ListSandboxesMeta, DEFAULT_SANDBOX_*.

CodeExecutionResult

Field Type Description
success bool Derived from exit code.
stdout / stderr str Combined streams.
exit_code int | None Process exit code.
results Any Parsed output when applicable.
error str | None Error hint (often stderr).
logs dict e.g. stdout / stderr line lists.

OpenAPI client

The package includes a generated voidrun.api_client module. Regenerate it when the VoidRun OpenAPI specification changes (same spec as other official clients). After regen, confirm sandbox status values still match the server (e.g. running, stopped, paused, error, killed, deleted, …).

Runnable examples

The examples/ directory contains scripts for sync/async usage, exec, FS, lifecycle, PTY, background commands, and the code interpreter.

Run all examples (loads py-sdk/.env if present, sets PYTHONPATH):

chmod +x scripts/run_all_examples.sh   # once
./scripts/run_all_examples.sh

The script exits with status 1 if any example fails (useful for CI).

Single example

From the py-sdk directory (with PYTHONPATH including the repo root, same as the batch script):

export VR_API_KEY="your-api-key"
export PYTHONPATH="$(pwd)"

python3 examples/sync_usage.py
python3 examples/async_usage.py

Use an API key from the same VoidRun deployment as the API host (hosted default, or set VR_API_URL for self-hosted).

Development and tests

cd py-sdk
pip install -e .
pip install pytest pytest-asyncio pytest-mock

pytest tests/

Hatch shortcut:

hatch run test
hatch run all-examples   # runs scripts/run_all_examples.sh

Building and publishing

pip install build
python -m build

Or with Poetry: poetry build / poetry publish. See pyproject.toml for package metadata.

Error handling

Failures raise exceptions from the OpenAPI client (for example ApiException) with HTTP status and body. Parse the error body for error and details fields returned by the VoidRun API.

from voidrun import VoidRun
from voidrun.api_client.rest import ApiException

vr = VoidRun()

try:
    vr.get_sandbox("nonexistent-id")
except ApiException as e:
    print(e.status, e.body)

Troubleshooting

"API key is required …"

Set VR_API_KEY or pass api_key= to the constructor.

"Base URL is required …"

You cleared the base URL (for example empty VR_API_URL). Omit the variable to use the packaged default, or set VR_API_URL / API_URL (self-hosted) with the correct prefix (often /api).

Unauthorized / invalid API key

The key must match the VoidRun API you are calling (hosted default host or your self-hosted VR_API_URL). A local .env pointing at localhost with a cloud key (or vice versa) will return 401.

Sandbox creation failures

Respect minimum CPU and memory enforced by your org/plan. Defaults are 1 CPU and 1024 MB; increase if the API rejects smaller values.

PTY timeouts

Increase timeout in run_command, or allow more time before closing the session.

File not found

List parent directories with sandbox.fs.list_files and confirm paths inside the sandbox.

Contributing, license, support

Contributions are welcome; see the repository’s contributing guidelines if present.


Made with care by VoidRun.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

voidrun-0.0.7.tar.gz (61.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

voidrun-0.0.7-py3-none-any.whl (149.1 kB view details)

Uploaded Python 3

File details

Details for the file voidrun-0.0.7.tar.gz.

File metadata

  • Download URL: voidrun-0.0.7.tar.gz
  • Upload date:
  • Size: 61.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for voidrun-0.0.7.tar.gz
Algorithm Hash digest
SHA256 137de5d9275b881197f704a0563e8a463fee570b8131be61851535ac60096fbe
MD5 fb0661c3c06ca103c6f6b4b349f5ff07
BLAKE2b-256 43e69562c7f170572f21eeb9f72718aa806e659a0c1b1b13597c6392e3e3d6d6

See more details on using hashes here.

File details

Details for the file voidrun-0.0.7-py3-none-any.whl.

File metadata

  • Download URL: voidrun-0.0.7-py3-none-any.whl
  • Upload date:
  • Size: 149.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for voidrun-0.0.7-py3-none-any.whl
Algorithm Hash digest
SHA256 9b3b613c072b5b7b41765b4fc4f1ae70453bcbfee5726fa22b5220c8ba4179e5
MD5 8890d0182c134ebe394f04520bdc7a2c
BLAKE2b-256 497ba2d87b2036c1050d4fe93cd494e1be835580403ab8b516e855f4d7ba1b3c

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page