Running Pydantic’s Monty Rust sandboxed Python subset in WebAssembly
6th February 2026
There’s a jargon-filled headline for you! Everyone’s building sandboxes for running untrusted code right now, and Pydantic’s latest attempt, Monty, provides a custom Python-like language (a subset of Python) in Rust and makes it available as both a Rust library and a Python package. I got it working in WebAssembly, providing a sandbox-in-a-sandbox.
Here’s how they describe Monty:
Monty avoids the cost, latency, complexity and general faff of using full container based sandbox for running LLM generated code.
Instead, it let’s you safely run Python code written by an LLM embedded in your agent, with startup times measured in single digit microseconds not hundreds of milliseconds.
What Monty can do:
- Run a reasonable subset of Python code—enough for your agent to express what it wants to do
- Completely block access to the host environment: filesystem, env variables and network access are all implemented via external function calls the developer can control
- Call functions on the host—only functions you give it access to [...]
A quick way to try it out is via uv:
uv run --with pydantic-monty python -m asyncio
Then paste this into the Python interactive prompt—the -m asyncio enables top-level await:
import pydantic_monty code = pydantic_monty.Monty('print("hello " + str(4 * 5))') await pydantic_monty.run_monty_async(code)
Monty supports a very small subset of Python—it doesn’t even support class declarations yet!
But, given its target use-case, that’s not actually a problem.
The neat thing about providing tools like this for LLMs is that they’re really good at iterating against error messages. A coding agent can run some Python code, get an error message telling it that classes aren’t supported and then try again with a different approach.
I wanted to try this in a browser, so I fired up a code research task in Claude Code for web and kicked it off with the following:
Clone https://github.com/pydantic/monty to /tmp and figure out how to compile it into a python WebAssembly wheel that can then be loaded in Pyodide. The wheel file itself should be checked into the repo along with build scripts and passing pytest playwright test scripts that load Pyodide from a CDN and the wheel from a “python -m http.server” localhost and demonstrate it working
Then a little later:
I want an additional WASM file that works independently of Pyodide, which is also usable in a web browser—build that too along with playwright tests that show it working. Also build two HTML files—one called demo.html and one called pyodide-demo.html—these should work similar to https://tools.simonwillison.net/micropython (download that code with curl to inspect it)—one should load the WASM build, the other should load Pyodide and have it use the WASM wheel. These will be served by GitHub Pages so they can load the WASM and wheel from a relative path since the .html files will be served from the same folder as the wheel and WASM file
Here’s the transcript, and the final research report it produced.
I now have the Monty Rust code compiled to WebAssembly in two different shapes—as a .wasm bundle you can load and call from JavaScript, and as a monty-wasm-pyodide/pydantic_monty-0.0.3-cp313-cp313-emscripten_4_0_9_wasm32.whl wheel file which can be loaded into Pyodide and then called from Python in Pyodide in WebAssembly in a browser.
Here are those two demos, hosted on GitHub Pages:
- Monty WASM demo—a UI over JavaScript that loads the Rust WASM module directly.
- Monty Pyodide demo—this one provides an identical interface but here the code is loading Pyodide and then installing the Monty WASM wheel.
![Screenshot of a web app titled "Monty via Pyodide" with description "Run Monty (a sandboxed Python interpreter by Pydantic) inside Pyodide (CPython compiled to WebAssembly). This loads the pydantic-monty wheel and uses its full Python API. Code is saved in the URL for sharing." A green banner reads "Code executed successfully!" Below are example buttons labeled "Basic", "Inputs", "Reuse", "Error Handling", "Fibonacci", and "Classes". A code editor labeled "Python Code (runs inside Monty sandbox via Pyodide):" contains: "import pydantic_monty\n\n# Create interpreter with input variables\nm = pydantic_monty.Monty('x + y', inputs=['x', 'y'])\n\n# Run with different inputs\nresult1 = m.run(inputs={"x": 10, "y": 20})\nprint(f"10 + 20 = {result1}")\n\nresult2 = m.run(inputs={"x": 100, "y": 200})" with "Run Code" and "Clear" buttons. The Output section shows "10 + 20 = 30" and "100 + 200 = 300" with a "Copy" button. Footer reads "Executed in 4.0ms".](https://static.simonwillison.net/static/2026/monty-pyodide.jpg)
As a connoisseur of sandboxes—the more options the better!—this new entry from Pydantic ticks a lot of my boxes. It’s small, fast, widely available (thanks to Rust and WebAssembly) and provides strict limits on memory usage, CPU time and access to disk and network.
It was also a great excuse to spin up another demo showing how easy it is these days to turn compiled code like C or Rust into WebAssembly that runs in both a browser and a Pyodide environment.
More recent articles
- Distributing Go binaries like sqlite-scanner through PyPI using go-to-wheel - 4th February 2026
- Moltbook is the most interesting place on the internet right now - 30th January 2026