Channels (beta)
Connect external messaging platforms to your Letta Code agents
Channels let your Letta Code agent receive and respond to messages from external platforms like Telegram and Slack. Messages from the platform flow into the agent’s conversation, and the agent replies using the MessageChannel tool.
Channels function as an additional communication option. You can combine channels with the Letta Code app, the CLI, or chat.letta.com — all connected to the same agent and memory.
Getting started
Section titled “Getting started”You can set up channels via the Letta Code app or the CLI. The app provides a visual setup flow in the “Channels” sidebar tab. The CLI flow is documented below.
Telegram (CLI)
Section titled “Telegram (CLI)”1. Create a bot
Section titled “1. Create a bot”Create a Telegram bot via @BotFather and copy your bot token.
2. Configure
Section titled “2. Configure”letta channels configure telegramThe interactive wizard will:
- Auto-install the Telegram runtime dependencies
- Ask for your bot token (validates it against the Telegram API)
- Let you choose a DM policy (
pairing,allowlist, oropen)
Config is written to ~/.letta/channels/telegram/accounts.json.
3. Start the server with channels enabled
Section titled “3. Start the server with channels enabled”letta server --channels telegramYou’ll see [Telegram] Bot started as @your_bot in the output. The bot begins long-polling for messages immediately.
4. Pair a Telegram chat to an agent
Section titled “4. Pair a Telegram chat to an agent”Send any message to your bot from Telegram. With the default pairing policy, the bot replies with a pairing code and instructions to complete setup in Letta Code.
You can complete the pairing from the CLI:
letta channels pair \ --channel telegram \ --code B5ZR5H \ --agent <your-agent-id> \ --conversation <your-conversation-id>The --agent flag defaults to the LETTA_AGENT_ID env var and --conversation defaults to LETTA_CONVERSATION_ID (or "default").
You can also pair from within an active Letta Code session (app, CLI, or desktop):
/channels telegram pair B5ZR5H5. Chat
Section titled “5. Chat”Messages from Telegram now flow into the agent’s conversation. The agent responds using the MessageChannel tool, which converts markdown to Telegram-safe HTML formatting (bold, italic, code, links, etc.).
Slack (CLI)
Section titled “Slack (CLI)”1. Create a Slack app
Section titled “1. Create a Slack app”- Go to api.slack.com/apps and click Create New App
- Choose From a manifest, select your workspace, paste the JSON manifest below, and create the app
- Generate an app-level token: go to Settings > Basic Information, scroll to App-Level Tokens, click Generate Token and Scopes, give it a name (e.g. “main”), add the
connections:writescope, and click Generate. Copy the token (xapp-...). - Install the app: go to Settings > Install App, click Install to Workspace, authorize, then copy the Bot User OAuth Token (
xoxb-...)
Slack app manifest
{ "display_information": { "name": "Letta Code", "description": "Slack connector for Letta Code" }, "features": { "bot_user": { "display_name": "Letta Code Slack Bot", "always_online": true }, "app_home": { "messages_tab_enabled": true, "messages_tab_read_only_enabled": false } }, "oauth_config": { "scopes": { "bot": [ "app_mentions:read", "channels:history", "chat:write", "files:read", "files:write", "groups:history", "im:history", "reactions:read", "reactions:write", "users:read" ] } }, "settings": { "org_deploy_enabled": false, "socket_mode_enabled": true, "is_hosted": false, "token_rotation_enabled": false, "event_subscriptions": { "bot_events": [ "app_mention", "message.channels", "message.groups", "message.im", "reaction_added", "reaction_removed" ] } }}This manifest pre-configures Socket Mode, all required scopes, event subscriptions, and App Home messaging.
2. Configure
Section titled “2. Configure”letta channels configure slackThe wizard asks for both tokens and your DM policy (open or allowlist).
If you choose allowlist, you’ll need Slack user IDs. To find a user ID: open the user’s profile in Slack, click the three-dot menu (⋯), and select Copy member ID. IDs start with U or W.
3. Start the server
Section titled “3. Start the server”letta server --channels slack4. Bind the Slack app to an agent
Section titled “4. Bind the Slack app to an agent”Unlike Telegram (which uses pairing codes), Slack requires binding the app to an agent before any messages will route:
letta channels bind --channel slack --agent <your-agent-id>The --agent flag defaults to the LETTA_AGENT_ID env var. If you have multiple Slack accounts configured, pass --account-id to specify which one.
You can also bind from the Letta Code app under Channels > Slack.
5. Chat
Section titled “5. Chat”Once bound, DM the app or @mention it in a channel to start chatting.
Slack routing behavior:
- @mentions in channels: Each mention creates a new conversation for the agent. The agent replies in-thread, and all subsequent messages in that thread are forwarded without requiring mentions.
- DMs: Each DM chat gets a 1:1 mapping to a conversation. Routes are auto-created on first message.
- DM policy: Slack defaults to
open(recommended).allowlistis also supported for DMs. Thepairingpolicy does not apply to Slack.
Architecture
Section titled “Architecture”flowchart LR
subgraph Platform["Messaging platform"]
TG["Telegram / Slack"]
end
subgraph Local["Your machine (letta server)"]
Adapter["Channel adapter<br/>(long-polling / Socket Mode)"]
Registry["Channel registry"]
Queue["Message queue"]
Agent["Agent"]
Tool["MessageChannel tool"]
end
TG -->|"Inbound message"| Adapter
Adapter --> Registry
Registry -->|"XML-wrapped message"| Queue
Queue --> Agent
Agent -->|"Tool call"| Tool
Tool -->|"Outbound reply"| TG
- The adapter receives messages from the platform (Telegram uses long-polling, Slack uses Socket Mode)
- The registry checks DM policy (pairing/allowlist/open), looks up the route, and formats the message as XML
- The message enters the agent’s queue as a
channelsource item - The agent processes it and calls the MessageChannel tool to reply
- The tool converts markdown to platform-safe formatting and sends through the adapter
DM policies
Section titled “DM policies”Each channel has a DM policy that controls who can message the bot:
| Policy | Behavior |
|---|---|
pairing (default for Telegram) | Unknown users receive a one-time pairing code. An operator must approve the code to bind the chat to an agent. |
allowlist | Only pre-configured user IDs can message. Others are rejected. |
open (default for Slack) | Anyone can message. For Telegram, requires a route to exist. For Slack, routes are auto-created on first DM or @mention. |
Routing
Section titled “Routing”Routes bind a platform chat ID to an agent + conversation pair. They’re stored in ~/.letta/channels/<channel>/routing.yaml.
Routes are created automatically when pairing completes, or manually via the CLI:
# Add a route manuallyletta channels route add \ --channel telegram \ --chat-id 123456789 \ --agent agent-abc123 \ --conversation default
# List all routesletta channels route list
# List routes for a specific channelletta channels route list --channel telegram
# Remove a routeletta channels route remove --channel telegram --chat-id 123456789CLI reference
Section titled “CLI reference”| Command | Description |
|---|---|
letta channels install <channel> | Install channel runtime dependencies (optional — configure does this automatically) |
letta channels configure <channel> | Interactive setup wizard (installs runtime deps if needed) |
letta channels status | Show config, routing, and pairing state (JSON) |
letta channels route list [--channel <ch>] | Show routing table |
letta channels route add [options] | Add a route binding a chat to an agent |
letta channels route remove [options] | Remove a route |
letta channels bind [options] | Bind a channel account to an agent (required for Slack) |
letta channels pair [options] | Complete a pairing code and bind to agent (Telegram) |
Common flags
Section titled “Common flags”| Flag | Commands | Description |
|---|---|---|
--channel <name> | route, pair | Channel name (telegram, slack) |
--account-id <id> | route add/remove, pair | Account ID (required when multiple accounts exist for a channel, auto-resolved when only one exists) |
--chat-id <id> | route add/remove | Platform chat/conversation ID |
--agent <id> | route add, pair | Agent ID (defaults to LETTA_AGENT_ID) |
--conversation <id> | route add, pair | Conversation ID (defaults to LETTA_CONVERSATION_ID or "default") |
--code <code> | pair | Pairing code from the bot |
Headless deployment
Section titled “Headless deployment”For server/Docker deployments without interactive setup:
- Pre-write the config files to
~/.letta/channels/<channel>/ - Start with the
--install-channel-runtimesflag to auto-install dependencies:
letta server --channels telegram --install-channel-runtimesOr install runtimes separately:
letta channels install telegramEnvironment variables
Section titled “Environment variables”| Variable | Description |
|---|---|
LETTA_AGENT_ID | Default agent ID for pair and route add commands |
LETTA_CONVERSATION_ID | Default conversation ID (fallback: "default") |
LETTA_API_KEY | API key for letta server authentication |
State files
Section titled “State files”| File | Description |
|---|---|
~/.letta/channels/<ch>/accounts.json | Channel account configuration (tokens, DM policy, account metadata) |
~/.letta/channels/<ch>/routing.yaml | Route table (chat ID to agent/conversation binding) |
~/.letta/channels/<ch>/pairing.yaml | Pending and approved pairings |
Connection lifecycle
Section titled “Connection lifecycle”Channels integrate with the letta server WebSocket connection:
- On connect: channel adapters register their message handler and flush any buffered messages
- On disconnect: adapters pause delivery but keep polling/listening. Messages buffer until reconnection.
- On shutdown: adapters stop cleanly
This means if letta server briefly loses its WebSocket connection, no Telegram/Slack messages are dropped — they buffer and deliver when the connection restores.
You can also configure channels on remote devices — simply swap the selected device in the channels menu of the Letta Code app.