WEFT_OS/docs/architecture/runtime-wasmtime-integration.md
Marco Allegretti ab38b96a7f docs: document Wasmtime integration plan for weft-runtime
Specifies the concrete steps needed to replace the current READY stub
with real Wasm module execution:
- Optional cargo feature gate (wasmtime-runtime) to keep default builds
  fast; production service unit uses the feature-enabled binary.
- Engine + Module setup from wasm file path.
- WasiCtxBuilder with inherited stdout/stderr for READY signal passthrough.
- READY signal timing: Option A (print before _start) vs Option B
  (explicit weft_ready() export); Option A is the initial implementation.
- Entry point: _start (standard wasm32-wasi target output).
- Error handling: module load failures, trap handling, missing _start.
- Explicit non-scope: host imports beyond WASI, memory caps, component
  model, Wasm threads, fuel metering.
- Prerequisite: confirmed wasm32-wasi app SDK before integration.
2026-03-11 09:42:09 +01:00

3.6 KiB

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:

[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

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

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

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.