Documentation Index Fetch the complete documentation index at: https://mintlify.com/nearai/ironclaw/llms.txt
Use this file to discover all available pages before exploring further.
Overview
Channels receive messages from external sources (CLI, HTTP, WebSockets, etc.) and convert them to a unified message format for the agent to process.
The channel system supports:
Multiple concurrent input channels
Unified message abstraction
Streaming message delivery
Channel-specific metadata
WASM-based dynamic channel loading
Architecture
┌─────────────────────────────────────────────────────────────────────┐
│ ChannelManager │
│ │
│ ┌──────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ ReplChannel │ │ HttpChannel │ │ WasmChannel │ ... │
│ └──────┬───────┘ └──────┬──────┘ └──────┬──────┘ │
│ │ │ │ │
│ └─────────────────┴─────────────────┘ │
│ │ │
│ select_all (futures) │
│ │ │
│ ▼ │
│ MessageStream │
└─────────────────────────────────────────────────────────────────────┘
Core Types
Channel Trait
The main trait that all channels must implement.
#[async_trait]
pub trait Channel : Send + Sync {
fn name ( & self ) -> & str ;
fn message_stream ( & self ) -> MessageStream ;
async fn send ( & self , response : OutgoingResponse ) -> Result <(), ChannelError >;
async fn send_status ( & self , status : StatusUpdate ) -> Result <(), ChannelError >;
}
Methods
Return the channel name (must be unique)
message_stream
fn(&self) -> MessageStream
Get a stream of incoming messages from this channel
send
async fn(&self, response: OutgoingResponse) -> Result<()>
Send a response back through this channel
send_status
async fn(&self, status: StatusUpdate) -> Result<()>
Send a status update (typing indicator, progress, etc.)
IncomingMessage
A message received from an external channel.
Unique message identifier
Channel this message came from
User identifier within the channel
Optional display name for the user
Thread/conversation ID for threaded conversations
When the message was received
Channel-specific metadata
Constructors
new
fn(channel: impl Into<String>, user_id: impl Into<String>, content: impl Into<String>) -> Self
Create a new incoming message
with_thread
fn(self, thread_id: impl Into<String>) -> Self
Set the thread ID
with_metadata
fn(self, metadata: serde_json::Value) -> Self
Set channel-specific metadata
with_user_name
fn(self, name: impl Into<String>) -> Self
Set the user’s display name
Example
use ironclaw :: channels :: IncomingMessage ;
let msg = IncomingMessage :: new ( "slack" , "U12345" , "Hello agent!" )
. with_thread ( "C67890" )
. with_user_name ( "Alice" );
OutgoingResponse
A response to send back through a channel.
Optional thread ID to reply in
Optional file paths to attach
Channel-specific metadata for the response
Constructors
text
fn(content: impl Into<String>) -> Self
Create a simple text response
in_thread
fn(self, thread_id: impl Into<String>) -> Self
Set the thread ID for the response
with_attachments
fn(self, attachments: Vec<String>) -> Self
Add file attachments
with_metadata
fn(self, metadata: serde_json::Value) -> Self
Set channel-specific metadata
Example
use ironclaw :: channels :: OutgoingResponse ;
let response = OutgoingResponse :: text ( "Task completed!" )
. in_thread ( "C67890" )
. with_attachments ( vec! [ "report.pdf" . to_string ()]);
channel . send ( response ) . await ? ;
StatusUpdate
Status updates sent during processing (typing indicators, progress, etc.).
Optional progress (0.0 to 1.0)
StatusKind
Agent is processing the request
Agent is executing a tool (includes tool name)
Example
use ironclaw :: channels :: { StatusUpdate , StatusKind };
let status = StatusUpdate {
kind : StatusKind :: ToolExecution ( "http" . to_string ()),
message : Some ( "Fetching data..." . to_string ()),
progress : Some ( 0.5 ),
};
channel . send_status ( status ) . await ? ;
MessageStream
A stream of incoming messages from a channel.
pub type MessageStream = Pin < Box < dyn Stream < Item = IncomingMessage > + Send >>;
Use with async stream combinators:
use futures :: StreamExt ;
let mut stream = channel . message_stream ();
while let Some ( msg ) = stream . next () . await {
println! ( "Received: {} from {}" , msg . content, msg . user_id);
}
Built-in Channels
ReplChannel
Interactive command-line REPL channel.
Create a new REPL channel with stdin/stdout
with_prompt
fn(prompt: impl Into<String>) -> Self
Set a custom prompt string
use ironclaw :: channels :: ReplChannel ;
let repl = ReplChannel :: new () . with_prompt ( "ironclaw> " );
HttpChannel
HTTP webhook receiver channel.
new
fn(addr: impl Into<SocketAddr>) -> Self
Create a new HTTP channel listening on the given address
with_auth
fn(self, token: impl Into<String>) -> Self
Add bearer token authentication
use ironclaw :: channels :: HttpChannel ;
let http = HttpChannel :: new ( "127.0.0.1:8080" )
. with_auth ( "secret-token-123" );
HTTP Endpoint
The HTTP channel exposes a POST endpoint:
curl -X POST http://localhost:8080/message \
-H "Content-Type: application/json" \
-H "Authorization: Bearer secret-token-123" \
-d '{
"user_id": "user_123",
"content": "Hello agent!",
"thread_id": "thread_456"
}'
SignalChannel
Unix signal handler channel (SIGUSR1, SIGUSR2, etc.).
new
fn(signals: Vec<Signal>) -> Self
Create a signal channel that listens for the specified Unix signals
use ironclaw :: channels :: SignalChannel ;
use signal_hook :: consts :: signal ::* ;
let signal_ch = SignalChannel :: new ( vec! [ SIGUSR1 , SIGUSR2 ]);
GatewayChannel
WebSocket gateway for real-time bidirectional communication.
new
fn(addr: impl Into<SocketAddr>) -> Self
Create a WebSocket gateway listening on the given address
with_auth
fn(self, auth_fn: AuthFn) -> Self
Add custom authentication function
use ironclaw :: channels :: GatewayChannel ;
let gateway = GatewayChannel :: new ( "127.0.0.1:9000" );
Channel Manager
ChannelManager
Manages multiple channels and multiplexes their message streams.
Create a new channel manager
register
fn(&mut self, channel: Arc<dyn Channel>)
Register a channel with the manager
message_stream
fn(&self) -> MessageStream
Get a unified stream of messages from all registered channels
send
async fn(&self, channel_name: &str, response: OutgoingResponse) -> Result<()>
Send a response to a specific channel
Example
use ironclaw :: channels :: { ChannelManager , ReplChannel , HttpChannel };
use futures :: StreamExt ;
let mut manager = ChannelManager :: new ();
manager . register ( Arc :: new ( ReplChannel :: new ()));
manager . register ( Arc :: new ( HttpChannel :: new ( "127.0.0.1:8080" )));
let mut stream = manager . message_stream ();
while let Some ( msg ) = stream . next () . await {
// Process messages from all channels
println! ( "[{}] {}: {}" , msg . channel, msg . user_id, msg . content);
// Send response back through the originating channel
manager . send (
& msg . channel,
OutgoingResponse :: text ( "Received!" )
) . await ? ;
}
WASM Channels
Dynamically load channel implementations at runtime using WebAssembly.
WasmChannel
A channel implementation loaded from a WASM module.
load
async fn(wasm_bytes: &[u8]) -> Result<Self>
Load a WASM module as a channel
from_file
async fn(path: &Path) -> Result<Self>
Load a WASM channel from a file
use ironclaw :: channels :: wasm :: WasmChannel ;
let wasm_bytes = std :: fs :: read ( "channels/discord.wasm" ) ? ;
let channel = WasmChannel :: load ( & wasm_bytes ) . await ? ;
manager . register ( Arc :: new ( channel ));
WASM Channel Interface
WASM channels must implement the following interface:
// Export these functions from your WASM module
#[no_mangle]
pub extern "C" fn channel_name () -> * const u8 ;
#[no_mangle]
pub extern "C" fn channel_init () -> i32 ;
#[no_mangle]
pub extern "C" fn channel_poll_message () -> * const u8 ;
#[no_mangle]
pub extern "C" fn channel_send_response ( response_ptr : * const u8 , response_len : usize ) -> i32 ;
See the wasm module documentation for full details on the WASM channel ABI.
Error Handling
ChannelError
Errors that can occur during channel operations.
Failed to establish connection
Failed to send message/response
Received malformed message
Authentication/authorization failed
Channel or resource not found
WebSocket Gateway
The GatewayChannel provides a production-ready WebSocket server for real-time communication.
Client Connection
const ws = new WebSocket ( 'ws://localhost:9000' );
ws . onopen = () => {
ws . send ( JSON . stringify ({
type: 'message' ,
user_id: 'user_123' ,
content: 'Hello agent!' ,
thread_id: 'thread_456'
}));
};
ws . onmessage = ( event ) => {
const response = JSON . parse ( event . data );
console . log ( 'Agent:' , response . content );
};
Status Updates
The gateway sends real-time status updates:
ws . onmessage = ( event ) => {
const msg = JSON . parse ( event . data );
if ( msg . type === 'status' ) {
console . log ( 'Status:' , msg . kind , msg . message );
} else if ( msg . type === 'response' ) {
console . log ( 'Response:' , msg . content );
}
};
Best Practices
Channel isolation : Each channel should handle its own protocol/transport details
Unified messages : Convert channel-specific formats to IncomingMessage early
Metadata : Use the metadata field for channel-specific context (message IDs, etc.)
Error handling : Channels should gracefully handle disconnections and reconnect
Authentication : Validate users before accepting messages
Rate limiting : Consider rate limiting per user/channel to prevent abuse
Agent Module Agent orchestration and message processing
Tools Module Tools that agents can use to respond to messages