On Runtime, a DSPy program can run real software, not only pure Python.
DSPy's own PythonInterpreter runs code in Pyodide, a WebAssembly build of
Python, under Deno on your machine. That keeps code off your filesystem. But it
offers no shell and no compiler, and only the packages built for Pyodide. A
Runtime sandbox is an Ubuntu 24.04 microVM with its own kernel, Python 3.12,
Node.js 24, gcc, pip and sudo. dspy 3.4.1 was the current PyPI release on 25
October 2026.
Where DSPy runs code
| Module | Default interpreter | What the code can use |
|---|---|---|
dspy.ProgramOfThought |
PythonInterpreter (Deno and Pyodide) |
Pyodide's Python and its packages |
dspy.CodeAct |
PythonInterpreter |
Pyodide's Python, plus the tools you pass |
dspy.RLM |
PythonInterpreter |
Pyodide's Python, plus the tools you pass |
dspy.ReAct with Runtime tools |
A Runtime microVM | A bash shell, any package, files, the network you allow |
The PythonInterpreter docstring in dspy 3.4.1 describes it as a "local
interpreter for secure Python execution using Deno and Pyodide" with "no
access to the host filesystem, network, or environment by default". It needs
Deno installed (pip install "dspy[deno]"). The three code modules accept an
interpreter_factory argument, which selects another interpreter.
ReAct with a sandbox
DSPy tools are plain Python functions with type hints and docstrings. ReAct
takes them in a list and converts them itself. sandbox_tools(sbx) returns four
such functions.
Terminalpip install dspy withruntimePythonimport dspyfrom withruntime import Sandboxfrom withruntime.tools import sandbox_toolsdef solve(task: str) -> dspy.Prediction: with Sandbox.create( network={"internet": True, "allow": ["pypi.org", "*.pythonhosted.org"]}, timeout_seconds=900, on_lease_end="stop", ) as sbx: agent = dspy.ReAct("task -> answer", tools=sandbox_tools(sbx), max_iters=12) return agent(task=task)Configure the language model first, as in any DSPy program, with
dspy.configure(lm=dspy.LM(...)). The result has answer, reasoning and a
trajectory. The trajectory records every thought, tool call and observation,
so you can see which commands ran:
Pythonresult = solve("Install sympy, then factor x**6 - 1 and print the factors.")for step, value in result.trajectory.items(): print(step, value)print(result.answer)This loop ran on 25 September 2026 with dspy 3.3.1. dspy.utils.DummyLM
scripted the model. ReAct called runtime_exec, recorded the sandbox's exit
code and stdout as the observation, and finished with the answer.
Optimizing a program that runs code
Optimizers such as MIPROv2 and BootstrapFewShot call your program once per
training example and candidate. Give each call its own sandbox inside the
module. Every trial then starts from the same clean machine. Nothing one trial
installs can leak into the next score:
Pythonimport dspyfrom withruntime import Sandboxfrom withruntime.tools import sandbox_toolsclass Solver(dspy.Module): def __init__(self): super().__init__() self.signature = dspy.Signature("task -> answer") def forward(self, task: str) -> dspy.Prediction: with Sandbox.create(network={"internet": False}, timeout_seconds=300, on_lease_end="stop") as sbx: react = dspy.ReAct(self.signature, tools=sandbox_tools(sbx), max_iters=8) return react(task=task)Runtime bills the CPU the commands use, at $0.025 per vCPU-hour. It also bills $0.0075 per GiB-hour of memory. A thousand one-minute runs at 2 vCPU and 4 GiB, each using 20 CPU-seconds, cost $0.64. A sandbox idling while the model thinks costs $0.03125 an hour (pricing). A paid account runs 100 sandboxes at the same time, so each parallel evaluation thread gets a machine.
Keep keys and budgets safe
- The LM key stays with DSPy. DSPy calls the model from your process. The sandbox receives only the commands ReAct chooses, never the key.
- No network while scoring.
network={"internet": False}gives the sandbox no network card at all, so model-written code cannot send your training data anywhere. - Tokens the code needs are stored as Runtime secrets. Inside the sandbox, they appear only as placeholders.
- A long optimization run cannot overspend. Put a daily spending limit on
the key the optimizer uses. When a create would exceed the limit, the create
fails with
spending_limit_reached. Nothing is charged (read-only keys and daily limits).
Pyodide or a microVM?
Keep PythonInterpreter when the code is short, pure Python, and needs nothing
outside Pyodide. Use Runtime when a step needs a package that Pyodide lacks, a
command-line tool, a test suite, several languages, or a file that must survive
from one step to the next. The trade-off is covered in
Pyodide vs a server sandbox and
WebAssembly vs a microVM. Evaluation at
scale is covered in agent evals and SWE-bench.
A new account gets 100 free hours of a 1 GB machine in its first 30 days, with no card
needed:
Terminalprintf '%s\n' 'print(sum([125, 250, 375]))' > invoice.pynpx withruntime sandboxes run -- python3 - < invoice.pySources
- DSPy: ReAct and tools, plain functions as tools,
max_itersandtrajectory, read 25 October 2026 - dspy on PyPI, version 3.4.1; the
PythonInterpreterdocstring and theinterpreter_factorydefaults ofProgramOfThought,CodeActandRLMwere read from that release's source on 25 October 2026
Facts on this page were checked on 25 October 2026.