python3 script.py need an interpreter. Mirage calls that
interpreter a runtime, and you pick it per workspace. The TypeScript
packages ship two:
Pyodide (default)
Pyodide is full CPython in WebAssembly: real stdlib,sys.argv, stdin,
and auto-loaded scientific packages. Mirage mirrors the workspace mounts
into Pyodide’s in-memory filesystem, so open() and os.listdir work on
mounted paths.
Monty
Monty runs each execution in a crash-isolated worker with microsecond startup and no host filesystem, environment, or network access.pathlib
I/O routes through the workspace mounts, and the run’s env is readable
either way Python spells it (os.getenv or os.environ):
@pydantic/monty package:
python3 exit with code 127 and an
install hint.
Differences from CPython
- Command-line arguments are the
argvglobal;sys.argvdoes not exist. - The builtin
open()is not bridged yet in the JS binding; usepathlib(Path(...).read_text(),.write_text(),.iterdir()). - No
sys.stdinand no third-party imports. os.environreflects the session env only.
Selecting in YAML
Server workspace config files take a top-levelruntimes list:
captures, config,
script); the knobs that differ per runtime live in config. The
home config key locates the runtime’s interpreter or distribution,
in the spirit of JAVA_HOME. For
pyodide that is where the distribution loads from: it defaults to
the installed package in Node and the pinned CDN in the browser; point
it at self-hosted assets to pin or air-gap the runtime (falls back to
the MIRAGE_PYODIDE_HOME environment variable). monty embeds its
interpreter and has no config keys yet. Python-only names (wasi,
local) fail loud with a cross-language hint. In application code the
entries are the runtimes workspace option, instances carrying their
own options:
Resource limits
python3 is a command like any other: the same command_limits
blocks that guard cat or grep guard it, enforced at the same
central point. A run that exceeds timeout_seconds answers with exit
124 and python3: timed out after Ns on stderr, exactly like any
other command; max_bytes and max_lines cap its output the same
way. There is no python3-specific limit surface.
The deadline stops the interpreter, not just the answer. Monty’s
worker process is SIGKILLed when its run trips the deadline (or a
background job is killed), so a runaway loop never keeps burning.
Pyodide shares the event loop with the workspace, so the runtime arms
its interrupt buffer from a watchdog thread: the guest gets a
KeyboardInterrupt at the deadline and the run answers 124 even for
a busy while True loop. The watchdog needs SharedArrayBuffer
(always present in Node; in a browser only on cross-origin isolated
pages) — without it, a busy pyodide loop blocks the event loop until
it finishes, so prefer monty for untrusted code there.