Skip to main content

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 directory
  • output: str — Combined stdout/stderr
  • truncated: bool — Whether output was truncated
  • duration_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, coreutils
  • python — 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


Download files

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

Source Distribution

sandkasten-0.3.0.tar.gz (71.4 kB view details)

Uploaded Source

Built Distribution

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

sandkasten-0.3.0-py3-none-any.whl (13.7 kB view details)

Uploaded Python 3

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

Hashes for sandkasten-0.3.0.tar.gz
Algorithm Hash digest
SHA256 dffe4ab31a63b8a1c0da6fbc9bc72acf7d3a3c452b86abbd14fc87ea7a163e21
MD5 41ae87381ffb1c99fd18cd94409347f5
BLAKE2b-256 7533ac12eca1422e3cfab03deb9e8301121107c805fb384c3ba4191e9b2fa891

See more details on using hashes here.

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

Hashes for sandkasten-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 8c0b81f108e8611f6505ac8424d94294040aeab9168911964a5118749b81a2b7
MD5 e075fb2c8ed69ac7bb518dc70e1de519
BLAKE2b-256 bc1ae9b7aad56368b61ef2c88d444aeb8d9052eb39bee4b8ec25d052521f4cfb

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