How the tinychannels Crate Enables OpenHuman's 17 Messaging Channel Integrations

The tinychannels crate provides a unified transport, authentication, and data-model layer that allows OpenHuman to support 17 messaging platforms through thin re-exports rather than custom implementations.

OpenHuman's messaging architecture delegates all platform-specific heavy lifting to the tinychannels crate, a portable Rust library that abstracts Telegram, Discord, Slack, WhatsApp, iMessage, and 12 other services behind a common interface. By treating tinychannels as the single source of truth for channel logic, the tinyhumansai/openhuman repository maintains a lean codebase while offering extensive messenger compatibility. This integration pattern reduces adding new providers to a single line of code.

Architectural Overview of the tinychannels Integration

OpenHuman’s messaging layer lives under src/openhuman/channels/. Rather than reinvent transport logic for each service, OpenHuman delegates WebSocket handling, message serialization, OAuth flows, and platform-specific networking to tinychannels, exposing these capabilities through its own domain APIs and RPC endpoints.

The Channel Trait and Core Abstractions

At the foundation lies the Channel trait, which defines the minimal API every messenger must implement: send, listen, and auth. OpenHuman re-exports these types directly from tinychannels in src/openhuman/channels/traits.rs:

pub use tinychannels::{Channel, ChannelMessage, ChannelSendExt, SendMessage};

This re-export strategy ensures that OpenHuman’s interactive loop always uses the upstream trait definitions, guaranteeing consistency across all 17 integrated services.

Provider Re-exports and Feature Gating

Each of the 17 messaging providers exists as a thin module under src/openhuman/channels/providers/. These modules contain no implementation logic; they simply re-export the corresponding tinychannels provider. For example, src/openhuman/channels/providers/telegram/mod.rs contains:

pub use tinychannels::providers::telegram::{session_store, TelegramChannel};

Providers are conditionally compiled behind the channels feature flag using #[cfg(feature = "channels")] blocks in src/openhuman/channels/mod.rs. Building without a specific provider omits the corresponding re-export, and the channel runtime gracefully skips absent tools.

Runtime Host and Relay Infrastructure

The channel host supplies the runtime context—storage paths, credential stores, and policy enforcement—that providers require. OpenHuman constructs this host using tinychannels::host::ChannelHostBuilder in src/openhuman/channels/host/mod.rs, assembling it once per process and handing it to every provider.

For real-time communication, OpenHuman connects its relay runtime to tinychannels’ transport layer. The file src/openhuman/channels/relay_runtime.rs utilizes tinychannels::relay::RelayTransport and tinychannels::relay::WebSocketRelayConfig to manage inbound and outbound message envelopes.

How OpenHuman Implements the 17 Channel Stack

The integration spans seven architectural layers, each delegating to tinychannels:

All heavy lifting—OAuth flows, platform-specific networking, and message serialization—remains encapsulated within the tinychannels crate.

Adding a New Messaging Provider

Integrating an additional messenger requires no new logic in OpenHuman. The process follows four steps:

  1. Upstream Implementation: The tinychannels crate adds a new provider (e.g., providers::newservice).
  2. Re-export: OpenHuman adds a thin module under src/openhuman/channels/providers/ containing pub use tinychannels::providers::newservice::NewServiceChannel;.
  3. Feature Flagging: The provider is gated behind the channels feature in src/openhuman/channels/mod.rs.
  4. Automatic Exposure: The ChannelManager registered at startup automatically picks up the new provider through the existing RPC controller code.

Thus, the integration effort is reduced to a single line of re-export while tinychannels guarantees consistent behavior across all supported services.

Working with Channels in Practice

Sending Messages via the Unified API

OpenHuman exposes a uniform interface for sending messages regardless of the underlying platform. The following example demonstrates sending an email using the shared ChannelSendExt trait:

use openhuman::channels::{Channel, EmailChannel, SendMessage};

// Build the OpenHuman channel host (normally done at startup)
let host = openhuman::channels::host::build_channel_host()?;

// Obtain a concrete channel instance
let email: EmailChannel = host
    .provider_registry()
    .get::<EmailChannel>()
    .expect("Email provider not configured");

// Use the unified ChannelSendExt trait to send a message
let result = email
    .send_message(
        SendMessage {
            to: "user@example.com".into(),
            body: "Hello from OpenHuman!".into(),
            ..Default::default()
        },
    )
    .await?;

println!("Message sent, id: {}", result.message_id);

Listening for Inbound Events

Inbound message handling utilizes the host's unified stream, filtering envelopes by channel type:

use openhuman::channels::{Channel, ChannelHost};
use futures::StreamExt;

// Assume a host has been built as above
let host: ChannelHost = openhuman::channels::host::build_channel_host()?;

// Subscribe to inbound events from all configured channels
let mut inbound = host
    .inbound_stream()
    .await?
    .filter_map(|envelope| async move { envelope.ok() });

while let Some(envelope) = inbound.next().await {
    println!(
        "Incoming {} message from {}",
        envelope.channel.kind(),
        envelope.sender.id()
    );
}

Cargo Feature Configuration

Providers are toggled via Cargo features. The channels feature enables the core runtime, while individual messengers can be selectively included:

[features]
default = ["channels"]
channels = []                     # core flag

telegram = ["channels"]           # enables TelegramChannel

discord  = ["channels"]           # enables DiscordChannel

Source Code Reference

Key files illustrating the tinychannels integration include:

Summary

  • The tinychannels crate abstracts all transport, authentication, and messaging logic for 17 platforms, allowing OpenHuman to avoid platform-specific implementations.
  • Architecture: OpenHuman re-exports traits from src/openhuman/channels/traits.rs and providers from src/openhuman/channels/providers/, delegating runtime management to ChannelHostBuilder and ChannelManager.
  • Integration Cost: Adding a new messenger requires only a single-line re-export in src/openhuman/channels/providers/ and a feature flag, as all logic resides in the upstream crate.
  • Unified API: All channels implement the Channel trait and ChannelSendExt, enabling generic message sending and inbound stream processing regardless of the underlying service.

Frequently Asked Questions

What is the tinychannels crate and why does OpenHuman use it?

The tinychannels crate is a self-contained Rust library that implements the full messaging stack—including WebSocket handling, OAuth flows, and platform-specific networking—for 17 different messaging services. OpenHuman uses it to avoid maintaining 17 separate integrations, instead relying on tinychannels as the single source of truth for all messaging functionality.

How does OpenHuman add support for a new messaging platform?

Adding support requires only a re-export in src/openhuman/channels/providers/newservice/mod.rs that exposes the tinychannels provider type, plus a feature flag in the crate configuration. The existing ChannelManager and RPC controllers automatically pick up the new provider without additional logic, as all implementation details live in the tinychannels crate.

What role does the ChannelHost play in the messaging architecture?

The ChannelHost, constructed via tinychannels::host::ChannelHostBuilder in src/openhuman/channels/host/mod.rs, supplies the runtime context required by all providers—including storage paths, credential stores, and policy enforcement. It serves as the central registry and execution environment for the 17 integrated messaging channels.

How are messaging channels configured and enabled in OpenHuman?

Channels are configured through re-exported tinychannels types in src/openhuman/config/schema/channels.rs and enabled via Cargo features. The base channels feature activates the runtime, while individual providers (e.g., telegram, discord) are toggled as separate features that simply re-export the corresponding tinychannels modules.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →