> ## 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.

# Channel System

> Multi-channel communication architecture for REPL, HTTP, WASM, and Web Gateway

## Overview

Channels are IronClaw's abstraction for receiving messages from external sources and sending responses back. They provide a unified interface regardless of the underlying transport (CLI, HTTP, Telegram, web browser).

## Architecture

```mermaid theme={null}
graph TB
    subgraph External
        CLI[Command Line]
        TG[Telegram]
        WH[Webhooks]
        Browser[Web Browser]
    end
    
    subgraph Channels
        REPL[ReplChannel]
        WASM[WasmChannel<br/>Telegram, Slack]
        HTTP[HttpChannel]
        WEB[WebGateway<br/>SSE + WebSocket]
    end
    
    subgraph Core
        CM[ChannelManager]
        AL[Agent Loop]
    end
    
    CLI --> REPL
    TG --> WASM
    WH --> HTTP
    Browser --> WEB
    
    REPL --> CM
    WASM --> CM
    HTTP --> CM
    WEB --> CM
    
    CM --> AL
    AL --> CM
```

## Channel Trait

All channels implement a common interface:

<CodeGroup>
  ```rust Channel Trait theme={null}
  #[async_trait]
  pub trait Channel: Send + Sync {
      fn name(&self) -> &str;
      
      async fn start(&self) -> Result<MessageStream>;
      
      async fn respond(
          &self,
          msg: &IncomingMessage,
          response: OutgoingResponse,
      ) -> Result<()>;
      
      async fn send_status(
          &self,
          status: StatusUpdate,
          metadata: &serde_json::Value,
      ) -> Result<()>;
      
      async fn broadcast(
          &self,
          user_id: &str,
          response: OutgoingResponse,
      ) -> Result<()>;
      
      async fn health_check(&self) -> Result<()>;
      
      fn conversation_context(
          &self,
          metadata: &serde_json::Value
      ) -> HashMap<String, String>;
      
      async fn shutdown(&self) -> Result<()>;
  }
  ```
</CodeGroup>

## Message Types

### Incoming Message

Unified format for all inbound messages:

```rust theme={null}
pub struct IncomingMessage {
    pub id: Uuid,
    pub channel: String,          // "repl", "telegram", "http", "web"
    pub user_id: String,           // Channel-specific user identifier  
    pub user_name: Option<String>, // Display name
    pub content: String,           // Message text
    pub thread_id: Option<String>, // For threaded conversations
    pub received_at: DateTime<Utc>,
    pub metadata: serde_json::Value, // Channel-specific data
}
```

**Example**:

<CodeGroup>
  ```rust REPL Message theme={null}
  IncomingMessage {
      channel: "repl",
      user_id: "default",
      content: "What's the weather?",
      thread_id: None,
      metadata: serde_json::Value::Null,
  }
  ```

  ```rust Telegram Message   theme={null}
  IncomingMessage {
      channel: "telegram",
      user_id: "123456789",
      user_name: Some("alice"),
      content: "@bot what's the weather?",
      thread_id: None,
      metadata: json!({
          "chat_id": -987654321,
          "message_id": 42,
          "chat_type": "group"
      }),
  }
  ```

  ```rust Web Gateway Message theme={null}
  IncomingMessage {
      channel: "web",
      user_id: "user_abc123",
      content: "Build me a CLI tool",
      thread_id: Some("thread_xyz"),
      metadata: json!({
          "session_id": "sess_...",
          "connection_id": "conn_..."
      }),
  }
  ```
</CodeGroup>

### Outgoing Response

Format for responses back to channels:

```rust theme={null}
pub struct OutgoingResponse {
    pub content: String,                // Response text
    pub thread_id: Option<String>,      // Reply thread
    pub attachments: Vec<String>,       // File paths
    pub metadata: serde_json::Value,    // Channel-specific
}
```

### Status Updates

Real-time activity indicators:

```rust theme={null}
pub enum StatusUpdate {
    Thinking(String),
    ToolStarted { name: String },
    ToolCompleted { name: String, success: bool },
    ToolResult { name: String, preview: String },
    StreamChunk(String),
    Status(String),
    JobStarted { job_id: String, title: String, browse_url: String },
    ApprovalNeeded { request_id: String, tool_name: String, ... },
    AuthRequired { extension_name: String, auth_url: Option<String>, ... },
    AuthCompleted { extension_name: String, success: bool, ... },
}
```

## Built-in Channels

### REPL Channel

