Note
This project was an experiment in LLM-assisted development. Much of the code in this repo was written with Claude.
A distributed runtime that networks WASM modules via transparent HTTP interception. Modules make ordinary HTTP calls to each other β Wruntime intercepts, routes, and delivers them automatically.
β http://example.echo/echo.EchoService/Echo
ββββββββββββββ ββββββββββββββ
β caller β β β β β β β β β β β β β β ββΊ β echo β
β (WASM) β (appears direct) β (WASM) β
ββββββββ¬ββββββ ββββββββ²ββββββ
β β
β β‘ intercepted β£ routed β
β β
β βββββββββββββββββββ β
ββββββββββΊβ wr-proxy βββββββββββββββββββ
β β
β routes β
β load-balances β
β streams β
ββββββββββ¬βββββββββ
β β’ syncs
ββββββββΌβββββββ
β wr-manager β
βββββββββββββββ
Modules address each other using http://{namespace}.{module}/{proto_package}.{ProtoServiceName}/{ProtoMethodName} URLs. The runtime handles service discovery, version routing, circuit-breaker-aware load balancing across instances, and OpenTelemetry tracing β all transparent to the module code. Request and response bodies are streamed through the proxy with zero buffering.
Two WASM modules β echo returns whatever it receives, caller sends a message to echo and prints the result.
// schemas/echo.proto
syntax = "proto3";
package echo;
service EchoService {
rpc Echo (EchoRequest) returns (EchoResponse);
}
message EchoRequest { string message = 1; }
message EchoResponse { string message = 1; }Compile it:
protoc --descriptor_set_out=schemas/echo.binpb --include_imports echo.protobuild.rs:
fn main() {
prost_build::Config::new()
.service_generator(Box::new(wr_build::WrServiceGenerator))
.compile_protos(&["schemas/echo.proto"], &["schemas"])
.unwrap();
}src/lib.rs:
mod proto { include!(concat!(env!("OUT_DIR"), "/echo.rs")); }
// The complete local world is shown in docs/agents/guest-module-author/module_template.md.
#[allow(dead_code, unused_imports)]
mod bindings {
wit_bindgen::generate!({ path: "wit", world: "echo", generate_all });
}
use wr_sdk::prelude::*;
struct Component;
wr_sdk::export!(Component with_types_in wr_sdk::bindings);
impl ServiceGuest for Component {
fn handle(request: IncomingRequest, response_out: ResponseOutparam) {
proto::echo_service_handle(&Component, request, response_out);
}
}
impl proto::EchoService for Component {
fn echo(&self, req: proto::EchoRequest) -> Result<proto::EchoResponse, ServiceError> {
Ok(proto::EchoResponse { message: req.message })
}
}WrServiceGenerator generates a trait (EchoService) and a _handle function (echo_service_handle) from the proto definition β you implement the trait and delegate handle to the generated function.
build.rs:
fn main() {
prost_build::Config::new()
.service_generator(Box::new(wr_build::WrClientGenerator))
.compile_protos(&["schemas/echo.proto"], &["schemas"])
.unwrap();
}src/lib.rs:
mod proto { include!(concat!(env!("OUT_DIR"), "/echo.rs")); }
// The complete local world is shown in docs/agents/guest-module-author/module_template.md.
#[allow(dead_code, unused_imports)]
mod bindings {
wit_bindgen::generate!({ path: "wit", world: "caller", generate_all });
}
use prost::Message;
use proto::EchoServiceClient;
use wr_sdk::prelude::*;
struct Component;
wr_sdk::export!(Component with_types_in wr_sdk::bindings);
impl ServiceGuest for Component {
fn handle(request: IncomingRequest, response_out: ResponseOutparam) {
let client = EchoServiceClient::new("example.echo");
match client.echo(proto::EchoRequest { message: "hello".into() }) {
Ok(resp) => send_response(response_out, 200, resp.encode_to_vec()),
Err(e) => wr_sdk::log!("error: {e}"),
}
}
}WrClientGenerator generates a typed EchoServiceClient struct with one method per RPC. The client calls http://example.echo/echo.EchoService/Echo under the hood via wr_sdk::http::http_request.
engine.toml:
listen_address = "127.0.0.1:9100"
[node]
proxy_address = "http://127.0.0.1:9001"
control_address = "http://127.0.0.1:9002"
peer_port = 9443
[node.tls]
cert_path = "certs/127.0.0.1.crt"
key_path = "certs/127.0.0.1.key"
ca_cert_path = "certs/ca.crt"
[[module]]
name = "echo"
namespace = "example"
version = "1.0.0"
wasm_path = "target/wasm32-wasip2/debug/echo.wasm"
schema_path = "schemas/echo.binpb"
[[module]]
name = "caller"
namespace = "example"
version = "1.0.0"
wasm_path = "target/wasm32-wasip2/debug/caller.wasm"
schema_path = "schemas/echo.binpb"# Build the WASM components
cargo build --target wasm32-wasip2 -p echo
cargo build --target wasm32-wasip2 -p caller
# Start the services (in separate terminals, or background them)
just manager
just proxy
just engine ./engine.toml
# Invoke the caller through the proxy
wr-cli --manager http://127.0.0.1:9000 invoke --destination http://example.caller/runWASM modules can access host-provided capabilities through WIT interfaces:
| Binding | WIT | Preferred SDK surface | Description |
|---|---|---|---|
| Database | wit/db.wit |
wr_sdk::db builders and owned rows |
Parameterized SQL queries, transactions, and streaming against a shared Postgres pool |
| Blobstore | wit/blobstore.wit |
wr_sdk::blobstore::bucket scoped handle |
S3-compatible object storage constrained to a host-configured bucket allowlist |
| Tracing | wit/tracing.wit |
span!, set_attrs!, and event! |
Typed OpenTelemetry spans and batched attributes from within modules |
| LLM | wit/llm.wit |
wr_sdk::llm::CompletionBuilder |
Validated Anthropic Claude completions, streaming, and tool use |
Prefer these facades for application code. wr_sdk::bindings::wruntime::* exposes the raw WIT bindings as an intentional escape hatch for unsupported operations and protocol/negative tests.
See docs/host-bindings.md for configuration and usage examples.
Bundle once, deploy anywhere β the CLI packages cross-compiled binaries, WASM modules, and configs into a single tarball that works with both systemd and Docker. Shared settings (target, db_url, format, etc.) can live in a wr-deploy.toml so commands stay short.
# Bundle a node (proxy + engine) β target defaults to x86_64-unknown-linux-gnu
wr-cli node bundle --engine-config engine.toml
# Deploy to a remote host via SSH (format defaults to systemd)
wr-cli node deploy wr-node-bundle.tar.gz deploy@10.0.1.50 \
--db-url "postgres://postgres@10.0.1.1:5432/wruntime" \
--manager http://10.0.1.1:9000
# Or with a wr-deploy.toml providing db_url, just the positional args:
wr-cli node deploy wr-node-bundle.tar.gz deploy@10.0.1.50 \
--manager http://10.0.1.1:9000Manager deployment follows the same pattern (wr managers bundle / wr managers deploy). See docs/deployment.md for the deploy config reference, multi-node cluster setup, bundle structure, and template variables.
| Tool | Purpose |
|---|---|
| Rust + Cargo (stable) | Build all binaries |
just |
Run project recipes (see Justfile) |
protoc |
Compile .proto schemas to FileDescriptorSet binaries |
wasm32-wasip2 target |
rustup target add wasm32-wasip2 β build WASM component modules |
wasm-tools |
Strip/inspect WASM components (install: cargo install --locked wasm-tools) |
just build # debug build
just build-release # release build
just dev-up # start Postgres/RustFS for integration tests and examples
just multi-node # run two local proxy nodes and three engines
just test # all tests with test DB/S3 env vars set
just test-wasm # WASM host binding tests
just validate-ecommerce # ecommerce inline run with zero-warning enforcementwruntime/
βββ proto/
β βββ wruntime.proto # single source of truth for all gRPC messages
βββ wr-common/ # generated proto types (tonic + prost); shared NodeConfig
βββ wr-manager/ # central registry gRPC server
βββ wr-proxy/ # streaming HTTP routing proxy
βββ wr-engine/ # WASM runtime (wasmtime) + inbound HTTP server
βββ wr-sdk/ # WASM module SDK: http, io, db, tracing, llm, export macros
βββ wr-build/ # build.rs helper: service/client generators from proto
βββ wr-cli/ # CLI: invoke modules, list engines/services, query metrics (requires --manager or WR_MANAGER)
βββ wr-tests/ # integration tests
βββ wit/ # WIT interfaces (db, blobstore, tracing, llm)
βββ examples/
β βββ config/ # example single-node configs
β βββ ecommerce/ # example: inventory (handler) + client (runner)
β βββ codegen/ # example: LLM agent sandbox (code generation)
β βββ stockmarket/ # example: multi-module trading system
β βββ multi-node/ # local and deployment multi-node topology
- Agent guide β choose guest module author or wruntime maintainer mode
- Architecture β detailed system diagram, request flow, internal headers
- Configuration β manager, proxy, and engine TOML configs; health checks; routing rules; multi-node setup
- gRPC API β
ManagerServiceandNodeServiceRPC reference, worker job queue API - Protobuf Schemas β writing, compiling, and validation behavior
- Module SDK β
wr-sdk+wr-buildreference; handler and runner module guides - Host Bindings β database, blobstore, tracing, LLM, and filesystem access
- Deployment β bundle, deploy, multi-node clusters, systemd and Docker
- Testing β running integration tests