Skip to content

Monty

CICoveragePyPINPMcrates.iolicenseJoin Slack

A minimal, secure Python 3.14 interpreter written in Rust for use by AI.

Monty avoids the latency, complexity and cost of using a full container based sandbox for running LLM generated code.

Latency

Time to create a sandbox and run 10 REPL commands

SandboxCold startAgent run, warm†Combined‡
Monty4.50 ms0.40 ms4.90 ms
Full Monty (WebSocket)3.50 ms3.90 ms7.40 ms
WASI / wasmtime16 ms180 ms200 ms
Docker195 ms700 ms900 ms
Sandboxing service (Daytona)1500 ms400 ms1900 ms
Pyodide in Deno2700 ms35 ms2700 ms

† 10 commands run in a REPL against a sandbox that already exists, as you might expect from a simple agent with code mode. Monty and Full Monty keep the session, so each command is one feed; the others have no persistent interpreter, so command n re-runs commands 1 to n.

‡ The time to create the sandbox and perform the agent run: the two columns added together.

Learn more in the comparison to alternatives.

Why Monty

  1. Latency in microseconds, not seconds. A sandbox plus ten REPL commands takes 5 ms against 900 ms for Docker and 1900 ms for a sandboxing service, because the sandbox is a subprocess, a command is one message each way, and the session persists so nothing is re-run. See start latency.
  2. Suspend and resume from bytes. Every host call suspends the interpreter; feed_start returns the suspension and dump() serialises the whole interpreter, paused call stack included, to bytes you can store and load_snapshot later on another machine. There are no file descriptors, sockets or threads inside the sandbox, so nothing has to be reconstructed. See snapshots.
  3. Strict resource limits max_memory, max_duration_secs and max_recursion_depth are enforced by the VM itself, and max_suspensions by the pool; 'x' * 10**12 raises MemoryError before the allocation is attempted. See resource limits.
  4. A package, not infrastructure. uv add pydantic-monty, npm install @pydantic/monty or cargo add monty-pool: about 4.5 MB, no daemon, no image, no API key, and a worker baseline of about 2 MB so one machine runs hundreds. See getting started.
  5. MIT licensed, with commercial options. The interpreter, the pool and bindings are open source. Full Monty runs the same workers behind a WebSocket as a container image, adding OS-level isolation, and horizontal scaling.

Example

Installation

Terminal
uv add pydantic-monty

See getting started with Python.

The code string is what a model writes when asked how long a bar of chocolate could power a lightbulb. It calls a tool it was given, does arithmetic it should not do in its head, and prints the answer:

from pydantic_monty import Monty

code = """
kcal = nutrition('chocolate bar')['kcal']
hours = kcal * 4184 / (bulb_watts * 3600)
print(f'a chocolate bar could power a {bulb_watts}W bulb for {hours:.1f} hours')
"""

with Monty() as pool:
    with pool.checkout() as session:
        session.feed_run(
            code,
            inputs={'bulb_watts': 10},
            external_lookup={'nutrition': lambda food: {'kcal': 230}},
        )
        #> a chocolate bar could power a 10W bulb for 26.7 hours

Or in TypeScript:

import { Monty } from '@pydantic/monty'

const code = `
kcal = nutrition('chocolate bar')['kcal']
hours = kcal * 4184 / (bulb_watts * 3600)
print(f'a chocolate bar could power a {bulb_watts}W bulb for {hours:.1f} hours')
`

await using pool = await Monty.create()
await using session = await pool.checkout()
await session.feedRun(code, {
  inputs: { bulb_watts: 10 },
  externalLookup: { nutrition: (food: string) => ({ kcal: 230 }) },
})
// a chocolate bar could power a 10W bulb for 26.7 hours

nutrition ran on the host and the sandbox saw only its return value; the sandbox has no filesystem, environment or network with which to reach anything else. The Python, JavaScript and Rust quickstarts take it from here. Monty can do much more than this, see Examples.

Where the code comes from

LLMs are often faster, cheaper and more reliable when they write a short program that calls your tools, instead of making a sequence of individual tool calls: code mode from Cloudflare, programmatic tool calling and code execution with MCP from Anthropic, smolagents from Hugging Face. All of them need somewhere safe to run the generated code, and Monty is that place.

Next steps