Python SDK for Sandkasten — self-hosted sandbox runtime for AI agents
Project description
Sandkasten Python SDK
Python client for Sandkasten — a self-hosted sandbox runtime for AI agents.
Installation
pip install sandkasten
Or with uv:
uv add sandkasten
For OpenAI Agents SDK integration:
pip install sandkasten[agents]
# or
uv add sandkasten[agents]
Quick Start
import asyncio
from sandkasten import SandboxClient
async def main():
# Create client
client = SandboxClient(
base_url="http://localhost:8080",
api_key="sk-sandbox-quickstart"
)
# Create a session
session = await client.create_session(image="python")
try:
# Execute commands
result = await session.exec("echo 'Hello from sandbox'")
print(result.output) # Hello from sandbox
# Write a file
await session.write("hello.py", "print('Hello, World!')")
# Run it
result = await session.exec("python3 hello.py")
print(result.output) # Hello, World!
# Read files
result = await session.read("hello.py")
print(result.content.decode())
finally:
# Clean up
await session.destroy()
await client.close()
asyncio.run(main())
Usage with Context Managers
async with SandboxClient(base_url="...", api_key="...") as client:
async with await client.create_session() as session:
result = await session.exec("pip install requests")
# Session automatically destroyed on exit
API Reference
SandboxClient
Main client for managing sandbox sessions.
__init__(*, base_url: str, api_key: str, timeout: float = 120.0)
Create a new client.
- base_url: URL of Sandkasten daemon (e.g.,
http://localhost:8080) - api_key: API key for authentication
- timeout: HTTP timeout in seconds
async create_session(*, image: str = "python", ttl_seconds: int | None = None, workspace_id: str | None = None) -> Session
Create a new sandbox session.
- image: Image name (
base,python,node) - ttl_seconds: Session lifetime (None = daemon default)
- workspace_id: Persistent workspace ID (None = ephemeral)
async get_session(session_id: str) -> Session
Get an existing session by ID.
async list_sessions() -> list[SessionInfo]
List all active sessions.
async close()
Close the HTTP client.
Session
A stateful sandbox session with persistent shell and filesystem.
async exec(cmd: str, *, timeout_ms: int = 30000) -> ExecResult
Execute a shell command.
Stateful: Directory changes, environment variables, and background processes persist.
await session.exec("cd /tmp")
result = await session.exec("pwd")
print(result.cwd) # /tmp
Returns ExecResult:
exit_code: int— Exit code (0 = success)cwd: str— Current working directoryoutput: str— Combined stdout/stderrtruncated: bool— Whether output was truncatedduration_ms: int— Execution time in milliseconds
async write(path: str, content: str | bytes)
Write content to a file.
await session.write("script.py", "print('hello')")
await session.write("data.bin", b"\x00\x01\x02")
async read(path: str, *, max_bytes: int | None = None) -> ReadResult
Read a file. Returns ReadResult with content, path, and truncated fields.
result = await session.read("output.txt")
print(result.content.decode())
if result.truncated:
print("(output was truncated)")
async upload(file: str | Path | BinaryIO, *, dest_path: str = "/workspace", filename: str | None = None) -> list[str]
Upload a file via multipart form. Returns list of uploaded paths.
async stats() -> SessionStats
Get resource usage (memory_bytes, memory_limit, cpu_usage_usec).
async info() -> SessionInfo
Get session metadata (status, expiry, etc.).
async destroy()
Destroy the session and clean up resources.
Using with AI Agent Frameworks
OpenAI Agents SDK
Install the agents extra: pip install sandkasten[agents]
Pattern 1: Context-based (recommended)
from agents import Agent, Runner
from sandkasten import SandboxClient
from sandkasten import SandkastenContext, sandkasten_tools
client = SandboxClient(base_url="...", api_key="...")
session = await client.create_session(image="python")
context = SandkastenContext(session=session)
agent = Agent[SandkastenContext](
name="coding-assistant",
instructions="You have a Linux sandbox. Use the tools to execute commands and manage files.",
tools=sandkasten_tools(),
)
result = await Runner.run(
agent,
"Write a Python script that prints fibonacci numbers",
context=context,
)
print(result.final_output)
await session.destroy()
await client.close()
Pattern 2: Factory-based (simple)
from agents import Agent, Runner
from sandkasten import SandboxClient, create_sandkasten_tools
client = SandboxClient(base_url="...", api_key="...")
session = await client.create_session(image="python")
tools = create_sandkasten_tools(session)
agent = Agent(
name="coding-assistant",
instructions="You have a Linux sandbox. Use the tools to execute commands and manage files.",
tools=tools,
)
result = await Runner.run(agent, "Write a Python script that prints fibonacci numbers")
print(result.final_output)
await session.destroy()
await client.close()
Pattern 3: Per-user workspace (multi-tenant)
For different users, each gets an isolated workspace. Files persist across sessions for the same workspace_id.
from agents import Agent, Runner
from sandkasten import SandboxClient, sandbox_tools_for_workspace
client = SandboxClient(base_url="...", api_key="...")
# Per request: use workspace_id per user (e.g. from auth)
user_id = "user-123" # or f"tenant-{tid}-user-{uid}"
async with sandbox_tools_for_workspace(client, workspace_id=user_id) as (session, tools):
agent = Agent(name="coding-assistant", instructions="...", tools=tools)
result = await Runner.run(agent, user_request)
print(result.final_output)
Available tools: sandbox_exec, sandbox_write_file, sandbox_read_file, sandbox_list_files, sandbox_stats.
See examples/openai_agents/ for runnable examples (minimal + multi-user workspace).
LangChain
from langchain.tools import tool
from sandkasten import SandboxClient
client = SandboxClient(base_url="...", api_key="...")
session = None
@tool
async def sandbox_exec(cmd: str) -> str:
"""Execute a command in the sandbox."""
result = await session.exec(cmd)
return result.output
# Use with LangChain agents...
Available Images
base— Minimal Ubuntu with bash, coreutilspython— Python 3 with pip, uv, common packages (requests, httpx, pandas, numpy, matplotlib, beautifulsoup4, etc.)node— Node.js 22 with npm
Error Handling
All methods raise httpx.HTTPError on failure. Stream errors raise SandkastenStreamError:
from sandkasten import SandboxClient, SandkastenStreamError
try:
result = await session.exec("invalid-command")
except httpx.HTTPStatusError as e:
print(f"HTTP {e.response.status_code}: {e.response.text}")
try:
async for chunk in session.exec_stream("fail-cmd"):
...
except SandkastenStreamError as e:
print(f"Stream error: {e}")
Development
# Clone repo
git clone https://github.com/yourusername/sandkasten
cd sandkasten/sdk/python
# Install with uv
uv sync
# Install dev dependencies and run tests
uv sync --extra dev
pytest
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 sandkasten-0.3.0.tar.gz.
File metadata
- Download URL: sandkasten-0.3.0.tar.gz
- Upload date:
- Size: 71.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dffe4ab31a63b8a1c0da6fbc9bc72acf7d3a3c452b86abbd14fc87ea7a163e21
|
|
| MD5 |
41ae87381ffb1c99fd18cd94409347f5
|
|
| BLAKE2b-256 |
7533ac12eca1422e3cfab03deb9e8301121107c805fb384c3ba4191e9b2fa891
|
File details
Details for the file sandkasten-0.3.0-py3-none-any.whl.
File metadata
- Download URL: sandkasten-0.3.0-py3-none-any.whl
- Upload date:
- Size: 13.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8c0b81f108e8611f6505ac8424d94294040aeab9168911964a5118749b81a2b7
|
|
| MD5 |
e075fb2c8ed69ac7bb518dc70e1de519
|
|
| BLAKE2b-256 |
bc1ae9b7aad56368b61ef2c88d444aeb8d9052eb39bee4b8ec25d052521f4cfb
|