A plugin framework built on the Wasmi WebAssembly interpreter. The Wasmi Plugin Framework is designed to run wasm plugins across many architectures, including natively, on mobile, and web browsers (running guest wasm32-wasip1 instances within wasm32-unknown-unknown!).
Features
- Uses JSON-RPC over stdio for communication with host
- stdin / stdout for bidirectional JSON-RPC communication
- stderr for logs
- Async compatible host & guest
- Single-threaded compatible
- Interpreter-based (works on IOS, thanks to wasmi)
Limitations
- Plugins are stateless. Each host call made to a plugin is made to a new instance of that plugin. Data persistence must be handle by the host.
- No multi-threading support for guests (wasi-wasip1 limitation)
- No filesystem or network access access for guests
Why not WIT / the Component Model?
The wasm component model is an enhancement for wasm designed to provide clear interopability. While it provides excellent interopability, it has a few limitations which make it suboptimal for my use cases:
- Backwards compatibility: The component model uses WIT interfaces for interopability. With WIT, changing a function's signature is a breaking change and will become incompatible with previous versions of the interface. Thus, any time you want to change the host's interface, for example adding a new optional parameter to a function or type, you must version the entire interface.
- Simplicity: The component model and WIT add a lot of complexity. For simple use cases, where WASI is being implemented anyways, using a protocol like JSON-RPC over stdio is much simpler and easier to setup.
The Wasmi Plugin Framework intentionally targets a subset of the wasm32-wasip1 spec to maximize compatibility across platforms. Because of this, some wasi syscalls are either not implemented or have limited functionality.
The following wasi syscalls are fully supported:
args_getargs_sizes_getenviron_getenviron_sizes_getrandom_getsched_yieldproc_raiseproc_exit
The following wasi syscalls are partially supported:
fd_read- only supports reading from stdin (fd 0)fd_write- only supports writing to stdout (fd 1) and stderr (fd 2)clock_time_get- supportsCLOCKID_REALTIMEandCLOCKID_MONOTONICpoll_oneoff- supports onlyclocksubscriptions
The remaining wasi syscalls are not supported. Because this framework is designed to run in wasm32-unknown-unknown environments (specifically web browsers), filesystem and network access would be mostly impossible anyways. If you need network or filesystem access for your plugin, consider implementing those features as host methods instead.
What this means:
Most of the time unless you're deliberately trying to use an unsupported feature (ie using filesystem access, trying to spawn a thread, making network requests, etc), your plugin will work just fine. If you do try to use an unsupported feature, the plugin will likely panic and return an error to the host.
graph TB
subgraph Host["Host Process (wasmi-hdk)"]
App["Your Application"]
Executor[WASM Executor]
HostMethods["Host Methods"]
end
subgraph Plugin["Guest Process (wasmi-pdk)"]
PluginMethods["Plugin Methods"]
Code["Your Plugin Code"]
end
App -->|call| Executor
Executor -->|via JSON-RPC| PluginMethods
PluginMethods --> Code
Code -->|via JSON-RPC| HostMethods
HostMethods --> Executor
- Bidirectional RPC: Host and plugin can call methods on each other via JSON-RPC over stdin/stdout
- Cooperative execution: Fuel-based yielding enables async operation in single-threaded environments
- WASI subset: Provides subset of wasi syscalls (stdio, time, random, yield, poll_oneoff) for plugin execution
See the host tests and test-plugin for example usage.