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) ormono_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 inforge/data/telegram_pins.json),progress_message(rate-limited self-edits),inline_keyboard,chat_action. - The
TELEGRAM_FORMATTING_RULESconstant gets injected into bothforge_telegram_brain.pypersona 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.pyforge_telegram_coordinator_bot.pyforge_telegram_notify_bot.pyforge_telegram_remote_bridge.py(sendandedit)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]