Telegram Compose
Format and deliver rich, scannable Telegram messages via direct API with HTML formatting.
How This Skill Gets Used
This skill is auto-invoked by the main session agent. No other skills need to know about it.
Decision Rule (for the main session agent)
Before sending a message to Telegram, check:
- - Short reply (<3 lines, no structure): Send directly via OpenClaw
message tool. Done. - Substantive content (>3 lines, or has lists/stats/sections/reports): Spawn this skill as a sub-agent.
Spawning the sub-agent
The main session agent calls sessions_spawn with:
CODEBLOCK0
Task template:
CODEBLOCK1
IMPORTANT: The caller MUST specify which bot account to use. The sub-agent must NOT auto-select or iterate accounts.
CRITICAL: The sub-agent announcement routes back to the main session, NOT to Telegram. So the main session should reply NO_REPLY after spawning to avoid double-messaging. The sub-agent's curl call is what delivers to Telegram.
What the sub-agent receives
- 1. Skill path — so it can read the formatting rules
- Bot account name — which Telegram bot account to use (must be specified, never auto-selected)
- Chat ID — where to send
- Thread ID — topic thread if applicable
- Raw content — the unformatted text/data to turn into a rich message
Credentials
Bot token: Stored in the OpenClaw config file under channels.telegram.accounts.<name>.botToken.
The account name is always provided by the caller. Never auto-select or iterate accounts.
CODEBLOCK2
Sending
CODEBLOCK3
Formatting Rules
HTML Tags
CODEBLOCK4
Escaping
Escape these characters in text content only (not in your HTML tags):
- -
& → & (do this FIRST to avoid double-escaping) - INLINECODE6 → INLINECODE7
- INLINECODE8 → INLINECODE9
Common gotcha: content containing & (e.g., "R&D", "Q&A") will break HTML parsing if not escaped.
Structure Pattern
CODEBLOCK5
Style Rules
- 1. Faux headings:
EMOJI <b>CAPS TITLE</b> with blank line after - Emojis: 1-3 per message as visual anchors, not decoration
- Whitespace: Blank lines between sections
- Long content: Use INLINECODE12
- Links: Own line, with arrow: INLINECODE13
Examples
Status update:
CODEBLOCK6
Alert:
CODEBLOCK7
List:
✅ <b>PRIORITIES</b>
• <s>Review PR #234</s> — done
• <b>Finish docs</b> — in progress
• Deploy staging
<i>2 of 3 complete</i>
Mobile-Friendly Data Display
Never use <pre> for stats, summaries, or visual layouts. <pre> uses monospace font and wraps badly on mobile, breaking alignment and tree characters. Reserve <pre> for actual code/commands only.
For structured data, use emoji + bold + separators:
CODEBLOCK9
Other patterns:
Record cards:
CODEBLOCK10
Bullet lists:
• <b>hzl-cli:</b> 1.12.0
• <b>skill:</b> 1.0.6
Limits and Splitting
- - Message max: 4,096 characters
- Caption max: 1,024 characters
If formatted message exceeds 4,096 chars:
- 1. Split at section boundaries (blank lines between
<b>HEADING</b> blocks) - Each chunk must be valid HTML (don't split inside a tag)
- Send chunks sequentially with a 1-second delay between them
- First chunk gets the full heading; subsequent chunks get a continuation indicator: INLINECODE18
Error Handling
If Telegram API returns an error:
| Error | Action |
|---|
| INLINECODE19 | HTML is malformed. Strip all HTML tags and resend as plain text. |
| INLINECODE20 |
Split per the rules above and retry. |
|
Bad Request: message thread not found | Retry without
message_thread_id (sends to General). |
|
Too Many Requests: retry after X | Wait X seconds, then retry once. |
| Any other error | Report the error back; don't retry. |
Fallback rule: If HTML formatting fails twice, send as plain text rather than not sending at all. Delivery matters more than formatting.
Sub-Agent Execution Checklist
When running as a sub-agent, follow this sequence:
- 1. Parse the task — extract Bot account name, Chat ID, Thread ID (if any), skill path, and raw content
- Read this SKILL.md — load the formatting rules
- Format the content — apply HTML tags, structure pattern, style rules, mobile-friendly data display
- Escape special chars —
& then < then > in text content only (not in your HTML tags) - Check length — if >4,096 chars, split at section boundaries
- Get bot token — auto-detect config path, extract token for the specified account (error if not found)
- Send via curl — use the appropriate template (with/without thread ID)
- Check response — parse curl output for INLINECODE27
- Handle errors — follow the error handling table above
- Report back — reply with message_id on success, or error details on failure
Telegram Compose
通过直接 API 和 HTML 格式化,生成并发送丰富、易读的 Telegram 消息。
如何使用该技能
该技能由主会话代理自动调用。 其他技能无需了解它。
决策规则(供主会话代理使用)
在向 Telegram 发送消息之前,请检查:
- - 简短回复(<3 行,无结构): 直接通过 OpenClaw message 工具发送。完成。
- 实质性内容(>3 行,或包含列表/统计/章节/报告): 将该技能作为子代理生成。
生成子代理
主会话代理使用以下参数调用 sessions_spawn:
sessions_spawn(
model: claude-haiku-4-5,
task: <任务内容 — 见下方模板>
)
任务模板:
阅读 {baseDir}/SKILL.md 中的 telegram-compose 技能以了解格式化规则,然后将此内容格式化并发送到 Telegram。
机器人账号:(例如 main — 必须与 channels.telegram.accounts 中的键匹配)
聊天 ID:
线程 ID:(如果不是论坛/话题聊天,则省略此行)
要格式化的内容:
<原始内容在此>
发送后,成功则回复 message_id,失败则回复错误信息。回复中不要包含已格式化的消息 — 它已发送到 Telegram。
重要提示: 调用者必须指定使用哪个机器人账号。子代理不得自动选择或遍历账号。
关键提示: 子代理的公告会路由回主会话,而不是 Telegram。因此,主会话在生成子代理后应回复 NO_REPLY,以避免重复发送消息。子代理的 curl 调用才是实际发送到 Telegram 的操作。
子代理接收的内容
- 1. 技能路径 — 以便读取格式化规则
- 机器人账号名称 — 要使用的 Telegram 机器人账号(必须指定,不得自动选择)
- 聊天 ID — 发送目标
- 线程 ID — 适用的话题线程
- 原始内容 — 要转换为丰富消息的未格式化文本/数据
凭据
机器人令牌: 存储在 OpenClaw 配置文件的 channels.telegram.accounts..botToken 下。
账号名称始终由调用者提供。 不得自动选择或遍历账号。
bash
自动检测配置路径
CONFIG=$([ -f ~/.openclaw/openclaw.json ] && echo ~/.openclaw/openclaw.json || echo ~/.openclaw/clawdbot.json)
ACCOUNT 由调用者提供(例如 main)
在提取令牌前验证账号是否存在
ACCOUNT=
accountname>
BOT_TOKEN=$(jq -r .channels.telegram.accounts.$ACCOUNT.botToken $CONFIG)
if [ $BOTTOKEN = null ] || [ -z $BOTTOKEN ]; then
echo 错误:配置中未找到账号 $ACCOUNT 或没有 botToken
exit 1
fi
发送
bash
CONFIG=$([ -f ~/.openclaw/openclaw.json ] && echo ~/.openclaw/openclaw.json || echo ~/.openclaw/clawdbot.json)
ACCOUNT 由调用者提供 — 不得自动选择
BOT_TOKEN=$(jq -r .channels.telegram.accounts.$ACCOUNT.botToken $CONFIG)
无话题线程
curl -s -X POST https://api.telegram.org/bot${BOT_TOKEN}/sendMessage \
-H Content-Type: application/json \
-d $(jq -n \
--arg chat $CHAT_ID \
--arg text $MESSAGE \
{
chat_id: $chat,
text: $text,
parse_mode: HTML,
linkpreviewoptions: { is_disabled: true }
})
有话题线程
curl -s -X POST https://api.telegram.org/bot${BOT_TOKEN}/sendMessage \
-H Content-Type: application/json \
-d $(jq -n \
--arg chat $CHAT_ID \
--arg text $MESSAGE \
--argjson thread $THREAD_ID \
{
chat_id: $chat,
text: $text,
parse_mode: HTML,
messagethreadid: $thread,
linkpreviewoptions: { is_disabled: true }
})
格式化规则
HTML 标签
粗体 斜体 下划线 删除线
等宽字体
代码块
点击前隐藏
引用
默认折叠
链接
通过 ID 提及
转义
仅在文本内容中(不在 HTML 标签中)转义以下字符:
- - & → &(先执行此操作以避免双重转义)
- < → <
- > → >
常见陷阱:包含 & 的内容(例如 R&D、Q&A)如果未转义,将破坏 HTML 解析。
结构模式
EMOJI 大写标题
标签: 值
标签: 值
章节
• 项目符号
• 另一个项目
关键引用或摘要
详情
此处为隐藏内容...
长内容放在可展开块中。
操作链接 →
样式规则
- 1. 伪标题: EMOJI 大写标题,后面跟空行
- 表情符号: 每条消息 1-3 个,作为视觉锚点,而非装饰
- 空白: 章节之间留空行
- 长内容: 使用
- 链接: 单独一行,带箭头:链接文本 →
示例
状态更新:
📋 任务完成
任务: 部署 v2.3
状态: ✅ 完成
耗时: 12 分钟
所有健康检查通过。
警报:
⚠️ 需要关注
问题: API 速率限制达到 90%
操作: 检查使用情况
查看仪表盘 →
列表:
✅ 优先级
• 审查 PR #234 — 已完成
• 完成文档 — 进行中
• 部署暂存环境
已完成 2/3
移动端友好数据展示
切勿使用 显示统计、摘要或视觉布局。
使用等宽字体,在移动端换行效果差,会破坏对齐和树形字符。仅将 用于实际代码/命令。
对于结构化数据,使用表情符号 + 粗体 + 分隔符:
❌ 不好(移动端换行):
├─ 🟠 Reddit 32 个线程 │ 1,658 分
└─ 🌐 网页 8 页
✅ 好(自然流动):
🟠 Reddit: 32 个线程 · 1,658 分 · 625 条评论
🔵 X: 22 条帖子 · 10,695 个赞 · 1,137 次转发
🌐 网页: 8 页(补充)
🗣️ 热门声音: @handle1 · @handle2 · r/subreddit
其他模式:
记录卡片:
Ruby
生日:6 月 16 日 · 年龄:11
Rhodes
生日:10 月 1 日 · 年龄:8
项目符号列表:
• hzl-cli: 1.12.0
• skill: 1.0.6
限制与拆分