The host interface
The host interface (host in src/lib/omw/wit/omw.wit) exposes the static,
baked-in capabilities of the runtime to an agent brain: logging, agent identity,
timer helpers, inter-agent messaging, event receipt, and UUID generation. It is
imported by every brain (wasm components and the bundled rhai / js interpreters
alike) and implemented 1:1 by the runtime’s runtime::host module.
This page describes the WIT surface from the guest’s point of view. The actor mechanics that back it are covered in actor.
Events
The unit of everything the guest can observe is an event-envelope, a record
with two fields:
id— the UUID handle of the subscribed source the event came from, andevent— one of the following variant payloads:
| variant | payload | meaning |
|---|---|---|
message(string) | the text | a message from a subscribed agent |
error(string) | the error text | a failed I/O surfaced to the guest |
timer | — | a timestamp / duration / cron timer fired |
reload | — | the brain script changed; exit so the run restarts |
shutdown | — | the process is shutting down; exit terminally |
chat-delta(chat-delta) | a stream chunk | a chat-stream delta |
chat-end | — | an open chat stream finished |
tool-result(tool-result) | { name, arguments, value } | a queued tool invocation returned |
resource-list-updated | list<resource-info> | a subscribed resource list changed, with the new list |
resource-updated | resource-content | a subscribed resource updated in place, with freshly read content |
endpoint-message(endpoint-message) | { session, messages, tools, params? } | an inbound endpoint chat request routed to a subscribed agent |
endpoint-session-end(endpoint-session-end) | { session, error? } | an endpoint session ended: normal or abrupt |
A chat-delta carries content, reasoning, a tool-call, a finish-reason,
and a usage block, all optional, so a chunk may carry text, reasoning, a
partial tool call, token counts, or a terminal reason.
A tool-result event’s payload carries the tool’s name, its arguments, and
its value — the text result queued call-tool returned.
A resource-updated event’s resource-content carries the resource’s uri, an
optional mime-type, and the content itself — actual text for textual
formats, base64 for anything else (match on mime-type to tell which).
An endpoint-message event payload carries the endpoint session’s session id,
the chat history as messages (a chat-message per entry), tools the tools
the client advertised, and params — the opaque JSON string of any extra
generation settings the client submitted. An endpoint-session-end payload
carries the session id and an optional error when the session was
interrupted.
The guest correlates an envelope with a specific source by matching id against
the UUID the opening call returned — for example the UUID from
provider.chat-stream, a host.wait-* call, tooling.call-tool, or
tooling.subscribe-*.
Message flow
subscribe-agent(agent)— subscribe to messages from another agent.unsubscribe-agent(uuid)— cancel a subscription by itssubscribe-agentUUID.subscribe-lifecycle()— subscribe to lifecycle events (reload,shutdown, and reload-failureerror); returns a UUID handle they arrive tagged with. Errors on a second subscribe (one per run).unsubscribe-lifecycle(uuid)— drop the lifecycle subscription; a foreign UUID is a no-op.send-agent(agent, payload)— send text to another agent. The message only lands in the recipient’s inbox if it subscribed to the sender, tagged with that subscription’s UUID.recv()— blocking receive of the next event from this agent’s single inbox, with a host-side timeout (seerecv_timeout_secsin tunables). Returns anevent-envelopeor an error.try-recv()— non-blocking poll of the next event; returnsnonewhen the inbox is empty.
Correlate a lifecycle event by matching id against the UUID
subscribe-lifecycle returned, and kind for reload / shutdown / error
(a reload-failure error means the edit was invalid and the live run kept
going).
The endpoint
The optional endpoint server lets each agent address itself as an OpenAI-compatible model.
The guest side is three calls:
subscribe-endpoint(model)— subscribe this agent to the endpoint under the model namemodel; returns a UUID handle. Inbound requests for that model arrive asendpoint-messageevents tagged with it, and the model is listed on/v1/modelswhile subscribed. Errors if the model is already taken.unsubscribe-endpoint(uuid)— drop the model from/v1/models, stop routing, and abruptly end every in-flight session of that subscription (each fires anendpoint-session-endevent with an error).stream-endpoint(session, delta)— stream onechat-deltato an endpoint session. Non-blocking: it buffers into the session’s local queue and returns immediately. The reply ends when a delta carries afinish-reason; a session ends exactly once (delivering anendpoint-session-endevent).
Timers
omw uses unsigned 64-bit ticks (milliseconds since the Unix epoch) as its
timestamp type. The guest gets a set of pure helpers plus three scheduling
calls:
time-now()— current time in ticks.time-format(ts, format)— format a tick with a strftime-style format.wait-until(ts)— wait until a future timestamp fires; errors iftsis not in the future.wait-for(ms)— wait formsmilliseconds.wait-cron(spec)— wait until the next fire of a cron spec.cancel-timer(uuid)— cancel a pending wait by the UUID itswait-*call returned.sleep-for(ms)— blocking wait formsmilliseconds; returns once the delay elapses. Unlikewait-for, notimerevent is scheduled.sleep-until(ts)— blocking wait until a future timestamp fires; errors iftsis not in the future. Unlikewait-until, notimerevent is scheduled.sleep-cron(spec)— blocking wait until the next fire of a cron spec. Unlikewait-cron, notimerevent is scheduled.
Each wait-* call returns a UUID immediately; when the deadline passes, a
timer event tagged with that UUID is delivered to the inbox. The brain reads
it back with recv/try-recv and matches id to know which timer fired. A
pending wait can be cancelled at any time with cancel-timer(uuid). The
sleep-* variants are the blocking mirror — they hold the brain until the wait
finishes and return directly (no timer event, no cancel handle, and an error
is reported in-band).
Identity
whoami()— the calling agent’s configured name. It lets a brain shared by several agents tell which one it is running as, for example to subscribe to its own name or pick a role.
Logging
log(level, message)— write a structured log line.levelis one oftrace,debug,info,warn, orerror, and unknown levels default toinfo. The calling agent’s name is attached as a structured field.
UUIDs
new-uuid()— a fresh v4 UUID string. Every handle used across the host (subscriptions, streams, timers) is one of these. The guest can also use it for its own purposes.
Base64
base64-encode(bytes)— encode raw bytes as standard padded base64 (RFC 4648 §4), matching the encoding of MCPblobresource contents.base64-decode(data)— decode standard padded base64 back to raw bytes. Errors on invalid input.
Memory
Per-agent string store that survives hot reloads:
memory-get(key)— read a value; none when absent.memory-set(key, value)— store a value, overwriting.memory-remove(key)— delete; true when a value was present.
Scoped to the calling agent, so agents cannot race each other. Treat entries like variables: subscription handles, state-machine state, small checkpoints. Not a database — keep values small.