{
  "schemaVersion": "1.0",
  "item": {
    "slug": "telegram-compose",
    "name": "Telegram Compose",
    "source": "tencent",
    "type": "skill",
    "category": "开发工具",
    "sourceUrl": "https://clawhub.ai/tmchow/telegram-compose",
    "canonicalUrl": "https://clawhub.ai/tmchow/telegram-compose",
    "targetPlatform": "OpenClaw"
  },
  "install": {
    "downloadMode": "redirect",
    "downloadUrl": "/downloads/telegram-compose",
    "sourceDownloadUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=telegram-compose",
    "sourcePlatform": "tencent",
    "targetPlatform": "OpenClaw",
    "installMethod": "Manual import",
    "extraction": "Extract archive",
    "prerequisites": [
      "OpenClaw"
    ],
    "packageFormat": "ZIP package",
    "includedAssets": [
      "SKILL.md"
    ],
    "primaryDoc": "SKILL.md",
    "quickSetup": [
      "Download the package from Yavira.",
      "Extract the archive and review SKILL.md first.",
      "Import or place the package into your OpenClaw setup."
    ],
    "agentAssist": {
      "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
      "steps": [
        "Download the package from Yavira.",
        "Extract it into a folder your agent can access.",
        "Paste one of the prompts below and point your agent at the extracted folder."
      ],
      "prompts": [
        {
          "label": "New install",
          "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete."
        },
        {
          "label": "Upgrade existing",
          "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run."
        }
      ]
    },
    "sourceHealth": {
      "source": "tencent",
      "status": "healthy",
      "reason": "direct_download_ok",
      "recommendedAction": "download",
      "checkedAt": "2026-05-07T17:22:31.273Z",
      "expiresAt": "2026-05-14T17:22:31.273Z",
      "httpStatus": 200,
      "finalUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=afrexai-annual-report",
      "contentType": "application/zip",
      "probeMethod": "head",
      "details": {
        "probeUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=afrexai-annual-report",
        "contentDisposition": "attachment; filename=\"afrexai-annual-report-1.0.0.zip\"",
        "redirectLocation": null,
        "bodySnippet": null
      },
      "scope": "source",
      "summary": "Source download looks usable.",
      "detail": "Yavira can redirect you to the upstream package for this source.",
      "primaryActionLabel": "Download for OpenClaw",
      "primaryActionHref": "/downloads/telegram-compose"
    },
    "validation": {
      "installChecklist": [
        "Use the Yavira download entry.",
        "Review SKILL.md after the package is downloaded.",
        "Confirm the extracted package contains the expected setup assets."
      ],
      "postInstallChecks": [
        "Confirm the extracted package includes the expected docs or setup files.",
        "Validate the skill or prompts are available in your target agent workspace.",
        "Capture any manual follow-up steps the agent could not complete."
      ]
    },
    "downloadPageUrl": "https://openagent3.xyz/downloads/telegram-compose",
    "agentPageUrl": "https://openagent3.xyz/skills/telegram-compose/agent",
    "manifestUrl": "https://openagent3.xyz/skills/telegram-compose/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/telegram-compose/agent.md"
  },
  "agentAssist": {
    "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
    "steps": [
      "Download the package from Yavira.",
      "Extract it into a folder your agent can access.",
      "Paste one of the prompts below and point your agent at the extracted folder."
    ],
    "prompts": [
      {
        "label": "New install",
        "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete."
      },
      {
        "label": "Upgrade existing",
        "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run."
      }
    ]
  },
  "documentation": {
    "source": "clawhub",
    "primaryDoc": "SKILL.md",
    "sections": [
      {
        "title": "Telegram Compose",
        "body": "Format and deliver rich, scannable Telegram messages via direct API with HTML formatting."
      },
      {
        "title": "How This Skill Gets Used",
        "body": "This skill is auto-invoked by the main session agent. No other skills need to know about it."
      },
      {
        "title": "Decision Rule (for the main session agent)",
        "body": "Before sending a message to Telegram, check:\n\nShort reply (<3 lines, no structure): Send directly via OpenClaw message tool. Done.\nSubstantive content (>3 lines, or has lists/stats/sections/reports): Spawn this skill as a sub-agent."
      },
      {
        "title": "Spawning the sub-agent",
        "body": "The main session agent calls sessions_spawn with:\n\nsessions_spawn(\n  model: \"claude-haiku-4-5\",\n  task: \"<task content — see template below>\"\n)\n\nTask template:\n\nRead the telegram-compose skill at {baseDir}/SKILL.md for formatting rules, then format and send this content to Telegram.\n\nBot account: <account_name>  (e.g., \"main\" — must match a key in channels.telegram.accounts)\nChat ID: <chat_id>\nThread ID: <thread_id>  (omit this line if not a forum/topic chat)\n\nContent to format:\n---\n<raw content here>\n---\n\nAfter sending, reply with the message_id on success or the error on failure. Do NOT include the formatted message in your reply — it's already been sent to Telegram.\n\nIMPORTANT: The caller MUST specify which bot account to use. The sub-agent must NOT auto-select or iterate accounts.\n\nCRITICAL: 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."
      },
      {
        "title": "What the sub-agent receives",
        "body": "Skill path — so it can read the formatting rules\nBot account name — which Telegram bot account to use (must be specified, never auto-selected)\nChat ID — where to send\nThread ID — topic thread if applicable\nRaw content — the unformatted text/data to turn into a rich message"
      },
      {
        "title": "Credentials",
        "body": "Bot token: Stored in the OpenClaw config file under channels.telegram.accounts.<name>.botToken.\n\nThe account name is always provided by the caller. Never auto-select or iterate accounts.\n\n# Auto-detect config path\nCONFIG=$([ -f ~/.openclaw/openclaw.json ] && echo ~/.openclaw/openclaw.json || echo ~/.openclaw/clawdbot.json)\n\n# ACCOUNT is provided by the caller (e.g., \"main\")\n# Validate the account exists before extracting the token\nACCOUNT=\"<provided_account_name>\"\nBOT_TOKEN=$(jq -r \".channels.telegram.accounts.$ACCOUNT.botToken\" \"$CONFIG\")\n\nif [ \"$BOT_TOKEN\" = \"null\" ] || [ -z \"$BOT_TOKEN\" ]; then\n  echo \"ERROR: Account '$ACCOUNT' not found in config or has no botToken\"\n  exit 1\nfi"
      },
      {
        "title": "Sending",
        "body": "CONFIG=$([ -f ~/.openclaw/openclaw.json ] && echo ~/.openclaw/openclaw.json || echo ~/.openclaw/clawdbot.json)\n# ACCOUNT provided by caller — never auto-select\nBOT_TOKEN=$(jq -r \".channels.telegram.accounts.$ACCOUNT.botToken\" \"$CONFIG\")\n\n# Without topic thread\ncurl -s -X POST \"https://api.telegram.org/bot${BOT_TOKEN}/sendMessage\" \\\n  -H \"Content-Type: application/json\" \\\n  -d \"$(jq -n \\\n    --arg chat \"$CHAT_ID\" \\\n    --arg text \"$MESSAGE\" \\\n    '{\n      chat_id: $chat,\n      text: $text,\n      parse_mode: \"HTML\",\n      link_preview_options: { is_disabled: true }\n    }')\"\n\n# With topic thread\ncurl -s -X POST \"https://api.telegram.org/bot${BOT_TOKEN}/sendMessage\" \\\n  -H \"Content-Type: application/json\" \\\n  -d \"$(jq -n \\\n    --arg chat \"$CHAT_ID\" \\\n    --arg text \"$MESSAGE\" \\\n    --argjson thread $THREAD_ID \\\n    '{\n      chat_id: $chat,\n      text: $text,\n      parse_mode: \"HTML\",\n      message_thread_id: $thread,\n      link_preview_options: { is_disabled: true }\n    }')\""
      },
      {
        "title": "HTML Tags",
        "body": "<b>bold</b>  <i>italic</i>  <u>underline</u>  <s>strike</s>\n<code>mono</code>  <pre>code block</pre>\n<tg-spoiler>hidden until tapped</tg-spoiler>\n<blockquote>quote</blockquote>\n<blockquote expandable>collapsed by default</blockquote>\n<a href=\"url\">link</a>\n<a href=\"tg://user?id=123\">mention by ID</a>"
      },
      {
        "title": "Escaping",
        "body": "Escape these characters in text content only (not in your HTML tags):\n\n& → &amp;  (do this FIRST to avoid double-escaping)\n< → &lt;\n> → &gt;\n\nCommon gotcha: content containing & (e.g., \"R&D\", \"Q&A\") will break HTML parsing if not escaped."
      },
      {
        "title": "Structure Pattern",
        "body": "EMOJI <b>HEADING IN CAPS</b>\n\n<b>Label:</b> Value\n<b>Label:</b> Value\n\n<b>SECTION</b>\n\n• Bullet point\n• Another point\n\n<blockquote>Key quote or summary</blockquote>\n\n<blockquote expandable><b>Details</b>\n\nHidden content here...\nLong details go in expandable blocks.</blockquote>\n\n<a href=\"https://...\">Action Link →</a>"
      },
      {
        "title": "Style Rules",
        "body": "Faux headings: EMOJI <b>CAPS TITLE</b> with blank line after\nEmojis: 1-3 per message as visual anchors, not decoration\nWhitespace: Blank lines between sections\nLong content: Use <blockquote expandable>\nLinks: Own line, with arrow: Link Text →"
      },
      {
        "title": "Examples",
        "body": "Status update:\n\n📋 <b>TASK COMPLETE</b>\n\n<b>Task:</b> Deploy v2.3\n<b>Status:</b> ✅ Done\n<b>Duration:</b> 12 min\n\n<blockquote>All health checks passing.</blockquote>\n\nAlert:\n\n⚠️ <b>ATTENTION NEEDED</b>\n\n<b>Issue:</b> API rate limit at 90%\n<b>Action:</b> Review usage\n\n<a href=\"https://dashboard.example.com\">View Dashboard →</a>\n\nList:\n\n✅ <b>PRIORITIES</b>\n\n• <s>Review PR #234</s> — done\n• <b>Finish docs</b> — in progress\n• Deploy staging\n\n<i>2 of 3 complete</i>"
      },
      {
        "title": "Mobile-Friendly Data Display",
        "body": "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.\n\nFor structured data, use emoji + bold + separators:\n\n❌ BAD (wraps on mobile):\n<pre>\n├─ 🟠 Reddit  32 threads │ 1,658 pts\n└─ 🌐 Web     8 pages\n</pre>\n\n✅ GOOD (flows naturally):\n🟠 <b>Reddit:</b> 32 threads · 1,658 pts · 625 comments\n🔵 <b>X:</b> 22 posts · 10,695 likes · 1,137 reposts\n🌐 <b>Web:</b> 8 pages (supplementary)\n🗣️ <b>Top voices:</b> @handle1 · @handle2 · r/subreddit\n\nOther patterns:\n\nRecord cards:\n\n<b>Ruby</b>\nBirthday: Jun 16 · Age: 11\n\n<b>Rhodes</b>\nBirthday: Oct 1 · Age: 8\n\nBullet lists:\n\n• <b>hzl-cli:</b> 1.12.0\n• <b>skill:</b> 1.0.6"
      },
      {
        "title": "Limits and Splitting",
        "body": "Message max: 4,096 characters\nCaption max: 1,024 characters\n\nIf formatted message exceeds 4,096 chars:\n\nSplit at section boundaries (blank lines between <b>HEADING</b> blocks)\nEach chunk must be valid HTML (don't split inside a tag)\nSend chunks sequentially with a 1-second delay between them\nFirst chunk gets the full heading; subsequent chunks get a continuation indicator: <i>(continued)</i>"
      },
      {
        "title": "Error Handling",
        "body": "If Telegram API returns an error:\n\nErrorActionBad Request: can't parse entitiesHTML is malformed. Strip all HTML tags and resend as plain text.Bad Request: message is too longSplit per the rules above and retry.Bad Request: message thread not foundRetry without message_thread_id (sends to General).Too Many Requests: retry after XWait X seconds, then retry once.Any other errorReport the error back; don't retry.\n\nFallback rule: If HTML formatting fails twice, send as plain text rather than not sending at all. Delivery matters more than formatting."
      },
      {
        "title": "Sub-Agent Execution Checklist",
        "body": "When running as a sub-agent, follow this sequence:\n\nParse the task — extract Bot account name, Chat ID, Thread ID (if any), skill path, and raw content\nRead this SKILL.md — load the formatting rules\nFormat the content — apply HTML tags, structure pattern, style rules, mobile-friendly data display\nEscape special chars — & then < then > in text content only (not in your HTML tags)\nCheck length — if >4,096 chars, split at section boundaries\nGet bot token — auto-detect config path, extract token for the specified account (error if not found)\nSend via curl — use the appropriate template (with/without thread ID)\nCheck response — parse curl output for \"ok\": true\nHandle errors — follow the error handling table above\nReport back — reply with message_id on success, or error details on failure"
      }
    ],
    "body": "Telegram Compose\n\nFormat and deliver rich, scannable Telegram messages via direct API with HTML formatting.\n\nHow This Skill Gets Used\n\nThis skill is auto-invoked by the main session agent. No other skills need to know about it.\n\nDecision Rule (for the main session agent)\n\nBefore sending a message to Telegram, check:\n\nShort reply (<3 lines, no structure): Send directly via OpenClaw message tool. Done.\nSubstantive content (>3 lines, or has lists/stats/sections/reports): Spawn this skill as a sub-agent.\nSpawning the sub-agent\n\nThe main session agent calls sessions_spawn with:\n\nsessions_spawn(\n  model: \"claude-haiku-4-5\",\n  task: \"<task content — see template below>\"\n)\n\n\nTask template:\n\nRead the telegram-compose skill at {baseDir}/SKILL.md for formatting rules, then format and send this content to Telegram.\n\nBot account: <account_name>  (e.g., \"main\" — must match a key in channels.telegram.accounts)\nChat ID: <chat_id>\nThread ID: <thread_id>  (omit this line if not a forum/topic chat)\n\nContent to format:\n---\n<raw content here>\n---\n\nAfter sending, reply with the message_id on success or the error on failure. Do NOT include the formatted message in your reply — it's already been sent to Telegram.\n\n\nIMPORTANT: The caller MUST specify which bot account to use. The sub-agent must NOT auto-select or iterate accounts.\n\nCRITICAL: 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.\n\nWhat the sub-agent receives\nSkill path — so it can read the formatting rules\nBot account name — which Telegram bot account to use (must be specified, never auto-selected)\nChat ID — where to send\nThread ID — topic thread if applicable\nRaw content — the unformatted text/data to turn into a rich message\nCredentials\n\nBot token: Stored in the OpenClaw config file under channels.telegram.accounts.<name>.botToken.\n\nThe account name is always provided by the caller. Never auto-select or iterate accounts.\n\n# Auto-detect config path\nCONFIG=$([ -f ~/.openclaw/openclaw.json ] && echo ~/.openclaw/openclaw.json || echo ~/.openclaw/clawdbot.json)\n\n# ACCOUNT is provided by the caller (e.g., \"main\")\n# Validate the account exists before extracting the token\nACCOUNT=\"<provided_account_name>\"\nBOT_TOKEN=$(jq -r \".channels.telegram.accounts.$ACCOUNT.botToken\" \"$CONFIG\")\n\nif [ \"$BOT_TOKEN\" = \"null\" ] || [ -z \"$BOT_TOKEN\" ]; then\n  echo \"ERROR: Account '$ACCOUNT' not found in config or has no botToken\"\n  exit 1\nfi\n\nSending\nCONFIG=$([ -f ~/.openclaw/openclaw.json ] && echo ~/.openclaw/openclaw.json || echo ~/.openclaw/clawdbot.json)\n# ACCOUNT provided by caller — never auto-select\nBOT_TOKEN=$(jq -r \".channels.telegram.accounts.$ACCOUNT.botToken\" \"$CONFIG\")\n\n# Without topic thread\ncurl -s -X POST \"https://api.telegram.org/bot${BOT_TOKEN}/sendMessage\" \\\n  -H \"Content-Type: application/json\" \\\n  -d \"$(jq -n \\\n    --arg chat \"$CHAT_ID\" \\\n    --arg text \"$MESSAGE\" \\\n    '{\n      chat_id: $chat,\n      text: $text,\n      parse_mode: \"HTML\",\n      link_preview_options: { is_disabled: true }\n    }')\"\n\n# With topic thread\ncurl -s -X POST \"https://api.telegram.org/bot${BOT_TOKEN}/sendMessage\" \\\n  -H \"Content-Type: application/json\" \\\n  -d \"$(jq -n \\\n    --arg chat \"$CHAT_ID\" \\\n    --arg text \"$MESSAGE\" \\\n    --argjson thread $THREAD_ID \\\n    '{\n      chat_id: $chat,\n      text: $text,\n      parse_mode: \"HTML\",\n      message_thread_id: $thread,\n      link_preview_options: { is_disabled: true }\n    }')\"\n\nFormatting Rules\nHTML Tags\n<b>bold</b>  <i>italic</i>  <u>underline</u>  <s>strike</s>\n<code>mono</code>  <pre>code block</pre>\n<tg-spoiler>hidden until tapped</tg-spoiler>\n<blockquote>quote</blockquote>\n<blockquote expandable>collapsed by default</blockquote>\n<a href=\"url\">link</a>\n<a href=\"tg://user?id=123\">mention by ID</a>\n\nEscaping\n\nEscape these characters in text content only (not in your HTML tags):\n\n& → &amp; (do this FIRST to avoid double-escaping)\n< → &lt;\n> → &gt;\n\nCommon gotcha: content containing & (e.g., \"R&D\", \"Q&A\") will break HTML parsing if not escaped.\n\nStructure Pattern\nEMOJI <b>HEADING IN CAPS</b>\n\n<b>Label:</b> Value\n<b>Label:</b> Value\n\n<b>SECTION</b>\n\n• Bullet point\n• Another point\n\n<blockquote>Key quote or summary</blockquote>\n\n<blockquote expandable><b>Details</b>\n\nHidden content here...\nLong details go in expandable blocks.</blockquote>\n\n<a href=\"https://...\">Action Link →</a>\n\nStyle Rules\nFaux headings: EMOJI <b>CAPS TITLE</b> with blank line after\nEmojis: 1-3 per message as visual anchors, not decoration\nWhitespace: Blank lines between sections\nLong content: Use <blockquote expandable>\nLinks: Own line, with arrow: Link Text →\nExamples\n\nStatus update:\n\n📋 <b>TASK COMPLETE</b>\n\n<b>Task:</b> Deploy v2.3\n<b>Status:</b> ✅ Done\n<b>Duration:</b> 12 min\n\n<blockquote>All health checks passing.</blockquote>\n\n\nAlert:\n\n⚠️ <b>ATTENTION NEEDED</b>\n\n<b>Issue:</b> API rate limit at 90%\n<b>Action:</b> Review usage\n\n<a href=\"https://dashboard.example.com\">View Dashboard →</a>\n\n\nList:\n\n✅ <b>PRIORITIES</b>\n\n• <s>Review PR #234</s> — done\n• <b>Finish docs</b> — in progress\n• Deploy staging\n\n<i>2 of 3 complete</i>\n\nMobile-Friendly Data Display\n\nNever 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.\n\nFor structured data, use emoji + bold + separators:\n\n❌ BAD (wraps on mobile):\n<pre>\n├─ 🟠 Reddit  32 threads │ 1,658 pts\n└─ 🌐 Web     8 pages\n</pre>\n\n✅ GOOD (flows naturally):\n🟠 <b>Reddit:</b> 32 threads · 1,658 pts · 625 comments\n🔵 <b>X:</b> 22 posts · 10,695 likes · 1,137 reposts\n🌐 <b>Web:</b> 8 pages (supplementary)\n🗣️ <b>Top voices:</b> @handle1 · @handle2 · r/subreddit\n\n\nOther patterns:\n\nRecord cards:\n\n<b>Ruby</b>\nBirthday: Jun 16 · Age: 11\n\n<b>Rhodes</b>\nBirthday: Oct 1 · Age: 8\n\n\nBullet lists:\n\n• <b>hzl-cli:</b> 1.12.0\n• <b>skill:</b> 1.0.6\n\nLimits and Splitting\nMessage max: 4,096 characters\nCaption max: 1,024 characters\n\nIf formatted message exceeds 4,096 chars:\n\nSplit at section boundaries (blank lines between <b>HEADING</b> blocks)\nEach chunk must be valid HTML (don't split inside a tag)\nSend chunks sequentially with a 1-second delay between them\nFirst chunk gets the full heading; subsequent chunks get a continuation indicator: <i>(continued)</i>\nError Handling\n\nIf Telegram API returns an error:\n\nError\tAction\nBad Request: can't parse entities\tHTML is malformed. Strip all HTML tags and resend as plain text.\nBad Request: message is too long\tSplit per the rules above and retry.\nBad Request: message thread not found\tRetry without message_thread_id (sends to General).\nToo Many Requests: retry after X\tWait X seconds, then retry once.\nAny other error\tReport the error back; don't retry.\n\nFallback rule: If HTML formatting fails twice, send as plain text rather than not sending at all. Delivery matters more than formatting.\n\nSub-Agent Execution Checklist\n\nWhen running as a sub-agent, follow this sequence:\n\nParse the task — extract Bot account name, Chat ID, Thread ID (if any), skill path, and raw content\nRead this SKILL.md — load the formatting rules\nFormat the content — apply HTML tags, structure pattern, style rules, mobile-friendly data display\nEscape special chars — & then < then > in text content only (not in your HTML tags)\nCheck length — if >4,096 chars, split at section boundaries\nGet bot token — auto-detect config path, extract token for the specified account (error if not found)\nSend via curl — use the appropriate template (with/without thread ID)\nCheck response — parse curl output for \"ok\": true\nHandle errors — follow the error handling table above\nReport back — reply with message_id on success, or error details on failure"
  },
  "trust": {
    "sourceLabel": "tencent",
    "provenanceUrl": "https://clawhub.ai/tmchow/telegram-compose",
    "publisherUrl": "https://clawhub.ai/tmchow/telegram-compose",
    "owner": "tmchow",
    "version": "1.0.4",
    "license": null,
    "verificationStatus": "Indexed source record"
  },
  "links": {
    "detailUrl": "https://openagent3.xyz/skills/telegram-compose",
    "downloadUrl": "https://openagent3.xyz/downloads/telegram-compose",
    "agentUrl": "https://openagent3.xyz/skills/telegram-compose/agent",
    "manifestUrl": "https://openagent3.xyz/skills/telegram-compose/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/telegram-compose/agent.md"
  }
}