hoophq/plugins: one worked example per language, each with the fixtures the conformance tool replays and a config that runs it. examples/resp (Redis, Rust), examples/memcache (memcached, Go) and examples/sqlframe (a binary framing over SQL, C++) cover every capability between them. The SDK source and the x-acmewire reference live in the Sidecar repository under sidecar/codec/wasm.
The contract in one paragraph
decode(dir, bytes) returns statements and a consumed count. An incomplete trailing message is not an error: return the statements before it and stop consumed at its first byte. The Sidecar keeps the rest and passes it again, prefixed to the next read. Malformed bytes are an error, and the Sidecar drops the connection. The Sidecar fills the protocol field itself; the module sets operation from the Sidecar’s vocabulary and puts its native verb under metadata["<protocol>.verb"].
Table and relation names are lowercased by the module. The policy compares them as they arrive.
Rust
Add the crate from crates.io and the wasm32 target:Cargo.toml
Codec, describe the module in a Manifest, and let the macro emit the exports for the capabilities you list:
src/lib.rs
frame returns Ok(None) on a partial header or payload, so consumed stops there. The capability list in export_codec! and manifest.capabilities must name the same set; describe traps when they differ, which the conformance tool reports as check 1.
Build and test:
filter, rewrite, flush, take_credential, content, open) have defaults, so add one at a time and list its capability when you do.
Go (TinyGo)
Packagecodec is the module github.com/hoophq/hoop/sidecar/codec/wasm/sdk/tinygo; add it with go get github.com/hoophq/hoop/sidecar/codec/wasm/sdk/tinygo@v0.1.0. The tag carries the module path as a prefix because the module sits below the repository root. A plug-in implements codec.Codec, the capability interfaces it supports, and calls codec.Serve from init:
main.go
-target wasm-unknown is the freestanding target: no WASI, no scheduler, and main never runs, so Serve goes in init. The package also compiles with the standard Go toolchain, so go test exercises your decoder on the host.
C
hoop_codec.h is a single header: import declarations, an export macro, packed-return helpers and an optional arena allocator. It carries a skeleton you fill in. Fetch it from the hoophq/plugins repository, where each SDK release places it beside sdk/VERSION: curl -fsSLO https://raw.githubusercontent.com/hoophq/plugins/main/sdk/c/hoop_codec.h.
HOOP_EXPORT uses export_name, so you need no --export flags. A module calls only the imports it needs; the linker drops the rest.
Other languages
The ABI is a C ABI over linear memory with JSON payloads. Zig and AssemblyScript target it directly. JavaScript and Python work through an engine compiled into the module (Javy, componentize-py); such a module sets"wasi": true in its manifest and "instances": "per_lane", because one instance per connection costs megabytes each. See the ABI reference.
Fixtures
Fixtures are scripts the conformance tool replays: bytes in, expectations out. Keep them beside the module.acmewire.fixtures.json
expect.statements compares only the fields it names. expect.error: true means decode must report an error on that step, and the script ends there.
Prove it
Ship it
One.wasm file runs on amd64 and arm64. Publish it with its sha256 and the fixtures, then hand operators a plugins entry:
Next
ABI Reference
Every export and import, the manifest, the payloads and the failure rules.
Codec Plug-ins
Configure a lane and understand how a plug-in fails.