wRPC v0.0.1-draft.1 specification
Defines a transport-agnostic protocol for asynchronous WIT function calls using component model value encoding and multiplexed streams.
What this file does
Defines a transport-agnostic protocol for asynchronous WIT function calls using component model value encoding and multiplexed streams.
When to use it
- Building a cross-language RPC system for WebAssembly components
- Implementing a new wRPC transport like TCP or NATS
- Encoding streaming or future WIT values over the wire
- Understanding how wRPC indexes and frames invocations
Assumes this stack
wRPC v0.0.1-draft.1 specification
wRPC is a transport-agnostic protocol designed for asynchronous transmit of WIT function call invocations over network and other means of communication.
wRPC follows client-server model, where peers (servers) may serve function and method calls invoked by the other peers (clients).
wRPC relies on component model value definition encoding for data encoding on the wire.
Definitions
Transport
wRPC makes use of transports, which are responsible for establishing a connection between two parties and transferring the wRPC wire protocol data between them.
Examples of supported wRPC transports are: TCP, Unix Domain Sockets, QUIC and NATS.io.
Indexing
As WIT interfaces and associated values are asynchronous in nature, callers and callees require ability to asynchronously, bidirectionally transfer (portions of) function parameter and result value data.
For example, caller of wasi:http/outgoing-handler.handle function MUST be able to simultaneously send data over the passed output-stream and well as receive data from the returned input-stream. For this purpose wRPC transports MUST be multiplexed, i.e. they MUST allow for bidirectional concurrent transfer of multiple data streams.
wRPC uses a concept of "indexing" for differentiating and identifying the data streams used as part of processing of a single WIT function invocation.
An "index" is a sequence of unsigned 32-bit integers and represents a reflective structural path to the value, e.g. a record field or a list element.
Consider the following WIT:
package wrpc-example:doc@0.1.0;
interface example {
record rec {
a: stream<u8>,
b: u32,
}
foo: func(v: rec) -> stream<u8>;
}
A path to field a in foo parameter v is defined as a sequence: [0, 0].
The invoker of foo MAY choose to send the whole contents of parameter v, i.e. rec encoded using component model value definition encoding on the "root" (synchronous) parameter data channel, in which case stream<u8> is sent as list<u8>, otherwise, the invoker MAY mark rec.a as pending in the encoding of v and instead, send it asynchnously over data channel identified by [0, 0] (first field in the first parameter).
Similarly, the handler of foo MAY either send the complete resulting stream<u8> contents as encoded list<u8> over the "root" (synchronous) result data channel or asynchronously over data channel identified by 0 (first return value).
The indexing rules are as follows:
- Record fields are indexed in order of their WIT declaration
- Tuple members are indexed in order of their WIT declaration
- Variant members elements are indexed in order of their WIT declaration
- List elements are indexed in the order they appear in the list
- Stream elements are indexed in the order they appear in the stream
Framing
Some transports (like QUIC or NATS.io) have builtin support for multiplexing, whereas others, like TCP or UDS do not.
wRPC suggests a default framing format for non-multiplexed transports, however individual transport implementations are free to use a custom one.
Framed stream specification
wRPC framed stream begins with a version byte 0x00 and is followed by a header encoded using component model value definition encoding:
record header {
instance: string,
name: string,
}
The header MAY be followed by one or more frames encoded using component model value definition encoding:
record frame {
path: list<u32>,
data: list<u8>,
}
It is assumed that streams using this framing protocol can communicate "closing" to peers using some out-of-band mechanism.
Transport specifications
TCP
TCP relies on Framed stream specification to map a single TCP stream to a single wRPC invocation.
The server MUST listen on a TCP socket and client MUST establish a new connection to that socket per each invocation.
The write side of the stream MUST be shutdown as soon as data transfer is done, for example, once the client is done sending encoded parameter buffer and all asynchronous parameters, it MUST shutdown the write side of the stream to signal EOF to the server.
NATS.io
wRPC protocol operates under assumption that globally-unique IDs can be generated by the caller (client). No particular type of identifier is required by wRPC by specification, but in case of NATS transport, the common NATS inbox concept is assumed to be used throughout this specification.
wRPC NATS subjects assume to be rooted at a particular (optional) prefix, this prefix is configured out-of-band.
Invocation lifecycle
On a high level, lifecycle of an arbitrary wRPC invocation looks the following:
- Server subscribes on a subject
Tcorresponding to WIT function or methodFserved by itself - Client sends a message on subject
Tcarrying, optionally truncated, encoded parameters to functionFand reply subjectR_c - The server sends a packet with no payload on subject
R_cwith a reply subjectR_s
Concurrently:
- Client sends invocation parameter data on
R_s.paramsand indexed subjects derived from it - Server begins
Fexecution
- If
Freturns, concurrently, server sends invocation return data onR_c.resultsand indexed subjects derived from it - If
Ftraps or execution is not possible for some other reason, server closes all currently streams by sending a packet with an empty payload
Invocation subject scheme
Invocation subjects are defined as:
[<prefix>.]?wrpc.0.0.1.<wit-instance>.<wit-function>
Where wit-function corresponds to the function name as it appears in the WIT.
For the special case of resource constructors, the resource name is used.
Subject examples:
MBGL42DWFPGIEI63P333NCZW5BAGYJGSGLAIB6U7PPXKSXKJK74QTUZM.wrpc.0.0.1.wasi:http/outgoing-handler.handleNARNEZWUJIOUEDOHI6BDRRFST5W6SHMTQXX5CVOBJC7Z4BQ63S2DKZH6.wrpc.0.0.1.wasi:http/outgoing-handler.handleVD7C7DD6H5XSIL737EEVTHF7G6EYTMIPQLVOE2BLQDC7TEOGTUZECJYF.wrpc.0.0.1.wasi:http/outgoing-handler.handleVD7C7DD6H5XSIL737EEVTHF7G6EYTMIPQLVOE2BLQDC7TEOGTUZECJYF.wrpc.0.0.1.wasi:http/outgoing-handler@0.2.1.handledefault.wrpc.0.0.1.wasi:http/outgoing-handler.handledefault.wrpc.0.0.1.wasi:http/types.fieldsdefault.wrpc.0.0.1.wasi:http/types@0.2.0.fieldscustom.wrpc.0.0.1.wasi:http/types@0.2.0.fields
Messages sent on this subject MUST specify the reply inbox subject.
Indexing subject scheme
Index path is joined using . as the separator
Examples:
_INBOX.WMZAFf1AjlpSF3r5e65nFe.dOssD7ON.params.0.1.0_INBOX.WMZAFf1AjlpSF3r5e65nFe.dOssD7ON.params.0.1.1_INBOX.WMZAFf1AjlpSF3r5e65nFe.dOssD7ON.params.0.1_INBOX.WMZAFf1AjlpSF3r5e65nFe.dOssD7ON.params.1.2.1_INBOX.WMZAFf1AjlpSF3r5e65nFe.dOssD7ON.results.0.0.1_INBOX.WMZAFf1AjlpSF3r5e65nFe.dOssD7ON.results.0.0_INBOX.WMZAFf1AjlpSF3r5e65nFe.dOssD7ON.results.0
Component model value definition encoding extensions
Futures
future<T> values are encoded as variant future<T> { pending, ready(T) }.
In case a future is pending, it's value is transmitted using the parent's index.
For example:
foo: func(v: future<bool>);
If v is pending, encoded bool value is sent on index 0 (corresponding to first parameter)
Streams
stream<T> values are encoded as list<T> .
In case a stream is pending, it is transmitted as a sequence of list<T> chunks using the parent's index.
Each stream MUST finish with an empty list<T>.
Resources
Resources are encoded as opaque byte blobs, list<u8> and their meaning is entirely application specific.
What's inside
7 sections covering definitions, indexing, framing, TCP and NATS transport specs, and value encoding extensions
Change this for your project
- Replace
wrpc.0.0.1in subject scheme with your protocol version - Replace
_INBOXreferences with your NATS inbox naming convention - Replace
MBGL42DWFPGIEI63P333NCZW5BAGYJGSGLAIB6U7PPXKSXKJK74QTUZMexample prefixes with your own
Where it goes
Keep in docs/ or alongside the feature. Agents read it to implement against a defined contract.
Worth borrowing
- Indexing paths as sequences of u32 for structural navigation of nested values
- Separating synchronous root channels from async indexed sub-channels per invocation
Related Documents
GPU Selection Guide for Large Language Models (LLMs)
Guides GPU selection for LLM inference, fine-tuning, and training by mapping model sizes, precision levels, and budgets to VRAM requirements.
Community AI Agent Skills Discovery Sources
Catalogs 50+ platforms, repositories, directories, and communities for discovering and sharing AI agent skills across multiple coding tools.
ReleaseKit - Technical Requirements Document
Specifies a Go library and CLI for release automation with conventional commit parsing, validation checks, and workflow orchestration.
api_llm Specification
Defines a workspace of thin HTTP API clients for major LLM providers with no abstraction layer and explicit developer control.