Skip to main content
The Podflare Python SDK gives you a Sandbox object that wraps every API operation — code execution, forking, filesystem transfers, and lifecycle management — behind a clean, typed interface. Every public symbol ships with full type annotations so your editor can autocomplete and type-check your sandbox code.

Installation

Install the package from PyPI. Python 3.10 or later is required.
pip install podflare

Configuration

1

Set the host

By default the SDK reads PODFLARE_HOST from your environment and falls back to http://127.0.0.1:7070 for local development. You can also pass the host explicitly or share a single Client across multiple sandboxes to avoid creating one httpx.Client per sandbox.
from podflare import Sandbox, Client

# Reads PODFLARE_HOST env var, falls back to http://127.0.0.1:7070
sbx = Sandbox()

# Explicit host
sbx = Sandbox(host="https://api.podflare.dev")

# Shared Client — one httpx.Client for many sandboxes
client = Client(host="https://api.podflare.dev")
a = Sandbox(client=client)
b = Sandbox(client=client)
2

Set the API key

Pass your key explicitly or export PODFLARE_API_KEY so every Sandbox() call picks it up automatically.
from podflare import Sandbox

# Explicit
sbx = Sandbox(api_key="pk_your_key_here")

# Or via environment variable
# export PODFLARE_API_KEY=pk_...
sbx = Sandbox()
For local development without an API key, the SDK falls back to http://127.0.0.1:7070 automatically. See Authentication for details.

Core methods

run_code

run_code(code: str, language: Language = "python") -> ExecResult
Blocks until the code finishes and returns an ExecResult containing stdout, stderr, and exit_code.
r = sbx.run_code("print(sum(range(10)))")
assert r.exit_code == 0
assert r.stdout.strip() == "45"

run_code_stream

run_code_stream(code: str, language: Language = "python") -> Iterator[Event]
Yields Event objects as they arrive from the sandbox. Use this when you want to display output incrementally rather than waiting for the full result.
for ev in sbx.run_code_stream("for i in range(3): print(i)"):
    if ev.type == "stdout":
        print(ev.data, flush=True)
    elif ev.type == "exit":
        print("done, exit", ev.data)

fork

fork(n: int = 1) -> list[Sandbox]
Snapshots the running sandbox and spawns n independent children, each starting from the parent’s current memory and filesystem state. Fork is nearly flat in cost across n because children restore in parallel — spawning 5 children takes ~101 ms on reference hardware.
children = parent.fork(n=5)
See the Fork concept page for full semantics, timing benchmarks, and the tree-search pattern.

diff

diff(other: Sandbox, paths: list[str] | None = None) -> dict
Returns a filesystem diff between this sandbox and other. The result is a dict with added, removed, and modified keys containing lists of paths. By default, /root and /tmp are compared; pass paths to restrict the comparison.
a, b = parent.fork(n=2)
a.run_code("with open('/root/a.txt','w') as f: f.write('from a')")
b.run_code("with open('/root/b.txt','w') as f: f.write('from b')")

d = a.diff(b)
# {"added": ["/root/b.txt"], "removed": ["/root/a.txt"], "modified": []}

merge_into

merge_into(winner: Sandbox) -> None
Commits winner’s state as the new state of the parent. After this call, the parent’s ID remains valid and now drives winner’s VM. Calling winner.close() becomes a no-op.
parent.merge_into(winner)
# parent.id still valid, now drives winner's VM

upload and download

upload(data: bytes, remote_path: str) -> None
download(remote_path: str) -> bytes
Transfer small files to and from the sandbox filesystem. Best suited for files up to a few MB.
sbx.upload(b"hello", "/root/hello.txt")
assert sbx.download("/root/hello.txt") == b"hello"

close and context manager

close() -> None
Destroys the sandbox and releases its resources. Use the context manager form whenever possible — it calls close() automatically even if an exception is raised.
# Preferred: context manager
with Sandbox() as s:
    r = s.run_code("print('hello')")

# Manual: try/finally
s = Sandbox()
try:
    r = s.run_code("print('hello')")
finally:
    s.close()

Full example — fork, evaluate, merge

The following example loads a dataset once, forks five children to explore different hypotheses in parallel, picks the best result, and merges the winner back into the parent.
from podflare import Sandbox

def pick_best_index(results):
    # Your scoring logic here
    return max(range(len(results)), key=lambda i: results[i].exit_code == 0)

with Sandbox() as parent:
    parent.run_code("""
        import pandas as pd
        df = pd.read_csv('/data/medium.csv')
    """)

    plans = [
        "print(df['col_a'].mean())",
        "print(df['col_b'].mean())",
        "print(df[df.col_a > 0].shape)",
        "print(df.describe().loc['mean'])",
        "print(df.corr().iloc[0])",
    ]

    children = parent.fork(n=len(plans))
    try:
        results = [c.run_code(p) for c, p in zip(children, plans)]
        winner = children[pick_best_index(results)]
        parent.merge_into(winner)
    finally:
        for c in children:
            c.close()

Type annotations

The SDK ships full type annotations. Import ExecResult, Event, and Language from the top-level module to annotate your own functions.
from podflare import ExecResult, Event, Language
ExecResult
dataclass
Returned by run_code. Fields: stdout: str, stderr: str, exit_code: int.
Event
dataclass
Yielded by run_code_stream. Fields: type: str ("stdout", "stderr", "exit"), data: str.
Language
Literal
Literal["python", "bash"] — the set of languages accepted by run_code and run_code_stream.

Framework adapters

Use these integrations to wire Podflare sandboxes directly into AI agent frameworks.

OpenAI Agents SDK

from podflare.integrations.openai_agents import podflare_code_interpreter

Anthropic Messages API

from podflare.integrations.anthropic import handle_code_execution_tool_use