| name | add-telegram |
| description | Add Telegram as a channel. Can replace WhatsApp entirely or run alongside it. Also configurable as a control-only channel (triggers actions) or passive channel (receives notifications only). |
Add Telegram Channel
This skill adds Telegram support to NanoClaw using the skills engine for deterministic code changes, then walks through interactive setup.
Phase 1: Pre-flight
Check if already applied
Read .nanoclaw/state.yaml. If telegram is in applied_skills, skip to Phase 3 (Setup). The code changes are already in place.
Ask the user
-
Mode: Replace WhatsApp or add alongside it?
- Replace → will set
TELEGRAM_ONLY=true
- Alongside → both channels active (default)
-
Do they already have a bot token? If yes, collect it now. If no, we'll create one in Phase 3.
Phase 2: Apply Code Changes
Run the skills engine to apply this skill's code package. The package files are in this directory alongside this SKILL.md.
Initialize skills system (if needed)
If .nanoclaw/ directory doesn't exist yet:
npx tsx scripts/apply-skill.ts --init
Or call initSkillsSystem() from skills-engine/migrate.ts.
Apply the skill
npx tsx scripts/apply-skill.ts .claude/skills/add-telegram
This deterministically:
- Adds
src/channels/telegram.ts (TelegramChannel class implementing Channel interface)
- Adds
src/channels/telegram.test.ts (46 unit tests)
- Three-way merges Telegram support into
src/index.ts (multi-channel support, findChannel routing)
- Three-way merges Telegram config into
src/config.ts (TELEGRAM_BOT_TOKEN, TELEGRAM_ONLY exports)
- Three-way merges updated routing tests into
src/routing.test.ts
- Installs the
grammy npm dependency
- Updates
.env.example with TELEGRAM_BOT_TOKEN and TELEGRAM_ONLY
- Records the application in
.nanoclaw/state.yaml
If the apply reports merge conflicts, read the intent files:
modify/src/index.ts.intent.md — what changed and invariants for index.ts
modify/src/config.ts.intent.md — what changed for config.ts
Validate code changes
npm test
npm run build
All tests must pass (including the new telegram tests) and build must be clean before proceeding.
Phase 3: Setup
Create Telegram Bot (if needed)
If the user doesn't have a bot token, tell them:
I need you to create a Telegram bot:
- Open Telegram and search for
@BotFather
- Send
/newbot and follow prompts:
- Bot name: Something friendly (e.g., "Andy Assistant")
- Bot username: Must end with "bot" (e.g., "andy_ai_bot")
- Copy the bot token (looks like
123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11)
Wait for the user to provide the token.
Configure environment
Add to .env:
TELEGRAM_BOT_TOKEN=<their-token>
If they chose to replace WhatsApp:
TELEGRAM_ONLY=true
Sync to container environment:
mkdir -p data/env && cp .env data/env/env
The container reads environment from data/env/env, not .env directly.
Disable Group Privacy (for group chats)
Tell the user:
Important for group chats: By default, Telegram bots only see @mentions and commands in groups. To let the bot see all messages:
- Open Telegram and search for
@BotFather
- Send
/mybots and select your bot
- Go to Bot Settings > Group Privacy > Turn off
This is optional if you only want trigger-based responses via @mentioning the bot.
Build and restart
npm run build
launchctl kickstart -k gui/$(id -u)/com.nanoclaw
Phase 4: Registration
Get Chat ID
Tell the user:
- Open your bot in Telegram (search for its username)
- Send
/chatid — it will reply with the chat ID
- For groups: add the bot to the group first, then send
/chatid in the group
Wait for the user to provide the chat ID (format: tg:123456789 or tg:-1001234567890).
Register the chat
Use the IPC register flow or register directly. The chat ID, name, and folder name are needed.
For a main chat (responds to all messages, uses the main folder):
registerGroup("tg:<chat-id>", {
name: "<chat-name>",
folder: "main",
trigger: `@${ASSISTANT_NAME}`,
added_at: new Date().toISOString(),
requiresTrigger: false,
});
For additional chats (trigger-only):
registerGroup("tg:<chat-id>", {
name: "<chat-name>",
folder: "<folder-name>",
trigger: `@${ASSISTANT_NAME}`,
added_at: new Date().toISOString(),
requiresTrigger: true,
});
Phase 5: Verify
Test the connection
Tell the user:
Send a message to your registered Telegram chat:
- For main chat: Any message works
- For non-main:
@Andy hello or @mention the bot
The bot should respond within a few seconds.
Check logs if needed
tail -f logs/nanoclaw.log
Troubleshooting
Bot not responding
- Check
TELEGRAM_BOT_TOKEN is set in .env AND synced to data/env/env
- Check chat is registered:
sqlite3 store/messages.db "SELECT * FROM registered_groups WHERE jid LIKE 'tg:%'"
- For non-main chats: message must include trigger pattern
- Service is running:
launchctl list | grep nanoclaw
Bot only responds to @mentions in groups
Group Privacy is enabled (default). Fix:
@BotFather > /mybots > select bot > Bot Settings > Group Privacy > Turn off
- Remove and re-add the bot to the group (required for the change to take effect)
Getting chat ID
If /chatid doesn't work:
- Verify token:
curl -s "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/getMe"
- Check bot is started:
tail -f logs/nanoclaw.log
After Setup
Ask the user:
Would you like to add Agent Swarm support? Each subagent appears as a different bot in the Telegram group. If interested, run /add-telegram-swarm.