Files
gavrielc 51788de3b9 Skills engine v0.1 + multi-channel infrastructure (#307)
* refactor: multi-channel infrastructure with explicit channel/is_group tracking

- Add channels[] array and findChannel() routing in index.ts, replacing
  hardcoded whatsapp.* calls with channel-agnostic callbacks
- Add channel TEXT and is_group INTEGER columns to chats table with
  COALESCE upsert to protect existing values from null overwrites
- is_group defaults to 0 (safe: unknown chats excluded from groups)
- WhatsApp passes explicit channel='whatsapp' and isGroup to onChatMetadata
- getAvailableGroups filters on is_group instead of JID pattern matching
- findChannel logs warnings instead of silently dropping unroutable JIDs
- Migration backfills channel/is_group from JID patterns for existing DBs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: skills engine v0.1 — deterministic skill packages with rerere resolution

Three-way merge engine for applying skill packages on top of a core
codebase. Skills declare which files they add/modify, and the engine
uses git merge-file for conflict detection with git rerere for
automatic resolution of previously-seen conflicts.

Key components:
- apply: three-way merge with backup/rollback safety net
- replay: clean-slate replay for uninstall and rebase
- update: core version updates with deletion detection
- rebase: bake applied skills into base (one-way)
- manifest: validation with path traversal protection
- resolution-cache: pre-computed rerere resolutions
- structured: npm deps, env vars, docker-compose merging
- CI: per-skill test matrix with conflict detection

151 unit tests covering merge, rerere, backup, replay, uninstall,
update, rebase, structured ops, and edge cases.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: add Discord and Telegram skill packages

Skill packages for adding Discord and Telegram channels to NanoClaw.
Each package includes:
- Channel implementation (add/src/channels/)
- Three-way merge targets for index.ts, config.ts, routing.test.ts
- Intent docs explaining merge invariants
- Standalone integration tests
- manifest.yaml with dependency/conflict declarations

Applied via: npx tsx scripts/apply-skill.ts .claude/skills/add-discord
These are inert until applied — no runtime impact.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* remove unused docs (skills-system-status, implementation-guide)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 01:55:00 +02:00

5.7 KiB

name, description
name description
add-telegram 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

  1. Mode: Replace WhatsApp or add alongside it?

    • Replace → will set TELEGRAM_ONLY=true
    • Alongside → both channels active (default)
  2. 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:

  1. Open Telegram and search for @BotFather
  2. Send /newbot and follow prompts:
    • Bot name: Something friendly (e.g., "Andy Assistant")
    • Bot username: Must end with "bot" (e.g., "andy_ai_bot")
  3. 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:

  1. Open Telegram and search for @BotFather
  2. Send /mybots and select your bot
  3. 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:

  1. Open your bot in Telegram (search for its username)
  2. Send /chatid — it will reply with the chat ID
  3. 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

  1. Check TELEGRAM_BOT_TOKEN is set in .env AND synced to data/env/env
  2. Check chat is registered: sqlite3 store/messages.db "SELECT * FROM registered_groups WHERE jid LIKE 'tg:%'"
  3. For non-main chats: message must include trigger pattern
  4. Service is running: launchctl list | grep nanoclaw

Bot only responds to @mentions in groups

Group Privacy is enabled (default). Fix:

  1. @BotFather > /mybots > select bot > Bot Settings > Group Privacy > Turn off
  2. 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.