Quickstart

From zero to texting your Claude Code session, on Telegram, in five steps.

What hotline is

hotline is an MCP server that relays a Claude Code session to your messaging apps. Claude replies in short bubbles with a typing indicator, reacts with emoji, edits its own messages to show progress, and offers inline buttons when it wants you to pick one thing. Telegram is the default provider; Signal and Discord run alongside it or on their own.

It speaks Claude Code's experimental two-way channel protocol (claude/channel), which makes it Claude Code specific today. Details and caveats on the protocol page.

Install

go install github.com/1broseidon/hotline@latest   # -> $(go env GOPATH)/bin/hotline

Requires Go 1.26+. No prebuilt binaries yet.

Set up Telegram

  1. Get a bot token from @BotFather.

  2. Drop it in the channel's .env:

    mkdir -p ~/.claude/channels/tele-go
    printf 'TELEGRAM_BOT_TOKEN=123456789:AA…\n' > ~/.claude/channels/tele-go/.env
    chmod 600 ~/.claude/channels/tele-go/.env

    A real TELEGRAM_BOT_TOKEN environment variable wins over the .env file.

  3. Register hotline as an MCP server in the project you want to text with, via .mcp.json:

    {
      "mcpServers": {
        "hotline": { "command": "hotline", "args": ["run"] }
      }
    }
  4. Start Claude Code with the channel flag (channels are experimental and loaded by MCP server name):

    claude --dangerously-load-development-channels server:hotline
  5. DM your bot. The first message from an unknown sender returns a 6-hex pairing code. Approve it from your terminal:

    hotline pair <code>

That's it. Your session is now a Telegram chat. The pairing step is part of the access model; read Access & permissions before you hand the bot's handle to anyone.

The tools Claude gets

ToolWhat it does
replySend bubbles (array of short messages, paced) or text (single message, chunked past 4096 chars). Optional reply_to, files (images inline, others as documents, 50MB each), buttons (up to 12 inline options), format (text, markdownv2, html)
reactSet an emoji reaction (Telegram's fixed whitelist)
edit_messageEdit a message the bot sent, for interim progress. Edits don't push-notify
download_attachmentFetch a non-photo attachment by file_id into the inbox; returns a local path (Telegram's 20MB download cap applies)

Button taps come back as ordinary inbound messages whose content is the tapped label, verbatim. Tap authorization mirrors the inbound gate.

CLI

hotline [run]        # start the MCP server + Telegram poller (default)
hotline pair <code>  # approve a pending pairing code
hotline deny <code>  # reject a pending pairing code
hotline status       # print state-dir / token / access summary

pair, deny, and status take --provider kind[:instance] to select which provider's state they operate on (default: telegram).

Where things live

State lives in ~/.claude/channels/tele-go. The directory keeps its pre-rename name, so existing pairings, transcripts, and inboxes carry over: hotline was formerly tele-go, and TELE_GO_* variables keep working as fallbacks for one release. The full environment variable table is on Multiple providers.

next: Telegram in depth →