TinyChannels is a Rust library for OpenHuman channel and messaging primitives. It provides the portable channel contract, channel configuration schema, connection metadata, route helpers, and backend delegation layer used to connect channel surfaces to OpenHuman harnesses without coupling this crate to the OpenHuman application crate.
Configured provider discovery, legacy intent normalization, and external-webhook outbound startup are confidential module operations. The catalog returns provider facts without listening; outbound-only startup preserves Linq and WhatsApp Cloud sends while keeping their ingress explicitly external. Existing listener start methods retain their refusal when no webhook ingress is available.
Inbound preparation and hosted identity projection are confidential module operations. They return stable history, thread, client, and session keys using the module’s existing provider rules. Preparation preserves rich envelope data and rejects conflicting legacy identities. Hosts retain authenticated transport provenance separately: the envelope’s relay trust flag is intentionally omitted from serialization. Namespaces are limited to 256 bytes, identity requests to 4 KiB, and inbound requests to the bounded preparation payload limit.
Progressive replies run inside the private channel runtime through confidential
ExecuteProgressive commands. The module owns drafts, thinking and filler
bubbles, typing timers, error recovery, normalization, and idempotency keys;
DispatchControllerBackend supplies only the host's managed transport with
typed outcomes. Reply handles cannot cross runtimes. Terminal cleanup survives
caller cancellation, identical finalization retries do not send twice, and
shutdown joins replies before closing callbacks. Limits are 16 active replies,
128 retained terminal handles, 32 events and 128 KiB per command, 384 KiB per
accumulator, and a three-minute worker lifetime.
Runtime model/provider commands are prepared through confidential
PrepareRuntimeCommand. Hosts supply the current route, provider aliases and
an already-loaded model catalog. The module preserves the existing Telegram
and Discord command parser, unknown-provider proposals and help text, including
the first matching provider's first ten cached model IDs. It returns a proposal
or a ready-to-send reply; applying route changes, validating model IDs, clearing
history and reading product catalog storage remain host responsibilities.
Unrecognized commands return no proposal. Requests obey the existing bounded
preparation payload limit and fail after module shutdown.
- channel abstractions for inbound and outbound message streams
- harness-facing communication contracts
- transport-neutral message envelopes and routing metadata
- adapters for OpenHuman channel surfaces
- observability and lifecycle hooks around channel traffic
Runtime side effects are pluggable through ChannelBackend. OpenHuman owns the
actual backend implementation for REST/JWT/config storage, while this crate
validates channel metadata and delegates operations through that trait.
TinyChannels includes optional provider implementations that must be explicitly enabled:
| Provider | Feature | Channels | Dependencies |
|---|---|---|---|
| Email (send only) | email-send |
EmailChannel (SMTP send), providers::mail::LettreMailSender (async, per-credential) |
lettre |
email |
EmailChannel (SMTP + IMAP), providers::mail::AsyncImapReceiver |
lettre, async-imap, mail-parser |
|
| Lark/Feishu | lark |
LarkChannel (webhook receiver + Protobuf decoder) |
axum, prost |
| WhatsApp Web | whatsapp-web |
WhatsAppWebChannel (multi-device via whatsapp-rust) |
whatsapp-rust, whatsapp-rust-tokio-transport, whatsapp-rust-ureq-http-client, wacore |
Not on crates.io. This crate and
tinychannels-busarepublish = falseOpenHuman uses the vendored path dependency undervendor/tinychannels. Other consumers can use the direct Git dependency shown below. What a host loads at runtime is the compiledtinychannels-modulecdylib, delivered as a release artifact and pinned by SHA-256, not a published crate.
The default feature set (default = []) does not include these providers. To use them, add to your Cargo.toml:
[dependencies]
tinychannels = { git = "https://github.com/tinyhumansai/tinychannels", features = ["email", "lark", "whatsapp-web"] }Or enable them individually as needed:
[dependencies]
tinychannels = { git = "https://github.com/tinyhumansai/tinychannels", features = ["email"] }The providers::mail vocabulary (MailSender/MailReceiver, provider-tagged
MailCredentials, ImapCredentials) is always compiled and links nothing; see
src/providers/mail/README.md.
If you only ever send mail — no mailbox is polled — take email-send instead.
It gives you EmailChannel::new, send_message and the build_*_message
helpers on lettre alone, without the IMAP receive stack (18 fewer packages):
[dependencies]
tinychannels = { git = "https://github.com/tinyhumansai/tinychannels", features = ["email-send"] }email-send carries no Channel impl — a send-only build cannot listen, so
the trait is gated on the full email feature rather than promising a
half-working channel.
All other providers (Telegram, Discord, Slack, Signal, iMessage, IRC, Yuanbao/钉钉, etc.) are included in the default build.
cargo fmt --check
cargo clippy --all-targets -- -D warnings
cargo build --all-targets
cargo test
# Build and load the actual cdylib against local websocket and SMTP fixtures
./scripts/verify-module-artifact.sh
# Test with all optional providers
cargo test --features email,larkcrates/tinychannels-bus/holds shared message/envelope DTOs, serialized channel configuration, capabilities, controller schemas/response types, relay frames and errors.crates/tinychannels-runtime/owns provider/adapter callbacks, listener and dispatch supervision, pairing and relay crypto, persisted key/idempotency algorithms, history/context processing, configuration preparation and text segmentation. It re-exports the same bus DTOs.crates/tinychannels-module/is the loadable TinyBus module.- The module keeps its original
StartChannel,StopChannel,SendMessage,ListChannelsandChannelStatusmembers, and adds relay reservation/start/ stop/status/send plusShutdown, typedSendChannelIntent, and send-onlySendEmail. Relay startup configuration and SMTP credentials are host hydrated and sent only over TinyBus confidential calls. Relay handles are bounded single-use leases; accepted sends run in bounded module-owned queues so dropping a call waiter does not cancel the operation.SendChannelIntentpreserves the idempotency and thread fields for the host's delivery policy. Until a host durable-queue port is installed,Requireddurability is refused before provider send; the module does not own a durable outbox. LegacySendEmailremains available for small requests; larger attachments use the confidentialBeginEmailUpload/AppendEmailUploadChunk/SendEmailUploadprotocol, with bounded chunks and a replayable terminal result keyed by the opaque upload handle. src/lib.rsexports the crate surface and re-exports the contract.src/providers/holds the provider transports.src/delivery/holds the durable outbound queue andprogressive/, the streaming reply driver (draft, thinking and filler bubbles) over a host-suppliedProgressiveSender. The reply splitter (segment_for_delivery) lives intinychannels-runtime(delivery::segment) and is re-exported here.src/remote/implements/status,/sessions,/newand/helpfor every provider with theremote_controlcapability, over a host-suppliedRemoteControlHost.src/approvals/sends in-chat approval prompts for every provider with thechat_approvalscapability.src/relay/holds the relay transport loop, the WebSocket dialer and the process-wide transport registry.src/backend.rsownsChannelBackendandChannelManager;src/host/is the host service boundary;src/routes.rsandsrc/runtime.rshold portable runtime helpers.
The pure-contract relocation specification records extension-trait source migrations and subsequent module-operation work.
ChannelController accepts the additive PrepareConnect request. TinyChannels
validates credentials, verifies native email or Yuanbao authentication, and
returns a typed provider configuration update alongside the existing connection
result. The host persists the update and retains credential custody. Email
passwords and Yuanbao application secrets are removed from the update. Existing
Connect requests and all member argument counts remain unchanged; this
capability requires module operation contract 1.8.
CheckChannelHealth(config, proxy, timeout_ms) checks configured providers without
starting their listeners. Hydrated credentials and proxy settings require a
confidential TinyBus call. The per-provider budget is bounded to 1–60,000 ms;
results retain provider order and distinguish healthy, unhealthy, and timeout.
Hosts own credential hydration and presentation. ChannelStatus(name) keeps its
existing arity and continues to report a running provider's state.
ExecuteRemote parses and renders /status, /sessions, /new, and /help
inside the module and owns persisted chat bindings and busy-state updates. The
host supplies validated workspace configuration, route/history facts, and
conversation/session operations through the existing confidential backend
callback. The module awaits host history clearing before committing a new
binding. Ordinary messages and unsupported providers produce no remote reply.
The additive contract is revision 14 / operation version 1.15; existing members
and callback arity are unchanged.