Interactive command-line interface.

<CodeGroup>
  ```rust Implementation theme={null}
  pub struct ReplChannel {
      tx: mpsc::Sender<IncomingMessage>,
      rx: Mutex<Option<mpsc::Receiver<IncomingMessage>>>,
  }
  ```

  ```bash Usage theme={null}
  $ ironclaw

  ┌─────────────────────────────────────────────────────────┐
  │                      IronClaw v0.1.0                    │
  │         Your secure personal AI assistant               │
  └─────────────────────────────────────────────────────────┘

  > What's on my calendar today?

  [Agent processes request...]

  You have 3 events today:
  - 9:00 AM: Team standup
  - 2:00 PM: Design review  
  - 4:30 PM: 1:1 with Sarah

  >
  ```
</CodeGroup>

**Features**:

* Readline support (history, editing)
* Command completion
* Multi-line input (Ctrl+D to submit)
* Status updates (thinking indicators)
* Color-coded output

**Commands**:

<AccordionGroup>
  <Accordion title="Session Management">
    * `/quit`, `/exit` - Exit IronClaw
    * `/clear` - Clear conversation
    * `/new` - Start new thread
    * `/undo` - Undo last turn
    * `/redo` - Redo undone turn
  </Accordion>

  <Accordion title="Job Control">
    * `/jobs` - List running jobs
    * `/status <id>` - Check job status
    * `/cancel <id>` - Cancel job
    * `/interrupt` - Stop current operation
  </Accordion>

  <Accordion title="Memory">
    * `/compact` - Compact conversation history
    * `/summarize` - Summarize current thread
    * `/heartbeat` - Run heartbeat check
  </Accordion>
</AccordionGroup>

### HTTP Channel

Webhook receiver for external integrations.

<CodeGroup>
  ```rust Configuration theme={null}
  pub struct HttpChannel {
      port: u16,              // Default: 3000
      bind_addr: String,      // Default: "127.0.0.1"
  }
  ```

  ```bash Start Server theme={null}
  ironclaw --http-port 3000
  ```
</CodeGroup>

**Endpoints**:

<CodeGroup>
  ```http POST /webhook theme={null}
  POST /webhook HTTP/1.1
  Content-Type: application/json

  {
    "user_id": "github_webhook",
    "content": "Deploy to production failed: timeout",
    "metadata": {
      "repo": "myorg/myapp",
      "commit": "abc123",
      "severity": "high"
    }
  }
  ```

  ```http Response theme={null}
  HTTP/1.1 200 OK
  Content-Type: application/json

  {
    "message_id": "550e8400-e29b-41d4-a716-446655440000",
    "status": "processing"
  }
  ```
</CodeGroup>

**Use Cases**:

* CI/CD notifications
* Monitoring alerts
* External system events
* Scheduled jobs (cron)

### WASM Channels

Dynamic channel implementations loaded as WebAssembly modules.

**Architecture**:

```text theme={null}
┌─────────────────────────────────────────────────────┐
│            WASM Channel Runtime                     │
│                                                     │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────┐  │
│  │  Telegram    │  │    Slack     │  │  Signal  │  │
│  │  (telegram.  │  │  (slack.     │  │ (signal. │  │
│  │   wasm)      │  │   wasm)      │  │  wasm)   │  │
│  └──────┬───────┘  └──────┬───────┘  └────┬─────┘  │
│         │                 │                │        │
│         └─────────────────┴────────────────┘        │
│                           │                         │
│                  ┌────────▼─────────┐               │
│                  │  Host Functions  │               │
│                  │  - http_call     │               │
│                  │  - log           │               │
│                  │  - time          │               │
│                  └──────────────────┘               │
└─────────────────────────────────────────────────────┘
```

**Capabilities**:

<CodeGroup>
  ```rust HTTP Capability theme={null}
  HttpCapability::new(vec![
      EndpointPattern::host("api.telegram.org")
          .with_path_prefix("/bot"),
  ])
  ```

  ```rust Secrets Capability   theme={null}
  SecretsCapability::new(vec![
      "TELEGRAM_BOT_TOKEN",
      "TELEGRAM_WEBHOOK_SECRET",
  ])
  ```
</CodeGroup>

**Example: Telegram Channel**

