myelin
Define async service APIs as traits, communicate over channels.
Myelin lets you define service interfaces as Rust traits and generates all the channel plumbing — request/response enums, typed clients, server dispatch loops, and transport adapters — via a proc macro.
Features
- Trait-driven — define your API once, get client and server code generated
- Transport-agnostic — local channels (tokio, embassy, smol) or serialized streams (postcard over stdio/TCP/UART)
no_stdcompatible — core library works without allocator; embassy transport uses static allocation for embedded targets- Cancel-safe — dropping a client future mid-await never corrupts state
- Sync + async — generated clients and servers come in both async and
blocking (
BlockOn-based) variants for thread interop - Infallible transports — local transports return values directly (no
Resultwrapping) via theTransportResulttrait
Quick Example
This generates GreeterClient, GreeterRequest/GreeterResponse enums,
greeter_serve(), GreeterServiceSync, and transport-specific helpers.
Transports
| Transport | Feature | Use case |
|---|---|---|
| Tokio (mpsc + oneshot) | tokio |
In-process, tokio async |
| Embassy (static Channel + Signal) | embassy |
Embedded, no_std |
| Smol (async-channel) | smol |
In-process, smol async |
| Postcard stream | postcard |
Cross-process, serialized (stdio/TCP/UART) |
| CBOR stream | cbor |
Cross-process, self-describing (nitro bus, nbusctl tail) |
Unreleased
stream::codec: addCborCodecalongsidePostcardCodec, gated on the newcborCargo feature (off by default, pulls inminicbor-serde). Produces a self-describing wire format suitable for debuggable IPC buses (e.g. nitro'snbus/nbusctl tail). Postcard remains the default; the new codec is additive and slots intoStreamTransport/DuplexStreamTransportunchanged throughCborCodecError, which unifiesminicbor-serde's distinct encode/decode error types (the transport requiresEncoder::Error == Decoder::Error).stream::routing: addMuxedSlots::new_boxed() -> Box<Self>, which constructs theN × BUFslot array directly in a heap allocation. The existingMuxedSlots::new()builds the slot array on the stack first, so it overflows typical runtime worker stacks (e.g. tokio's 2 MiB default) for largeN * BUFconfigurations.new_boxedkeeps stack use bounded regardless ofBUF.stream::duplex::DuplexShared::slotsis nowBox<MuxedSlots<N, BUF>>, andDuplexStreamTransport::with_layersusesMuxedSlots::new_boxed(). This letsDuplexStreamTransport<_, _, _, _, 32, 131_072>construct on a 1 MiB stack — see the newduplex_construction_on_restricted_stackregression test. Hot paths (acquire,deliver,recv_reply,try_recv_slot) are unchanged — access goes throughBox's auto-deref.stream::transport: addwith_boxed_routerconstructor; consumesBox<MuxedSlots<N, BUF>>fromMuxedSlots::new_boxed(), avoids stack-overflow forBUF≥ 256 KiB.
Provenance
This library was coded by Anthropic's Claude Opus using the tau agent.
License
Licensed under either of Apache License, Version 2.0 or MIT license at your option.