WASM plugin (L3)
The Launcher (Launcher)runs L3 plugins as WASM modules inside its Rust layer (wasmtime engine) in a Sandbox (Sandbox). They suit agents, protocol parsers, and other complex logic. Unlike L2 (frontend script), L3 runs in an independent runtime and does not depend on a browser environment.1. How it works
- When the Launcher starts, the Rust gateway scans
plugins/{plugin id}/plugin.wasm(the Manifestlayersmust includel3) - The wasmtime engine loads the module, injects host functions (the
qomicexmodule), and calls the functions exported by the plugin - The gateway port is written to
plugins/.gateway_port; the backendPluginGatewayClientreads it and proxies calls - The frontend calls through the backend with
__PLUGIN_API__.callWasm(...)
2. Plugin structure
plugin.wasm (at plugins/{plugin id}/plugin.wasm), so you do not need to declare a path in the Manifest. entry.backend is a reserved field (currently unused); do not rely on it.
3. Plugin exports (WASM → Launcher)
4. Host API (Launcher → WASM)
Plugins reach Launcher capabilities by importing functions from theqomicex module:
- Strings are passed as
(pointer, length); the plugin manages its own wasm linear memory http_fetch/instance_listare reserved today (they return -1). Use the frontendcallBackend/proxyFetchfor network and Instance access
5. Examples in multiple languages
A WASM plugin is a bare core module (not WASI, not a component). Feasibility by language:Common conventions (all languages)
- Export
on_load/on_unload(() -> ()) for the gateway to call; custom exports are() -> ()or() -> i32 - Import the host functions of the
qomicexmodule (log/db_set/db_get/get_plugin_id) - Strings are passed as
(pointer, length); the pointer is a wasm linear memory offset (i32), not a host pointer - Linear memory must be exported (conventionally named
memory); the gateway reads it withcaller.get_export("memory") - Function signatures must match the registered host signatures exactly, or instantiation fails
1. Rust (verified)
Cargo.toml:2. C / C++ (feasible)
plugin.c:- You must use
wasm32-unknown-unknown(notwasm32-wasi, which pulls in WASI imports) - With
-nostdlibthere is nomemcpy/memset; implement them yourself if you need them -Wl,--export-memoryexports the linear memory asmemory
3. AssemblyScript (feasible)
entry.ts:memory by default, which matches the gateway convention. --exportRuntime exports memory helpers such as __new/__pin; if size matters, use --runtime stub.
4. Zig (feasible)
plugin.zig:5. Go (limited, WASI mode)
Go has only two wasm targets,js / wasip1, and no bare core module target. A wasip1 build carries the Go runtime and imports WASI, so the gateway must register WASI before it can run (the current gateway does not, so it does not work). For reference only:
6. C# / Python (not available)
- C# (.NET): NativeAOT does not support the wasm target; the Mono browser-wasm / wasi-wasm output is the entire .NET runtime (several MB, with WASI symbols) rather than a bare core module, so it cannot meet the gateway conventions.
- Python: there is no wasm compilation target; approaches such as Pyodide “port the CPython interpreter to wasm” instead of compiling your code into a module.
6. Calling from a plugin or the frontend
wasm:execute
7. Backend proxy endpoints
The backend proxies the gateway capabilities as the following HTTP endpoints (the frontend API wraps them for you):8. Notes
- A plugin package must contain
plugin.wasmand its Manifestlayersmust includel3before the gateway loads it plugin.wasmis a core wasm module (core module), not a WASI/component module- The data directory matches frontend plugins (
{data dir}/plugins/{id}/) and is determined byQOMICEX_HOMEor the system data directory - Gateway logs go to the Launcher console (prefixed
[plugin]/[gateway]) - Today
db_set/db_getare a key-value store inside the gateway process and are cleared on restart;http_fetch/instance_listare reserved