<Steps>
  <Step title="Build WASM Module">
    ```bash theme={null}
    cd channels-src/telegram
    cargo build --target wasm32-wasip1 --release
    ```
  </Step>

  <Step title="Bundle with Runtime">
    ```bash theme={null}
    # Automatically bundled during ironclaw build
    cargo build --release
    ```
  </Step>

  <Step title="Configure Bot Token">
    ```bash theme={null}
    ironclaw config set TELEGRAM_BOT_TOKEN <your-token>
    ```
  </Step>

  <Step title="Start IronClaw">
    ```bash theme={null}
    ironclaw --enable-telegram
    ```
  </Step>
</Steps>

<Info>
  See [Telegram Setup Guide](/channels/telegram) for complete integration instructions.
</Info>

### Web Gateway

Browser-based UI with real-time streaming.

**Transport Protocols**:

<Tabs>
  <Tab title="Server-Sent Events (SSE)">
    **Purpose**: Server-to-client streaming (status updates, tool execution)

    ```javascript theme={null}
    const eventSource = new EventSource('/api/chat/stream?session_id=...');

    eventSource.addEventListener('thinking', (e) => {
      const data = JSON.parse(e.data);
      showThinkingIndicator(data.message);
    });

    eventSource.addEventListener('tool_started', (e) => {
      const data = JSON.parse(e.data);
      addToolCard(data.name);
    });

    eventSource.addEventListener('message', (e) => {
      const data = JSON.parse(e.data);
      appendToResponse(data.content);
    });
    ```

    **Event Types**:

    * `thinking` - Agent is processing
    * `tool_started` - Tool execution began
    * `tool_result` - Tool output preview
    * `message` - Response chunk
    * `complete` - Turn finished
    * `error` - Error occurred
  </Tab>

  <Tab title="WebSocket">
    **Purpose**: Bidirectional communication (alternative to SSE)

    ```javascript theme={null}
    const ws = new WebSocket('ws://localhost:3000/api/ws');

    ws.addEventListener('open', () => {
      ws.send(JSON.stringify({
        type: 'user_message',
        content: 'What is the weather?',
        thread_id: 'thread_123'
      }));
    });

    ws.addEventListener('message', (event) => {
      const msg = JSON.parse(event.data);
      switch (msg.type) {
        case 'assistant_message':
          displayResponse(msg.content);
          break;
        case 'tool_execution':
          showToolStatus(msg.tool_name, msg.status);
          break;
      }
    });
    ```
  </Tab>
</Tabs>

**UI Features**:

<CardGroup cols={2}>
  <Card title="Chat Interface" icon="message">
    * Multi-threaded conversations
    * Real-time streaming responses
    * Tool execution cards
    * Approval prompts
  </Card>

  <Card title="Memory Browser" icon="brain">
    * Search workspace files
    * View/edit documents
    * Daily logs explorer
    * Memory tree view
  </Card>

  <Card title="Job Monitor" icon="briefcase">
    * Live job tracking
    * Container logs
    * Status updates
    * Cancel/retry controls
  </Card>

  <Card title="Extensions" icon="puzzle-piece">
    * Install MCP servers
    * Manage WASM tools
    * OAuth authentication
    * Tool activation
  </Card>
</CardGroup>

## Channel Manager

Coordinates multiple channels and message routing.

<CodeGroup>
  ```rust ChannelManager theme={null}
  pub struct ChannelManager {
      channels: Arc<RwLock<HashMap<String, Arc<dyn Channel>>>>,
  }

  impl ChannelManager {
      pub async fn start_all(&self) -> Result<MessageStream> {
          // Start all channels and merge streams
      }
      
      pub async fn respond(
          &self,
          msg: &IncomingMessage,
          response: OutgoingResponse,
      ) -> Result<()> {
          // Route response to originating channel
      }
      
      pub async fn broadcast(
          &self,
          channel: &str,
          user_id: &str,
          response: OutgoingResponse,
      ) -> Result<()> {
          // Send proactive message
      }
      
      pub async fn broadcast_all(
          &self,
          user_id: &str,
          response: OutgoingResponse,
      ) -> HashMap<String, Result<()>> {
          // Broadcast to all channels
      }
  }
  ```
</CodeGroup>

**Message Flow**:

```mermaid theme={null}
sequenceDiagram
    participant C as Channel
    participant CM as ChannelManager
    participant AL as Agent Loop
    
    C->>CM: IncomingMessage
    CM->>AL: Forward message
    AL->>AL: Process
    AL->>CM: OutgoingResponse
    CM->>C: Route to channel
    C-->>User: Display response
```

## Conversation Context

Channels provide contextual information for the LLM:

