Skip to content

URL: https://mkdocs.justinsforge.com/memory/general/reference_telegram_bot_playbook/

Telegram Bot Playbook

Doctrine doc: telegram-bot-playbook.

Helper module: forge/scripts/forge_telegram_format.py.

Callback dispatcher: forge/scripts/forge_telegram_callbacks.py.

What the playbook covers

  • Parse modes (plain default, MarkdownV2 when bold/mono adds value, never HTML).
  • The no-table rule. Telegram does not render markdown tables. Use kv_block (2 cols) or mono_table (3+ cols). Boundary sanitizer auto-folds stray markdown tables to monospace.
  • Expandable blockquotes for content over 15 lines.
  • MarkdownV2 reserved-char escaping via escape_md_v2.
  • Feature catalog: tg_send, edit_or_send, pin_and_track (slot-keyed in forge/data/telegram_pins.json), progress_message (rate-limited self-edits), inline_keyboard, chat_action.
  • The TELEGRAM_FORMATTING_RULES constant gets injected into both forge_telegram_brain.py persona prompts (capture, coordinator).
  • Build order for adding a new feature: playbook -> helper -> auto pickup.

Send-boundary defense-in-depth

Every bot's send() now routes through sanitize_for_telegram, which folds in the canonical forge_text_sanitize.strip_em_dashes and additionally detects + converts markdown-table line runs to mono_table form. Same pattern as the em-dash sanitizer: prompt rules tell Sonnet what to do, the boundary enforces it on the way out.

Migrated send paths (5):

  • forge_telegram_capture_bot.py
  • forge_telegram_coordinator_bot.py
  • forge_telegram_notify_bot.py
  • forge_telegram_remote_bridge.py (send and edit)
  • forge_telegram_inbox_webhook.py (Shortcut echo)

Plus the proactive sender: forge_coordinator_proactive.send_coordinator now sanitizes body via sanitize_for_telegram (was strip_em_dashes only).

Callback queries

Each bot's polling loop dispatches callback_query updates to forge_telegram_callbacks.dispatch. Skills register prefixes via register("snooze", handler). Pre-registered: noop: (silent) and ack: (popup echoes payload).

Morning report proof-of-concept

forge_morning_report.py now uses progress_message while assembling, sends the final report via tg_send with an inline-keyboard [Snooze 1h] [Mark done] [Full plan] (all wired to noop: for now), and pins via pin_and_track(slot="daily"). Falls back to legacy send_coordinator if env loading fails so cron stays safe.

[Claude Code]