Metal boots into a persistent native MicroPython REPL #19520
Replies: 1 comment 1 reply
|
The shared-runtime versus isolated-context choice is the part I would scrutinize first. MicroPython's VM, heap, scheduler, and C object lifetimes form one coupled system; adding concurrent host tasks does not automatically make a single interpreter re-entrant. The invariants I would make explicit are:
For the shared mode, a single event-loop owner with queued callbacks is safer than allowing arbitrary Metal threads to call Python. For isolated contexts, give each interpreter its own heap, scheduler state, exception state, and module cache, and define how values cross the boundary. Copy/serialize values first; do not pass raw Python object references between heaps. The signed stdlib archive provides integrity, not isolation. Host bindings are the actual capability surface, so they need an explicit lifetime and permission model. I would test allocation pressure, nested callbacks, cancellation during I/O, GC during a host callback, and an exception crossing the C/Python boundary before optimizing parallel execution. A persistent REPL is a great demonstration, but the scheduler/GC ownership rules should be written down before third-party native bindings depend on them. |
Uh oh!
There was an error while loading. Please reload this page.
First of all: thank you to the MicroPython community and maintainers. MicroPython’s embeddability is what made this experiment practical in the first place.
I’m building Metal, an experimental UEFI/BIOS freestanding async runtime. It is not a conventional OS and it is very far from production-ready, but it now boots directly into a persistent interactive MicroPython REPL.
The important distinction is that MicroPython is native core code in Metal — not a Wasm guest and not a fresh interpreter created for each command. py <script> and py -c schedule more work on the same long-lived runtime; the C command console remains available through console().
Some details of the current experiment:
bidirectional host bindings: Python calls Metal/C, and Metal/C can call Python callables;
a persistent shared context for the normal path, with globals kept alive;
Python tasks and coroutines share Metal’s async scheduling model;
opt-in isolated contexts with their own heap and GC nursery for genuinely parallel bytecode execution;
a signed, trust-checked stdlib.zip with pure-Python modules and Metal-specific bindings;
WAMR remains a separate execution layer for signed Wasm/AOT mods — MicroPython is not being run through WAMR.
I’ve attached a boot/REPL screenshot. The pmcmd.ping("127.0.0.1") example is deliberately mundane, but it shows the Python side talking to a live Metal host/network stack rather than just printing a hello-world.
Repo: https://github.com/pymergetic/metal
I’m posting this primarily to say thanks and to ask for criticism, not applause. If you know the MicroPython port layer, scheduler, GC, heap/lifetime model, or long-lived embedding patterns: what would you question or redesign first? I would especially value feedback on the shared-runtime versus isolated-context model, async host bindings, and invariants this design must not violate.
All reactions