[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-83793":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":16,"subscribersCount":16,"size":16,"stars1d":17,"stars7d":18,"stars30d":18,"stars90d":16,"forks30d":16,"starsTrendScore":19,"compositeScore":20,"rankGlobal":10,"rankLanguage":10,"license":21,"archived":22,"fork":22,"defaultBranch":23,"hasWiki":24,"hasPages":22,"topics":25,"createdAt":10,"pushedAt":10,"updatedAt":26,"readmeContent":27,"aiSummary":10,"trendingCount":16,"starSnapshotCount":16,"syncStatus":28,"lastSyncTime":29,"discoverSource":30},83793,"micropython-wasm","simonw\u002Fmicropython-wasm","simonw","Python library for running a MicroPython sandbox using WebAssembly","",null,"Python",140,12,4,1,0,8,58,67,3.34,"Apache License 2.0",false,"main",true,[],"2026-06-12 02:04:35","# micropython-wasm\n\n[![PyPI](https:\u002F\u002Fimg.shields.io\u002Fpypi\u002Fv\u002Fmicropython-wasm.svg)](https:\u002F\u002Fpypi.org\u002Fproject\u002Fmicropython-wasm\u002F)\n[![Tests](https:\u002F\u002Fgithub.com\u002Fsimonw\u002Fmicropython-wasm\u002Factions\u002Fworkflows\u002Ftest.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fsimonw\u002Fmicropython-wasm\u002Factions\u002Fworkflows\u002Ftest.yml)\n[![Changelog](https:\u002F\u002Fimg.shields.io\u002Fgithub\u002Fv\u002Frelease\u002Fsimonw\u002Fmicropython-wasm?include_prereleases&label=changelog)](https:\u002F\u002Fgithub.com\u002Fsimonw\u002Fmicropython-wasm\u002Freleases)\n[![License](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Flicense-Apache%202.0-blue.svg)](https:\u002F\u002Fgithub.com\u002Fsimonw\u002Fmicropython-wasm\u002Fblob\u002Fmain\u002FLICENSE)\n\nMicroPython packaged as a WASI WebAssembly module and executed from Python\nusing Wasmtime.\n\nSee [Running Python code in a sandbox with MicroPython and WASM](https:\u002F\u002Fsimonwillison.net\u002F2026\u002FJun\u002F6\u002Fmicropython-in-a-sandbox\u002F) for background on this project.\n\nThis project is an experimental Python package for running small snippets of\nMicroPython in a fresh WebAssembly sandbox. It is designed around:\n\n- A custom MicroPython WASI artifact, not the Emscripten browser\u002FNode build.\n- The official `wasmtime` Python package.\n- A fresh Wasmtime instance for one-shot execution, plus an optional persistent\n  session API backed by a background thread.\n- No host filesystem access unless an explicit read-only directory is\n  preopened.\n- No network capability.\n- Configurable WebAssembly memory, fuel, and wall-clock controls.\n\n## Installation\n\nInstall from PyPI:\n\n```bash\npip install micropython-wasm\n```\n\nFor local development, use `uv`:\n\n```bash\ngit clone https:\u002F\u002Fgithub.com\u002Fsimonw\u002Fmicropython-wasm\ncd micropython-wasm\nuv run pytest\n```\n\n## Quick Start\n\nYou can run MicroPython in WASM from the command line:\n\n```bash\nmicropython-wasm -c \"print(1 + 1)\"\nmicropython-wasm script.py\nmicropython-wasm\n```\nYou can also `micropython-wasm` without installing it first using `uvx`:\n```bash\nuvx micropython-wasm --help\n```\n\nThe no-argument form starts a simple REPL with persistent state between\nprompts. Use `--memory` to set the WebAssembly memory limit in bytes and\n`--fuel` to set the Wasmtime fuel budget:\n\n```bash\nmicropython-wasm --memory 33554432 --fuel 20000000 -c \"print('hello')\"\n```\n\nTo use it in Python import code from the `micropython_wasm` package:\n\n```python\nfrom micropython_wasm import run\n\nresult = run(\"print(1 + 1)\")\nprint(result.stdout)\n```\n\nOutput:\n\n```text\n2\n```\n\n`run()` returns a `RunResult`:\n\n```python\nfrom micropython_wasm import run\n\nresult = run(\"print('hello')\")\n\nprint(result.stdout)          # \"hello\\n\"\nprint(result.stderr)          # \"\"\nprint(result.fuel_remaining)  # integer Wasmtime fuel count\n```\n\nEach call creates a new engine, store, WASI config, module instance, and\nMicroPython process. Globals and imports do not persist between calls.\n\nFor stateful usage with real resident MicroPython state, use\n`MicroPythonSession`:\n\n```python\nfrom micropython_wasm import MicroPythonSession\n\nwith MicroPythonSession() as session:\n    print(session.run(\"x = 10\\nprint(x)\").stdout)\n    print(session.run(\"x += 5\\nprint(x)\").stdout)\n    print(session.run(\"print(x * 2)\").stdout)\n```\n\nOutput:\n\n```text\n10\n\n15\n\n30\n```\n\nYou can also use the same object without a context manager, which is convenient\nin an interactive Python REPL:\n\n```python\nfrom micropython_wasm import MicroPythonSession\n\nsession = MicroPythonSession()\nsession.run(\"x = 10\")\nsession.run(\"print(x)\")\nsession.close()\n```\n\n## API\n\n### `run(code, ...)`\n\nRun MicroPython source code using the bundled artifact:\n\n```python\nfrom micropython_wasm import run\n\nresult = run(\n    \"print(sum(range(10)))\",\n    memory_bytes=16 * 1024 * 1024,\n    fuel=20_000_000,\n    wall_timeout_seconds=1.0,\n    host_result_bytes=256 * 1024,\n)\n```\n\nArguments:\n\n- `code`: MicroPython source code passed as `micropython -c \u003Ccode>`.\n- `wasm_path`: optional path to a custom WASI MicroPython artifact. If omitted,\n  `micropython_wasm\u002Fartifacts\u002Fmicropython-wasi.wasm` is used.\n- `memory_bytes`: maximum WebAssembly linear memory for the store.\n- `fuel`: Wasmtime fuel budget. Guest execution traps when it runs out.\n- `wall_timeout_seconds`: wall-clock timeout. Pass `None` to disable epoch\n  interruption.\n- `readonly_dir`: optional host directory to expose inside the guest as\n  `\u002Finput`, with read-only WASI directory and file permissions.\n- `host_functions`: optional mapping of host function names to Python callables.\n  This enables the low-level `host.call(name, payload_json)` bridge.\n- `host_result_bytes`: maximum serialized host callback response size. The\n  default is `256 * 1024`.\n\n### `run_micropython_wasi(code, wasm_path, ...)`\n\nRun code against an explicit `.wasm` artifact:\n\n```python\nfrom micropython_wasm import run_micropython_wasi\n\nresult = run_micropython_wasi(\n    \"print(2 ** 8)\",\n    \"micropython_wasm\u002Fartifacts\u002Fmicropython-wasi.wasm\",\n)\n```\n\nThis is useful when testing a locally rebuilt MicroPython artifact before\ncopying it into the package.\n\n### `MicroPythonSession(...)`\n\nCreate a persistent MicroPython VM running in a background Python thread:\n\n```python\nfrom micropython_wasm import MicroPythonSession\n\nsession = MicroPythonSession()\n\nsession.run(\"x = 10\")\nsession.run(\"x += 5\")\nresult = session.run(\"print(x)\")\nprint(result.stdout)\n\nsession.close()\n```\n\n`MicroPythonSession` starts lazily on the first `run()`. A bootstrap loop\nruns inside MicroPython and repeatedly calls back to the Python host for the\nnext code snippet. Each snippet is executed with `exec(..., globals())` in the\nsame MicroPython VM, so variables, imports, functions, classes, and live objects\nreally stay resident between calls.\n\n`MicroPythonSession` accepts the same resource, filesystem, and host\nfunction arguments as `run()`:\n\n```python\nsession = MicroPythonSession(\n    memory_bytes=16 * 1024 * 1024,\n    fuel=20_000_000,\n    readonly_dir=\"fixtures\",\n    host_functions={\"add\": lambda a, b: a + b},\n    host_result_bytes=256 * 1024,\n)\n```\n\nMethods and properties:\n\n- `session.run(code)`: run code in the resident VM and return a `RunResult`.\n- `session.register_function(func, name=None)`: expose a Python function to\n  MicroPython code, optionally under a custom name.\n- `session.close()`: send a close message to the guest loop and reject further\n  runs.\n- `session.closed`: `True` after `close()`.\n- `session.host_functions`: copy of registered host functions.\n- Context manager support: `with MicroPythonSession() as session: ...`.\n\nFuel is refreshed for each `session.run()` request. If a snippet exhausts fuel\nor otherwise traps the guest, the background VM stops and the session should be\ndiscarded.\n\n### `MicroPythonReplaySession(...)`\n\nCreate a transcript-backed session object with the same basic `run()` and\n`close()` shape as `MicroPythonSession`, but without keeping a MicroPython VM\nrunning in a background thread.\n\n`MicroPythonReplaySession` does not run a background thread and does not keep a\nlive MicroPython VM between calls. Each `run()` call executes a fresh Wasmtime\ninstance and returns when that one command-style execution finishes. To preserve\nvariables, functions, classes, and imports from the caller's point of view, it\nreconstructs state by replaying previous successful snippets before each new\nsnippet.\n\n```python\nfrom micropython_wasm import MicroPythonReplaySession\n\nsession = MicroPythonReplaySession()\n\nsession.run(\"\"\"\nimport math\n\ndef hypotenuse(a, b):\n    return math.sqrt(a * a + b * b)\n\"\"\")\n\nresult = session.run(\"print(hypotenuse(3, 4))\")\nprint(result.stdout)\n\nsession.close()\n```\n\n`MicroPythonReplaySession` accepts the same resource and filesystem arguments as\n`run()`:\n\n```python\nsession = MicroPythonReplaySession(\n    memory_bytes=16 * 1024 * 1024,\n    fuel=20_000_000,\n    wall_timeout_seconds=1.0,\n    readonly_dir=\"fixtures\",\n    host_result_bytes=256 * 1024,\n)\n```\n\nMethods and properties:\n\n- `session.run(code)`: run code and return a `RunResult`.\n- `session.close()`: clear the transcript and reject further runs.\n- `session.closed`: `True` after `close()`.\n- `session.snippets`: tuple of successful snippets currently retained.\n- Context manager support: `with MicroPythonReplaySession() as session: ...`.\n\nOnly successful snippets are retained. If a snippet exits nonzero or traps, it\nis not added to the session transcript:\n\n```python\nfrom micropython_wasm import MicroPythonReplaySession, MicroPythonWasmError\n\nsession = MicroPythonReplaySession()\nsession.run(\"x = 1\")\n\ntry:\n    session.run(\"x = 2\\nraise ValueError('boom')\")\nexcept MicroPythonWasmError:\n    pass\n\nprint(session.run(\"print(x)\").stdout)  # \"1\\n\"\n```\n\nFor `MicroPythonReplaySession`, each `session.run()` call creates a fresh guest\ninstance, replays previous successful snippets, emits an internal marker, then\nruns the new snippet and returns only the output after that marker. This\npreserves ordinary Python state from the caller's point of view, including\nvariables, functions, classes, and imports, but previous snippets are\nre-executed internally on every call.\n\nThat replay behavior matters if previous snippets perform side effects such as\nwriting files, making time-dependent calculations, consuming randomness, or\nmutating external host state. Use `MicroPythonSession` when you want true\nresident in-VM persistence.\n\nFor example, this calls the Python `record()` function again during the second\n`session.run()`, because the first snippet is replayed before `print(count)` is\nexecuted:\n\n```python\nfrom micropython_wasm import MicroPythonReplaySession\n\ncalls = []\n\ndef record(value):\n    calls.append(value)\n    return len(calls)\n\nsession = MicroPythonReplaySession(host_functions={\"record\": record})\nsession.run(\"count = record('once')\")\nsession.run(\"print(count)\")\nsession.close()\n\nprint(calls)  # [\"once\", \"once\"]\n```\n\n### Host Functions\n\n`MicroPythonSession` and `MicroPythonReplaySession` can expose regular Python\nfunctions to MicroPython code. Register a function, then call it by name inside\nthe guest:\n\n```python\nfrom micropython_wasm import MicroPythonSession\n\ndef add(a, b):\n    return a + b\n\nsession = MicroPythonSession()\nsession.register_function(add)\n\nresult = session.run(\"print(add(2, 3))\")\nprint(result.stdout)\n```\n\nOutput:\n\n```text\n5\n```\n\nIf the Python callable already has the name you want to expose, pass it\ndirectly:\n\n```python\ndef shout(value):\n    return value.upper() + \"!\"\n\nsession = MicroPythonSession()\nsession.register_function(shout)\n\nprint(session.run(\"print(shout('hello'))\").stdout)\n```\n\nTo expose a function under a different MicroPython name, pass `name=`:\n\n```python\ndef add(a, b):\n    return a + b\n\nsession = MicroPythonSession()\nsession.register_function(add, name=\"plus\")\n\nprint(session.run(\"print(plus(2, 3))\").stdout)\n```\n\nYou can also provide functions when constructing the session:\n\n```python\ndef format_name(first, last, uppercase=False):\n    result = f\"{first} {last}\"\n    if uppercase:\n        result = result.upper()\n    return result\n\nsession = MicroPythonSession(\n    host_functions={\"format_name\": format_name},\n)\n\nprint(session.run(\"print(format_name('Ada', last='Lovelace', uppercase=True))\").stdout)\n```\n\nArguments and return values cross the WebAssembly boundary as JSON. Supported\nvalues are therefore JSON-compatible values: `None`, booleans, numbers, strings,\nlists, and dictionaries with string keys.\n\nPython-side exceptions are returned to the MicroPython wrapper and raised as\n`RuntimeError`, so guest code can catch them:\n\n```python\ndef fail():\n    raise ValueError(\"bad host value\")\n\nsession = MicroPythonSession(host_functions={\"fail\": fail})\n\nresult = session.run(\"\"\"\ntry:\n    fail()\nexcept RuntimeError as ex:\n    print(str(ex))\n\"\"\")\n\nprint(result.stdout)\n```\n\nOutput:\n\n```text\nValueError: bad host value\n```\n\nUnder the hood the bundled MicroPython artifact includes a tiny built-in module\nnamed `host`. That module imports `micropython_wasm.host_call` from Wasmtime and\nexposes a low-level `host.call(name, payload_json)` function. The session API\nbuilds friendly MicroPython wrappers on top of that low-level bridge.\n\nOne-shot `run()` and `run_micropython_wasi()` also accept a `host_functions`\nmapping, but they do not automatically define friendly wrappers. They expose the\nlow-level `host` module:\n\n```python\nfrom micropython_wasm import run\n\ndef add(a, b):\n    return a + b\n\nresult = run(\n    \"\"\"\nimport host\nprint(host.call(\"add\", '{\"args\": [2, 3], \"kwargs\": {}}'))\n\"\"\",\n    host_functions={\"add\": add},\n)\n\nprint(result.stdout)\n```\n\n### `default_wasm_path()`\n\nReturn the package's expected artifact path:\n\n```python\nfrom micropython_wasm import default_wasm_path\n\nprint(default_wasm_path())\n```\n\n### Exceptions\n\nThe package raises:\n\n- `MicroPythonWasmArtifactNotFound` if the configured artifact does not exist.\n- `MicroPythonSessionClosed` if `session.run()` is called after\n  `session.close()`.\n- `MicroPythonWasmError` for guest traps, nonzero guest exits, invalid artifacts,\n  missing Wasmtime support, or invalid preopened directories.\n- `ValueError` for invalid host-side resource limits.\n\nFor example:\n\n```python\nfrom micropython_wasm import MicroPythonWasmError, run\n\ntry:\n    run('raise ValueError(\"boom\")')\nexcept MicroPythonWasmError as ex:\n    print(ex)\n```\n\n## Filesystem Access\n\nBy default, the guest gets no preopened host directories:\n\n```python\nfrom micropython_wasm import run\n\nrun(\"print('no files by default')\")\n```\n\nTo expose input files, place them in a directory and pass `readonly_dir`:\n\n```python\nfrom pathlib import Path\nfrom micropython_wasm import run\n\nfixtures = Path(\"fixtures\")\nfixtures.mkdir(exist_ok=True)\n(fixtures \u002F \"example.txt\").write_text(\"hello from the host\\n\")\n\nresult = run(\n    \"print(open('\u002Finput\u002Fexample.txt').read())\",\n    readonly_dir=fixtures,\n)\n\nprint(result.stdout)\n```\n\nThe directory is mounted at `\u002Finput` in the WASI guest. The package asks\nWasmtime for read-only directory and file permissions. Attempts to write inside\n`\u002Finput` should fail.\n\nDo not preopen your project root, home directory, `\u002F`, or a shared temporary\ndirectory when running untrusted code.\n\n## Resource Controls\n\nThe host configures these Wasmtime controls for each execution:\n\n- `Store.set_limits(memory_size=...)` limits WebAssembly linear memory.\n- `Store.set_fuel(...)` limits CPU-like instruction progress.\n- Epoch interruption is enabled when `wall_timeout_seconds` is not `None`.\n- `Config.max_wasm_stack` is set to `512 * 1024`.\n\nExample:\n\n```python\nfrom micropython_wasm import MicroPythonWasmError, run\n\ntry:\n    run(\n        \"while True:\\n    pass\",\n        fuel=50_000,\n        wall_timeout_seconds=None,\n    )\nexcept MicroPythonWasmError as ex:\n    print(\"stopped:\", ex)\n```\n\n`memory_bytes` limits guest linear memory, not total host process RSS. Wasmtime\nruntime memory, compiled code, Python process memory, and host callbacks are\noutside that limit. For high-risk multi-tenant workloads, run each execution in\na separate worker process with OS-level CPU, memory, and wall-clock limits too.\n\n## Network Access\n\nThis package does not expose network imports or host socket functions. The\ncurrent MicroPython WASI artifact also has socket and SSL support disabled in\nthe WASI variant configuration.\n\nIf network access is ever added, prefer a narrow host-mediated API such as\n`http_get(url)` with explicit allowlists, timeouts, redirect limits, and maximum\nresponse sizes. Do not expose raw sockets to untrusted code.\n\n## Supported Python Behavior\n\nMicroPython is not CPython. It implements a substantial subset of Python, but\nthere are differences in syntax support, standard-library coverage, object\nbehavior, and platform details.\n\nThe test suite verifies useful behavior including:\n\n- Arithmetic and big integers.\n- Strings and bytes.\n- Lists, tuples, dictionaries, and sets.\n- List, dict, set, and generator comprehensions.\n- Functions, default arguments, keyword-only arguments, lambdas, closures, and\n  recursion.\n- Classes, inheritance, `property`, `isinstance`.\n- `try`\u002F`except`\u002F`finally` and context managers.\n- `math`, `json`, `re`, `binascii`, `sys`, and `os.listdir('\u002Finput')`.\n- Fresh execution state between calls.\n- Transcript-backed session state across `MicroPythonReplaySession.run()` calls.\n- True resident VM state across `MicroPythonSession.run()` calls.\n- Host function callbacks through session `register_function()` methods.\n- Read-only file preopens.\n- Fuel exhaustion.\n\nKnown observations from this artifact:\n\n- `sys.platform` reports `linux`.\n- `sys.argv` is `['-c']` inside the guest.\n- `hashlib.sha256` is not available in the bundled artifact.\n- `zlib` is not available in the bundled artifact.\n\n### Listing Available Modules\n\nTo see the MicroPython import path and the modules available to the bundled\nartifact, run:\n\n```python\nfrom micropython_wasm import run\n\nresult = run(\n    \"\"\"\nimport sys\n\nprint(\"sys.path:\")\nfor path in sys.path:\n    print(\" \", path)\n\nprint()\nprint(\"modules:\")\nhelp(\"modules\")\n\"\"\"\n)\n\nprint(result.stdout)\n```\n\n`help(\"modules\")` is the most useful MicroPython-native listing because it\nincludes built-in and frozen modules as well as modules available on the\nfilesystem. A plain `os.listdir()` scan of `sys.path` will miss frozen modules\nin this artifact.\n\n## Rebuilding the WASI Artifact\n\nThe build helper is:\n\n```text\nscripts\u002Fbuild_micropython_wasi.py\n```\n\nIt:\n\n1. Clones MicroPython into `\u002Ftmp\u002Fmicropython-wasm-build\u002Fmicropython`.\n2. Checks out the requested ref, including GitHub PR refs such as\n   `pull\u002F13676\u002Fhead`.\n3. Builds `mpy-cross`.\n4. Runs `make submodules` for `ports\u002Funix`.\n5. Builds `ports\u002Funix VARIANT=wasi`.\n6. Includes the bundled `host` user C module by default.\n7. Finds the best wasm artifact.\n8. Copies it to `micropython_wasm\u002Fartifacts\u002Fmicropython-wasi.wasm`.\n\n### macOS ARM64 Setup\n\nInstall Binaryen:\n\n```bash\nbrew install binaryen\n```\n\nDownload `wasi-sdk` 25.0 to `\u002Ftmp`:\n\n```bash\ncurl -L -o \u002Ftmp\u002Fwasi-sdk-25.0-arm64-macos.tar.gz \\\n  https:\u002F\u002Fgithub.com\u002FWebAssembly\u002Fwasi-sdk\u002Freleases\u002Fdownload\u002Fwasi-sdk-25\u002Fwasi-sdk-25.0-arm64-macos.tar.gz\ntar -xzf \u002Ftmp\u002Fwasi-sdk-25.0-arm64-macos.tar.gz -C \u002Ftmp\n```\n\nBuild the artifact:\n\n```bash\nuv run python scripts\u002Fbuild_micropython_wasi.py \\\n  --ref pull\u002F13676\u002Fhead \\\n  --wasi-sdk \u002Ftmp\u002Fwasi-sdk-25.0-arm64-macos\n```\n\nUse `--clean` to discard the existing `\u002Ftmp` checkout:\n\n```bash\nuv run python scripts\u002Fbuild_micropython_wasi.py \\\n  --clean \\\n  --ref pull\u002F13676\u002Fhead \\\n  --wasi-sdk \u002Ftmp\u002Fwasi-sdk-25.0-arm64-macos\n```\n\nUse `--skip-build` to recopy an already-built artifact from the checkout:\n\n```bash\nuv run python scripts\u002Fbuild_micropython_wasi.py \\\n  --skip-build \\\n  --ref pull\u002F13676\u002Fhead \\\n  --wasi-sdk \u002Ftmp\u002Fwasi-sdk-25.0-arm64-macos\n```\n\n### Useful Build Options\n\n- `--repo-url`: alternate MicroPython repository.\n- `--ref`: git ref to build. PR refs like `pull\u002F\u003Cnumber>\u002Fhead` are supported.\n- `--work-dir`: alternate build checkout directory.\n- `--output`: alternate destination for the copied artifact.\n- `--variant`: alternate Unix variant, defaults to `wasi`.\n- `--wasi-sdk`: path to a `wasi-sdk` directory.\n- `--user-c-modules`: path to a MicroPython `USER_C_MODULES` directory.\n- `--jobs`: parallel build jobs.\n- `--extra-make-arg`: additional argument forwarded to the Unix make command.\n- `--clean`: remove the checkout before cloning.\n- `--skip-build`: find and copy an existing artifact without rebuilding.\n\nOn macOS, the script passes\n`CFLAGS_EXTRA=-Wno-error=gnu-folding-constant` when building `mpy-cross`, because\nthe experimental branch currently trips this Apple Clang warning while using\n`-Werror`.\n\n### Artifact Selection\n\nThe script prefers artifacts in this order:\n\n1. `build-wasi\u002Fmicropython.spilled.exnref`\n2. `build-wasi\u002Fmicropython.exnref`\n3. `build-wasi\u002Fmicropython.wasm`\n4. `build-wasi\u002Fmicropython`\n\nThe current local build produced:\n\n```text\n\u002Ftmp\u002Fmicropython-wasm-build\u002Fmicropython\u002Fports\u002Funix\u002Fbuild-wasi\u002Fmicropython\n\u002Ftmp\u002Fmicropython-wasm-build\u002Fmicropython\u002Fports\u002Funix\u002Fbuild-wasi\u002Fmicropython.exnref\nmicropython_wasm\u002Fartifacts\u002Fmicropython-wasi.wasm\n```\n\nThe copied package artifact is the `micropython.exnref` output.\n\n## Testing\n\nRun the full test suite:\n\n```bash\nuv run pytest\n```\n\nThe suite includes package tests and runtime integration tests against the\nbundled wasm artifact. If the artifact is missing, runtime integration tests are\nskipped, but package\u002Fbuild-script tests still run.\n\nTo test a custom artifact manually:\n\n```bash\nuv run python - \u003C\u003C'PY'\nfrom micropython_wasm import run_micropython_wasi\n\nresult = run_micropython_wasi(\n    \"print(1 + 1)\",\n    \"\u002Fpath\u002Fto\u002Fmicropython-wasi.wasm\",\n)\nprint(result.stdout)\nPY\n```\n\n## Security Notes\n\nThis package is a Wasmtime embedding for a MicroPython WASI command module. It\nis a useful sandboxing layer, but it is not a complete security boundary by\nitself for high-risk production use.\n\nReasonable defaults in this package:\n\n- Fresh instance for each run.\n- No inherited host environment.\n- No preopened host directories by default.\n- Optional read-only preopened directory only.\n- No network host functions.\n- Fuel and memory limits.\n- Optional wall-clock timeout.\n\nAdditional protections to consider:\n\n- Run executions in separate worker processes.\n- Apply OS-level memory and CPU limits.\n- Put workers in containers or another isolation boundary.\n- Bound stdout\u002Fstderr capture size if running untrusted code at scale.\n- Avoid host callbacks that expose ambient authority.\n- Keep Wasmtime and the MicroPython artifact pinned and regularly tested.\n\n## Implementation Status and Caveats\n\nThe repository currently includes a working bundled artifact at:\n\n```text\nmicropython_wasm\u002Fartifacts\u002Fmicropython-wasi.wasm\n```\n\nThat artifact was built from MicroPython PR `#13676`, using the PR ref\n`pull\u002F13676\u002Fhead`. MicroPython's WASI Unix variant is still experimental\nupstream, so this package should also be treated as experimental.\n\nThe test suite verifies the bundled artifact against arithmetic, strings,\nbytes, collections, comprehensions, functions, closures, recursion, classes,\nexceptions, context managers, a small standard-library subset, fresh instance\nisolation, read-only file access, and fuel interruption. It also verifies both\nstateful session APIs: the transcript-backed `MicroPythonReplaySession` and the\npersistent background-thread `MicroPythonSession`.\n\nOne important build caveat: the PR's full post-link Binaryen pipeline currently\nfails here at `wasm-opt --spill-pointers` with Binaryen 130. The artifact in this\nrepository uses the successful `wasm-opt --translate-to-exnref` postprocess\ninstead. Simple and moderately broad Python execution works under Wasmtime, but\nthis should be stress-tested before relying on it for hostile or long-running\ncode.\n\n## License\n\nApache-2.0\n",2,"2026-06-11 04:11:29","CREATED_QUERY"]