Monty and Islo: Sandbox the Snippet, Isolate the Agent

Blog

Monty and Islo: Sandbox the Snippet, Isolate the Agent

· Yossi Eliaz

Sometimes we let an agent write a little Python at runtime to reshape JSON before the next tool call. We run it in-process because spinning up a container per snippet is overkill. When it goes wrong, we want a clean exception, not surprise I/O, and definitely not a crashed worker.

A sandbox has three jobs: remove ambient capability, block escape hatches back into the host, and contain failure when something panics or spins.

Monty is for runtime-generated snippets: it deletes the dangerous builtins and forces any host access through functions you explicitly expose. Islo is for development time: zero-setup environments for AI coding agents that need a real repo and toolchain.

What Monty is for

Monty is an experimental, minimal Python interpreter written in Rust by the Pydantic team.

Monty starts by deleting capabilities. There is no open(), no __import__(), and no eval(). Host access is only through external functions you register.

Monty is moving fast. As of February 24, 2026, the latest release is v0.0.7 (published February 19, 2026).

A lot of the crash-hardening work landed in v0.0.5: fuzzing (PR #119), depth guards (PR #131), and integer overflow fixes (PR #147). v0.0.6 added suspendable REPL execution (PR #126), and v0.0.7 included more containment fixes too, like an async stack overflow fix (PR #174).

By default, the sharp edges are missing.

open("/etc/passwd")      # NameError
__import__("os")         # NameError
eval("1+1")              # NameError
import socket            # ModuleNotFoundError
import subprocess        # ModuleNotFoundError
import ctypes            # ModuleNotFoundError

That is exactly what you want for runtime code generation: compute stays in the VM, and I/O happens only where you expose it.

What still goes wrong

In a short red-team pass against Monty around the v0.0.4 era, we didn’t find a host escape.

We did find multiple ways to crash the interpreter with valid but weird programs. Many were fixed quickly, and the v0.0.5 hardening set above is a good sign. There’s still ongoing work, for example PR #124.

If you embed a VM inside your process, a panic is not just “a bug”. It is denial of service, and in multi-tenant systems it becomes a boundary question.

Three shapes show up often.

1) Arithmetic cliffs

i64::MIN / -1 is the classic one. Monty used to panic with attempt to divide with overflow. The fix is in v0.0.5 and it promotes to bigint on overflow (PR #147).

If you are embedding Monty inside your process, that panic is a worker crash.

n = -(2**63)
n // -1
divmod(n, -1)

2) Deep recursion

Deep nested structures are normal in agent workloads: JSON, ASTs, nested dicts. Without a guard, walking these during repr, equality, or hashing can blow the stack. Monty added depth guards in v0.0.5 (PR #131) after a crash class was reported (Issue #116).

x = []
for _ in range(2000):
    x = [x]
x

3) Bytecode correctness corners

There are still correctness edges where valid Python can trigger a VM panic, like nested functions where a parameter shadows an outer local (PR #124). In the PR writeup, the crash shows up as an index out of bounds panic in the VM.

def outer():
    scale = 10
    def inner(n, scale):
        return n * scale
    return inner(2, 3)

outer()

Where Islo fits

Monty is the runtime layer: execute runtime-generated Python without ambient host capability.

Islo is the development time layer: zero-setup environments you can open from anywhere, with a real repo and toolchain ready for a coding agent.

Use Monty when you need to execute small, runtime-generated Python without ambient host capability. Use Islo when you want a zero-setup environment for a coding agent and you don’t want it running on your laptop.


Monty on GitHub · Monty releases · HN discussion