WBX Sandbox

Examples

Copy-paste recipes for the most common jobs. They use the Python SDK and expect WBXSANDBOX_URL and WBXSANDBOX_API_KEY in the environment.

Give an AI model a "run code" tool

The model decides it needs to compute something, writes Python, and you run it in a sandbox and send the output back. This example uses the Anthropic API; the same pattern works with OpenAI or any model with tool calling.

import anthropic
from wbxsandbox import Sandbox

client = anthropic.Anthropic()
tools = [{
    "name": "run_python",
    "description": "Run Python code in a secure sandbox and return what it prints.",
    "input_schema": {"type": "object", "properties": {"code": {"type": "string"}}, "required": ["code"]},
}]

with Sandbox.create(template="code-interpreter", timeout=600) as sb:
    messages = [{"role": "user", "content": "What is the 50th Fibonacci number? Compute it."}]
    while True:
        resp = client.messages.create(model="claude-sonnet-5-5", max_tokens=2048,
                                      tools=tools, messages=messages)
        messages.append({"role": "assistant", "content": resp.content})
        if resp.stop_reason != "tool_use":
            print(resp.content[-1].text)
            break
        results = []
        for block in resp.content:
            if block.type == "tool_use":
                r = sb.run_code(block.input["code"], timeout=120)
                results.append({"type": "tool_result", "tool_use_id": block.id,
                                "content": (r.stdout + r.stderr)[-10000:] or "(no output)"})
        messages.append({"role": "user", "content": results})

Using ChatGPT, Claude Code, Claude Desktop or claude.ai? You don't need any code – connect over MCP.

Analyse a spreadsheet and get a chart

from wbxsandbox import Sandbox

with Sandbox.create(template="code-interpreter") as sb:
    sb.files.write("/home/user/sales.xlsx", open("sales.xlsx", "rb").read())
    r = sb.run_code("""
import pandas as pd, matplotlib.pyplot as plt
df = pd.read_excel("/home/user/sales.xlsx")
print(df.describe())
df.groupby("region")["revenue"].sum().sort_values().plot(kind="barh", figsize=(8, 4))
plt.tight_layout()
plt.savefig("/home/user/revenue.png", dpi=150)
""")
    print(r.check().stdout)
    open("revenue.png", "wb").write(sb.files.read("/home/user/revenue.png"))

Screenshot a web page

from wbxsandbox import Sandbox

with Sandbox.create(template="browser") as sb:
    r = sb.run_code("""
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
    page = p.chromium.launch().new_page(viewport={"width": 1280, "height": 800})
    page.goto("https://news.ycombinator.com")
    print(page.title())
    page.screenshot(path="/home/user/page.png", full_page=True)
""", timeout=120)
    print(r.check().stdout)
    open("page.png", "wb").write(sb.files.read("/home/user/page.png"))

Run a repository's tests

Typical for coding agents: check that a change really works before proposing it.

from wbxsandbox import Sandbox

with Sandbox.create(template="base", timeout=1200) as sb:
    sb.run("git clone --depth 1 https://github.com/psf/requests.git", timeout=120).check()
    sb.run("pip install -e '.[socks]' pytest", cwd="/home/user/requests", timeout=300).check()
    r = sb.run("pytest -q -x tests/test_utils.py", cwd="/home/user/requests", timeout=600)
    print("passed" if r.ok else "failed")
    print(r.stdout[-3000:])

Run untrusted code without internet

For code from users, students or the internet: switch the network off so nothing can be downloaded or sent anywhere, and keep the timeout short.

from wbxsandbox import Sandbox

submission = open("homework.py").read()
with Sandbox.create(template="mini", timeout=60, internet=False) as sb:
    sb.files.write("/home/user/main.py", submission)
    r = sb.run("python3 main.py < /dev/null", cwd="/home/user", timeout=10)
    print("exit", r.exit_code, "timed out" if r.timed_out else "")
    print(r.stdout[:2000])

Need only some websites? Use allow=["pypi.org", "files.pythonhosted.org"] instead of internet=False.

Keep one sandbox for a whole conversation

Files and installed packages survive between the user's messages: remember the sandbox id, attach to it on every turn, and pause it while the user is thinking.

from wbxsandbox import Sandbox

# first message of the conversation
sb = Sandbox.create(template="base", timeout=3600)
save_to_session("sandbox_id", sb.id)

# every following message
sb = Sandbox.connect(load_from_session("sandbox_id"))
if sb.state == "paused":
    sb.resume()
sb.set_timeout(3600)                                  # keep it alive while the chat is active
print(sb.run("ls /home/user").stdout)
sb.pause()                                            # not billed while the user is away

# when the conversation ends
sb.kill()

Show output live

from wbxsandbox import Sandbox

with Sandbox.create(template="base") as sb:
    r = sb.run("pip install pandas scikit-learn", timeout=300,
               on_stdout=lambda s: print(s, end=""),
               on_stderr=lambda s: print(s, end=""))
    print("exit", r.exit_code)

Run many jobs in parallel

Each job gets its own clean machine. You pay for the seconds each one runs, so 50 parallel jobs cost the same as 50 jobs one after another – they just finish 50× sooner.

from concurrent.futures import ThreadPoolExecutor
from wbxsandbox import Sandbox

def job(n):
    with Sandbox.create(template="mini", timeout=120) as sb:
        return sb.run(f"python3 -c 'print(sum(i*i for i in range({n})))'").stdout.strip()

with ThreadPoolExecutor(max_workers=20) as pool:
    for result in pool.map(job, [10**5, 10**6, 10**7] * 10):
        print(result)

How many sandboxes you can run at once depends on your plan. If you hit the limit the API answers 429 – retry after a moment.