<CodeGroup>
  ```rust REPL Context theme={null}
  fn conversation_context(&self, _metadata: &Value) -> HashMap<String, String> {
      HashMap::new() // Direct 1:1 session
  }
  ```

  ```rust Telegram Context theme={null}
  fn conversation_context(&self, metadata: &Value) -> HashMap<String, String> {
      let mut context = HashMap::new();
      
      if let Some(chat_type) = metadata.get("chat_type") {
          context.insert("chat_type".into(), chat_type.to_string());
      }
      
      if let Some(from) = metadata.get("from_username") {
          context.insert("sender".into(), from.to_string());
      }
      
      if chat_type == "group" || chat_type == "supergroup" {
          context.insert("is_group".into(), "true".into());
      }
      
      context
  }
  ```
</CodeGroup>

**System Prompt Injection**:

```text theme={null}
You are IronClaw, a secure personal AI assistant.

Context:
- Channel: telegram
- Chat Type: group  
- Sender: @alice
- Group: Engineering Team

Guidelines:
- This is a group chat. Be concise.
- Do not share private user context in groups.
- Address @alice specifically in your response.
```

## Broadcasting

Channels support proactive messaging for alerts and notifications.

**Example: Heartbeat Notification**

<CodeGroup>
  ```rust Heartbeat Runner theme={null}
  if let Some(urgent) = heartbeat_result.urgent_items {
      let message = format!(
          "Heartbeat Alert:\n\n{}",
          urgent.join("\n")
      );
      
      channels.broadcast_all(
          "default",
          OutgoingResponse::text(message)
      ).await;
  }
  ```

  ```text Result theme={null}
  [Telegram] Heartbeat Alert:
  - 3 unread emails marked urgent
  - Production deploy failed 15 min ago
  - Calendar reminder: meeting in 5 min

  [Web Gateway] [Same message in browser notification]

  [REPL] [Printed to terminal if running]
  ```
</CodeGroup>

**Use Cases**:

* Heartbeat urgent items
* Routine execution results
* System alerts
* Self-repair notifications
* Job completion updates

## Thread Management

Channels support multi-threaded conversations.

<CodeGroup>
  ```rust Create Thread theme={null}
  let msg = IncomingMessage::new("web", "user_123", "Hello")
      .with_thread("thread_abc");
  ```

  ```rust Thread Isolation theme={null}
  // Each thread maintains separate:
  - Conversation history
  - Context window
  - Undo/redo stack
  - Pending approvals
  ```
</CodeGroup>

**Thread Lifecycle**:

1. **Creation**: First message in thread
2. **Hydration**: Load from database if historical
3. **Updates**: Append turns as conversation continues
4. **Persistence**: Save to database after each turn
5. **Pruning**: Auto-delete stale threads after idle timeout

## Custom Channel Development

Build your own channel implementation:

<Steps>
  <Step title="Implement Channel Trait">
    ```rust theme={null}
    pub struct MyChannel {
        // Your channel state
    }

    #[async_trait]
    impl Channel for MyChannel {
        fn name(&self) -> &str { "my_channel" }
        
        async fn start(&self) -> Result<MessageStream> {
            // Connect to your message source
            // Return stream of IncomingMessage
        }
        
        async fn respond(
            &self,
            msg: &IncomingMessage,
            response: OutgoingResponse,
        ) -> Result<()> {
            // Send response back via your protocol
        }
        
        // ... implement other methods
    }
    ```
  </Step>

  <Step title="Register with ChannelManager">
    ```rust theme={null}
    let channel = Arc::new(MyChannel::new());
    channel_manager.register(channel).await;
    ```
  </Step>

  <Step title="Handle Messages">
    Channel manager automatically:

    * Merges your stream with others
    * Routes responses back to your channel
    * Handles broadcasts
  </Step>
</Steps>

<Tip>
  For production channels, consider building as WASM modules for hot-reloading and sandboxing.
</Tip>

## Next Steps

<CardGroup cols={2}>
  <Card title="Telegram Setup" icon="paper-plane" href="/channels/telegram">
    Configure Telegram bot integration
  </Card>

  <Card title="Web Gateway" icon="browser" href="/channels/web-gateway">
    Deploy browser-based interface
  </Card>

  <Card title="Webhook Server" icon="webhook" href="/channels/webhooks">
    Receive events from external systems
  </Card>

  <Card title="WASM Channels" icon="cube" href="/channels/wasm-channels">
    Build custom channels as WASM modules
  </Card>
</CardGroup>
