| Telegram Bot skill for sending and editing Telegram messages via Bot API. (2) Reply to a specific Telegram message with reply_to_message_id, (3) Edit an existing Telegram message, or (4) Push proactive Telegram notifications. Prefer rich formatted messages (headings, lists, tables, blockquotes, math, collapsible details, captioned media) over plain markdown whenever the content is more than one short paragraph.
npx skills add https://github.com/bubbuild/bub --skill telegram
Agent-facing execution guide for Telegram outbound communication.
Env vars:
BUB_TELEGRAM_TOKEN=${config.telegram.token}Collect these before execution:
chat_id (required)message_id (required for edit or reply)reply_to_message_id (required when you need a threaded reply)For any message that benefits from structured formatting — headings, bullet/numbered lists, tables, blockquotes, collapsible <details>, captioned media, math blocks, code blocks with language hints, or mixed media — use the dedicated telegram_rich.py script with rich-html-style markup. This is the first-choice path; fall back to plain markdown (telegram_send.py) only for short single-paragraph replies.
The Rich Message API uses sendRichMessage and editMessageText with a rich_message payload. Exactly one of html or markdown must be supplied. Supported HTML tags include <b>, <i>, <u>, <s>, <tg-spoiler>, <code>, <pre>, <mark>, <sub>, <sup>, <h1>-<h6>, <p>, <ul>/<ol>/<li>, <blockquote>, <aside>, <details>/<summary>, <table>, <figure>/<figcaption>, <img>/<video>/<audio>, <tg-collage>, <tg-slideshow>, <tg-map>, <tg-math>, <tg-math-block>, <tg-reference>, <tg-emoji>, <tg-time>. Full reference: https://core.telegram.org/bots/api#rich-html-style
# Send rich message (HTML)
uv run ./scripts/telegram_rich.py \
--chat-id <CHAT_ID> \
--html "<h2>Title</h2><p>Body with <b>bold</b> and <code>code</code>.</p>"
# Send rich message (HTML from heredoc via file)
uv run ./scripts/telegram_rich.py \
--chat-id <CHAT_ID> \
--html-file /tmp/payload.html \
--reply-to <MESSAGE_ID>
# Send rich message (Markdown instead of HTML)
uv run ./scripts/telegram_rich.py \
--chat-id <CHAT_ID> \
--markdown "## Title\n\n- item one\n- item two"
# Edit an existing message to become a rich message
uv run ./scripts/telegram_rich.py \
--chat-id <CHAT_ID> \
--edit <MESSAGE_ID> \
--html "<p>Updated content.</p>"
For multi-line rich HTML, prefer --html-file over passing the payload on the command line to avoid shell escaping pitfalls. The script reads the file as UTF-8 and strips a single trailing newline.
message_id is known, send a reply message (--reply-to).sender_is_bot=true), do not use reply mode, but send a normal message and prefix content with @<sender_username> (or the provided source username). If the user doesn't have a username, use --source-user-id to mention via tg://user?id= link.--message - (or --text -). NEVER embed message text directly in shell arguments — special characters like ', ", $, ! will be mangled or cause syntax errors.telegram_rich.py (rich-html-style) over telegram_send.py for anything beyond a single short paragraph. See the "Rich Messages" section above.In Telegram groups, communicate with another bot using only these patterns:
message_id is available./command@OtherBot when you need to invoke that bot intentionally.When this skill is in scope, prefer proactive and timely Telegram updates:
Recommended pattern:
When the inbound Telegram message is voice:
When an inbound Telegram message warrants acknowledgment but does not merit a full reply, use a Telegram reaction as the response.
But when any explanation or details are needed, use a normal reply instead.
Paths are relative to this skill directory.
# Send message (ALWAYS use heredoc stdin, never inline text in arguments)
cat << 'EOF' | uv run ${SKILL_DIR}/scripts/telegram_send.py --chat-id <CHAT_ID> --token "$BUB_TELEGRAM_TOKEN" --message -
Your message content here.
Special characters are safe: $100, "quotes", 'apostrophes', !exclamation
EOF
# Reply to a specific message
cat << 'EOF' | uv run ${SKILL_DIR}/scripts/telegram_send.py --chat-id <CHAT_ID> --token "$BUB_TELEGRAM_TOKEN" --reply-to <MESSAGE_ID> --message -
Reply content here.
EOF
# Source message sender is bot: no direct reply, use @username style
cat << 'EOF' | uv run ${SKILL_DIR}/scripts/telegram_send.py --chat-id <CHAT_ID> --token "$BUB_TELEGRAM_TOKEN" --source-is-bot --source-username <USERNAME> --message -
Message to a bot using @username mention.
EOF
# Source message sender is bot without username: use tg://user?id= link
cat << 'EOF' | uv run ${SKILL_DIR}/scripts/telegram_send.py --chat-id <CHAT_ID> --token "$BUB_TELEGRAM_TOKEN" --source-is-bot --source-user-id <USER_ID> --source-display-name "Display Name" --message -
Message to a user/bot using tg://user?id= mention.
EOF
# Edit an existing message
cat << 'EOF' | uv run ${SKILL_DIR}/scripts/telegram_edit.py --chat-id <CHAT_ID> --token "$BUB_TELEGRAM_TOKEN" --message-id <MESSAGE_ID> --text -
Updated content here.
EOF
When sending message to a bot, either use --reply-to argument or pass --source-is-bot with --source-username otherwise the bot will not receive the message.
For other actions that not covered by these scripts, use curl to call Telegram Bot API directly with the provided token.
telegram_rich.py (preferred for structured messages)--chat-id, -c: required--html: rich message content as HTML--html-file: read rich message HTML from a file (preferred for multi-line payloads)--markdown: rich message content as Markdown--markdown-file: read rich message Markdown from a file--rtl: render right-to-left--skip-entity-detection: skip URL/email/mention auto-detection--reply-to, -r: optional message ID to reply to--disable-notification: send silently--edit MESSAGE_ID: edit an existing message instead of sending--token, -t: optional (normally not needed)telegram_send.py--chat-id, -c: required, supports comma-separated ids--message, -m: required (use - to read from stdin)--reply-to, -r: optional--token, -t: optional (normally not needed)--source-is-bot: optional flag, disables reply mode and adds mention prefix--source-username: optional, uses @username style mention when set--source-user-id: optional, uses tg://user?id= link mention when username is not available--source-display-name: optional, display name for user ID mention (defaults to "User")telegram_edit.py--chat-id, -c: required--message-id, -m: required--text, -t: required (use - to read from stdin)--token: optional (normally not needed)In Telegram groups, communicate with another bot using only these patterns:
message_id is available./command@OtherBot when you need to invoke that bot intentionally.Take bubbuild/telegram from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.