Hyrouter plugins run during the initial connection phase (after the client sends the first Connect packet).
There are two plugin backends:
- gRPC (out-of-process)
- WASM (in-process, executed via wazero)
Both use the same request/response model: JSON-encoded ConnectRequest and ConnectResponse.
The JSON types are defined in internal/plugins/types.go.
eventsniclient_cert_fingerprint(optional)protocol_hash(optional)client_type(optional)uuid(optional)username(optional)language(optional)identity_token_present(optional)
strategy– selected strategy (round_robin|random|weighted)candidates– candidate backends for the current route/poolselected_index– index chosen by Hyrouterbackend– the selected backend (host,port,weight,meta)referral_content– current referral content (optional)
deny(bool)deny_reason(string, optional)candidates(list, optional)selected_index(int, optional)backend(object, optional)referral_content(bytes, optional)
Hyrouter wraps the content into a fixed, versioned referral envelope before sending it to the client.
Hyrouter dials a gRPC server and invokes:
- Service:
hyrouter.Plugin - Method:
OnConnect
Both request and response are JSON-encoded.
If your plugin is written in Go, you can reuse Hyrouter’s service descriptor:
internal/plugins.RegisterGRPCServer
See examples/grpc-plugin for a minimal runnable plugin.
task plugin:grpc:runWASM plugins are executed in-process via wazero.
Your module must export:
alloc(len: u32) -> u32on_connect(ptr: u32, len: u32) -> u64
The on_connect return value packs resp_ptr and resp_len:
- high 32 bits:
resp_ptr - low 32 bits:
resp_len
Hyrouter will read resp_len bytes from module memory starting at resp_ptr and interpret them as JSON for ConnectResponse.
The repository contains a Go-based WASM plugin example under examples/wasm-plugin.
Build it using:
task plugin:wasm:buildOr directly:
GOOS=wasip1 GOARCH=wasm go build -tags=examples -buildmode=c-shared -o examples/wasm-plugin/plugin.wasm ./examples/wasm-plugin- The module is expected to run under WASI.
- Hyrouter instantiates WASI (
wasi_snapshot_preview1) and tries to use the reactor entrypoint (_initialize) when present. - The plugin interface is synchronous; keep
on_connectfast.
Use the provided development configs:
dev/config.dev.yaml(no plugins)dev/config.plugins.dev.yaml(gRPC deny + WASM mutate)
Run:
task run:pluginsEnable debug logs:
task run:plugins:debug