# weft-runtime: Wasmtime Integration Plan **Status:** Not yet implemented. weft-runtime currently stubs execution with `println!("READY")`. --- ## Current State `crates/weft-runtime/src/main.rs` resolves the package directory, validates `app.wasm` exists, then prints `READY\n` and exits. No Wasm code is executed. The stub satisfies the supervisor contract (described in `docs/architecture/app-package-format.md`) and allows the full session lifecycle to be tested end-to-end. --- ## Required Changes ### 1. Optional feature gate Add a `wasmtime` cargo feature to `weft-runtime/Cargo.toml` so the default build remains fast: ```toml [features] default = [] wasmtime-runtime = ["dep:wasmtime"] [dependencies] wasmtime = { version = "30", optional = true, features = ["wasi"] } ``` `cfg(feature = "wasmtime-runtime")` guards the real implementation. `cfg(not(feature = "wasmtime-runtime"))` keeps the stub for tests and development. The production service unit (`infra/systemd/weft-appd.service`) would set `WEFT_RUNTIME_BIN` to a binary built with `--features wasmtime-runtime`. ### 2. Engine and module setup ```rust use wasmtime::{Config, Engine, Module, Store}; use wasmtime_wasi::{WasiCtxBuilder, preview1}; let engine = Engine::new(Config::default())?; let module = Module::from_file(&engine, &wasm_path)?; ``` ### 3. WASI context ```rust let wasi = WasiCtxBuilder::new() .inherit_stdout() .inherit_stderr() .build(); let mut store = Store::new(&engine, wasi); ``` stdout is inherited so the Wasm module can write `READY\n` directly via WASI `fd_write` (standard output fd=1). ### 4. READY signal timing The READY signal to weft-appd must be sent after module initialization but before the main event loop blocks. Two options: **Option A (simpler):** weft-runtime prints `READY\n` before calling the Wasm entry point. The Wasm module is responsible for being ready to handle requests when it starts running. **Option B (accurate):** The Wasm module exports a `weft_ready()` function that weft-runtime calls explicitly before starting the main event loop. The ready signal is sent after `weft_ready()` returns. Initial implementation should use Option A. Option B requires a convention on the Wasm module's exported interface. ### 5. Entry point call ```rust let linker = wasmtime_wasi::preview1::add_to_linker_sync(&engine)?; let instance = linker.instantiate(&mut store, &module)?; println!("READY"); let start = instance.get_typed_func::<(), ()>(&mut store, "_start")?; start.call(&mut store, ())?; ``` `_start` is the standard WASI entry point generated by Rust's `wasm32-wasi` target. ### 6. Error handling - `Module::from_file` failure: exit with non-zero code (weft-appd supervisor logs it). - `_start` trap: log the trap message, exit non-zero. - No `_start` export: log and exit non-zero. The package checker (`weft-pack`) should eventually validate this at install time. --- ## What Is Not Designed - **Host function imports**: Wasm modules that import host functions beyond WASI are not supported in the initial implementation. Custom host bindings are deferred. - **Memory limits**: no per-session memory cap is enforced. Deferred to capability model. - **Wasm component model**: not used. Wasm 2.0 module format only. - **Multi-threading (WASM threads)**: not enabled. - **Fuel metering**: not enabled. --- ## Prerequisite Before implementing: confirm the target Wasm module compilation pipeline. The WEFT app SDK must produce a valid `wasm32-wasi` binary that exports `_start`. Until an example app exists that can be tested, the Wasmtime integration cannot be verified end-to-end.