Skip to main content

Overview

The Telegram channel uses the grammY library to connect via the Telegram Bot API. It’s simpler to set up than WhatsApp (no QR codes) and supports both private chats and groups.

Installation

Run the /add-telegram skill in Claude Code:
/add-telegram
The skill will:
  • Install the Telegram channel code
  • Add required dependencies (grammy)
  • Guide you through bot creation
  • Configure authentication
  • Register your first chat

Creating a Telegram Bot

1

Open BotFather

In Telegram, search for @BotFather and start a chat
2

Create New Bot

Send /newbot and follow the prompts:
  • Bot name: Something friendly (e.g., “Andy Assistant”)
  • Bot username: Must end with “bot” (e.g., “andy_ai_bot”)
3

Copy Token

BotFather will reply with a bot token that looks like:
123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11
Copy this token — you’ll need it for configuration.

Configuration

Add the bot token to .env:
TELEGRAM_BOT_TOKEN=123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11
Then sync to container environment:
mkdir -p data/env && cp .env data/env/env
The channel auto-enables when TELEGRAM_BOT_TOKEN is set. No additional configuration needed.

Group Privacy Settings

By default, Telegram bots only see @mentions and commands in groups. To let the bot see all messages, you must disable Group Privacy.
1

Open BotFather

Search for @BotFather in Telegram
2

Select Bot

Send /mybots and select your bot
3

Disable Privacy

Go to Bot SettingsGroup PrivacyTurn off
4

Re-add to Groups

Remove and re-add the bot to any existing groups for the change to take effect
Skip this if you only want trigger-based responses (users must @mention the bot).

Chat Registration

Getting the Chat ID

The bot has a built-in /chatid command to find chat IDs:
1

Start Bot

Build and restart NanoClaw:
npm run build
launchctl kickstart -k gui/$(id -u)/com.nanoclaw  # macOS
systemctl --user restart nanoclaw  # Linux
2

Get Chat ID

  • For private chats: Search for your bot’s username in Telegram and send /chatid
  • For groups: Add the bot to the group, then send /chatid in the group
The bot will reply with:
Chat ID: tg:123456789
Name: John Doe
Type: private

Registering a Main Chat

Main chats respond to all messages (no trigger required):
registerGroup("tg:123456789", {
  name: "Telegram Main",
  folder: "telegram_main",
  trigger: "@Andy",
  added_at: new Date().toISOString(),
  requiresTrigger: false,
  isMain: true,
});

Registering Additional Chats

Additional chats require the trigger pattern:
registerGroup("tg:-1001234567890", {
  name: "Dev Team",
  folder: "telegram_dev-team",
  trigger: "@Andy",
  added_at: new Date().toISOString(),
  requiresTrigger: true,
});

How It Works

Connection

  1. Telegram channel reads TELEGRAM_BOT_TOKEN from environment
  2. Creates grammY bot instance
  3. Sets up message handlers and commands
  4. Starts long polling to receive updates

Message Handling

The channel automatically translates Telegram-specific features: @Mention Translation Telegram @mentions (like @andy_ai_bot) are automatically converted to NanoClaw’s trigger format:
Input:  "@andy_ai_bot what's the weather?"
Stored: "@Andy what's the weather?"
This ensures the trigger pattern matches correctly. Chat Type Detection
  • Private chats: Sender name used as chat name
  • Groups: Group title used as chat name
  • Supergroups: Treated same as groups

Built-in Commands

CommandPurpose
/chatidGet the chat ID for registration
/pingCheck if the bot is online

Troubleshooting

Bot Not Responding

1

Check Token

Verify TELEGRAM_BOT_TOKEN is set in .env AND synced to data/env/env:
grep TELEGRAM_BOT_TOKEN .env
grep TELEGRAM_BOT_TOKEN data/env/env
2

Check Registration

sqlite3 store/messages.db "SELECT * FROM registered_groups WHERE jid LIKE 'tg:%'"
3

Check Trigger

For non-main chats, message must include trigger pattern (e.g., @Andy hello)
4

Check Service

# macOS
launchctl list | grep nanoclaw

# Linux
systemctl --user status nanoclaw

Bot Only Responds to @Mentions in Groups

This is the default behavior when Group Privacy is enabled. To fix:
  1. @BotFather/mybots → select bot → Bot SettingsGroup PrivacyTurn off
  2. Remove and re-add the bot to the group

/chatid Command Not Working

1

Verify Token

Test the token directly:
curl -s "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/getMe"
2

Check Logs

tail -f logs/nanoclaw.log | grep -i telegram

Invalid Token Error

The token format should be <number>:<alphanumeric>. If you get “invalid token”:
  1. Go back to @BotFather
  2. Send /mybots → select your bot → API Token
  3. Copy the full token (including the colon)
  4. Update .env and sync: mkdir -p data/env && cp .env data/env/env
  5. Restart: npm run build && launchctl kickstart -k gui/$(id -u)/com.nanoclaw

Implementation Details

Dependencies

  • grammy - Modern Telegram Bot API framework

JID Format

  • Private chats: tg:<user-id> (e.g., tg:123456789)
  • Groups: tg:<group-id> (e.g., tg:-1001234567890)
Note: Group IDs are negative numbers, user IDs are positive.

Self-Registration Code

registerChannel('telegram', (opts: ChannelOpts) => {
  const env = readEnvFile(['TELEGRAM_BOT_TOKEN']);
  if (!env.TELEGRAM_BOT_TOKEN) return null;
  return new TelegramChannel(env.TELEGRAM_BOT_TOKEN, opts);
});
The channel only activates if TELEGRAM_BOT_TOKEN is set.

Message Processing

this.bot.on('message:text', async (ctx) => {
  // Skip commands
  if (ctx.message.text.startsWith('/')) return;
  
  const chatJid = `tg:${ctx.chat.id}`;
  let content = ctx.message.text;
  
  // Translate @bot_username to @AssistantName
  if (isBotMentioned && !TRIGGER_PATTERN.test(content)) {
    content = `@${ASSISTANT_NAME} ${content}`;
  }
  
  // Store metadata and deliver message
  this.opts.onChatMetadata(chatJid, timestamp, chatName, 'telegram', isGroup);
  this.opts.onMessage(chatJid, content, timestamp, sender, senderName, msgId);
});

Next Steps

Add Slack

Add Slack as another channel

Channel Overview

Learn about the channel system

Build docs developers (and LLMs) love