Skip to main content
Grip AI uses a flexible multi-channel architecture that allows the AI agent to communicate through multiple chat platforms simultaneously. The system is built around a decoupled message bus that separates message producers (chat channels) from consumers (the agent gateway).

Architecture Overview

The channel system consists of three main components:

1. Chat Channels

Each chat platform (Telegram, Discord, Slack) implements the BaseChannel interface defined in channels/base.py. Channels:
  • Receive messages from their platform
  • Wrap them as InboundMessage objects
  • Push them onto the MessageBus
  • Subscribe to OutboundMessage to deliver agent replies back to users

2. Message Bus

The MessageBus (defined in bus/queue.py) provides async message passing between components: Inbound Queue: Channels push incoming user messages here. The gateway pops messages, processes them through the agent, and generates responses. Outbound Pub/Sub: The gateway publishes agent responses, and all subscribed channels receive them. Each channel filters for messages targeting their platform.

3. Channel Manager

The ChannelManager (in channels/manager.py) handles the lifecycle of all enabled channels:
  • Loads channel configurations on startup
  • Instantiates and starts enabled channels
  • Gracefully stops all channels on shutdown
  • Provides lookup for active channels

Message Flow

User → Chat Platform → Channel → InboundMessage → MessageBus

                                                   Gateway

                                                   Agent Loop

User ← Chat Platform ← Channel ← OutboundMessage ← MessageBus
1
Step 1: User sends message
2
User sends a message through Telegram, Discord, or Slack.
3
Step 2: Channel receives message
4
The platform-specific channel implementation receives the message via webhook or WebSocket.
5
Step 3: Message pushed to bus
6
Channel wraps the message as an InboundMessage with:
7
  • channel: Platform identifier (“telegram”, “discord”, “slack”)
  • chat_id: Unique chat/channel identifier
  • user_id: User identifier for allowlist checks
  • text: Message content
  • metadata: Platform-specific data (message IDs, timestamps, etc.)
  • 8
    Step 4: Gateway processes message
    9
    Gateway pops the message from the bus, checks session state, and forwards to the agent loop.
    10
    Step 5: Agent generates response
    11
    The AI agent processes the message and generates a response.
    12
    Step 6: Response published
    13
    Gateway publishes an OutboundMessage to the bus with:
    14
  • channel: Target platform
  • chat_id: Destination chat
  • text: Response text (supports Markdown)
  • file_path: Optional file attachment
  • 15
    Step 7: Channel delivers response
    16
    The matching channel receives the outbound message and sends it to the user via the platform’s API.

    Message Types

    InboundMessage

    @dataclass(frozen=True)
    class InboundMessage:
        channel: str      # "telegram", "discord", "slack"
        chat_id: str      # Platform-specific chat identifier
        user_id: str      # User identifier for allowlist
        text: str         # Message content
        metadata: dict    # Platform-specific data
        timestamp: datetime
    

    OutboundMessage

    @dataclass(frozen=True)
    class OutboundMessage:
        channel: str              # Target platform
        chat_id: str              # Destination chat
        text: str                 # Response text (Markdown)
        metadata: dict            # Optional metadata
        reply_to_message_id: str  # Optional reply target
        file_path: str            # Optional file attachment
    
    When file_path is set, channels send the file as an attachment (photo for images, document for other files) with text as the caption.

    User Allowlists

    All channels support optional user allowlists for access control:
    channels:
      telegram:
        enabled: true
        token: "YOUR_BOT_TOKEN"
        allow_from:
          - "123456789"  # Only this user can interact
          - "987654321"
    
    If allow_from is empty or omitted, all users are allowed. Otherwise, only listed user IDs can send messages.

    Message Splitting

    Channels automatically split long responses to fit platform limits:
    • Telegram: 4,096 characters
    • Discord: 2,000 characters
    • Slack: 40,000 characters
    The BaseChannel.split_message() method intelligently splits on newline boundaries when possible, falling back to hard splits only when necessary.

    File Attachments

    All channels support sending files via the send_file() method: Telegram: Automatically detects image extensions (.png, .jpg, .jpeg, .gif, .webp) and sends as photos. Other files sent as documents. Discord: Uses discord.File attachments with optional caption. Slack: Uses files_upload_v2 API (fallback to files_upload for older SDK versions).

    Available Channels

    Telegram

    Full bot with rich commands and media support

    Discord

    Discord bot with command prefix support

    Slack

    Socket Mode bot (no public URL required)

    Next Steps

    Set up Telegram

    Create a Telegram bot and configure it with Grip AI

    Set up Discord

    Configure a Discord bot for your server

    Build docs developers (and LLMs) love