Telegram Send
Send voice, photo, and document files via Telegram bot — with a Bot-API-first delivery policy, automatic chat ID resolution, and a local endpoint fallback for text notices and retries.
Default Active Communication
telegram-send is injected into every session automatically. No manual loading required. When you say "send via Telegram" or "텔레그램으로 보내줌", the skill activates and the agent follows the delivery policy described on this page.
Quick Reference
| Skill name | telegram-send |
| Category | Communication |
| Default active | Yes — injected at session start |
| SKILL.md path | ~/.cli-jaw/skills/telegram-send/SKILL.md |
| System tools | curl, jq |
| Config source | ~/.cli-jaw/settings.json (telegram.token, telegram.allowedChatIds) |
| Primary API | Telegram Bot API (https://api.telegram.org/bot<TOKEN>/...) |
| Fallback API | Local endpoint (http://localhost:3457/api/telegram/send) |
| Supported types | photo, voice, document, text |
| Related skills | email-draft-polish, whatsapp, xurl |
| Related guide | Telegram Guide |
Delivery Policy (Bot-First)
The skill follows a strict two-tier delivery strategy. The Telegram Bot API is always tried first. The local CLI-JAW endpoint serves as a convenience layer for text and as a fallback when the Bot API fails.
| Message Type | Primary Method | Fallback |
|---|---|---|
photo | Telegram Bot API (sendPhoto) | Local endpoint (one retry) |
voice | Telegram Bot API (sendVoice) | Local endpoint (one retry) |
document | Telegram Bot API (sendDocument) | Local endpoint (one retry) |
text | Local endpoint (convenience) | Telegram Bot API (sendMessage) |
photo, voice, and document types, the agent always attempts the direct Bot API first. The local endpoint is only used as a single-retry fallback if the Bot API call fails. For text status notices, the local endpoint is used first for convenience.
Required Inputs
| Input | Source | Required For |
|---|---|---|
| Bot token | ~/.cli-jaw/settings.json → telegram.token | All Bot API calls |
| Chat ID | ~/.cli-jaw/settings.json → telegram.allowedChatIds[-1] | All Bot API calls |
| File path | Provided by user or generated by previous task | photo, voice, document |
| Caption / text | Provided by user (optional for media) | text; optional caption for media |
Step-by-Step Workflow
Step 1: Read Token and Chat ID
The agent reads credentials from the CLI-JAW settings file. Tokens are kept in shell variables only — never printed to stdout or logs.
TOKEN=$(jq -r '.telegram.token' ~/.cli-jaw/settings.json)
CHAT_ID=$(jq -r '.telegram.allowedChatIds[-1]' ~/.cli-jaw/settings.json)
If CHAT_ID resolves to null (no previous Telegram message on record), the agent recovers by pinging the local endpoint:
CHAT_ID=$(curl -sS -X POST http://localhost:3457/api/telegram/send \
-H "Content-Type: application/json" \
-d '{"type":"text","text":"chat_id check"}' | jq -r '.chat_id')
Step 2: Send via Bot API (Primary)
The agent constructs a curl multipart form POST to the appropriate Telegram Bot API endpoint based on the message type.
Send a photo
curl -sS -X POST "https://api.telegram.org/bot${TOKEN}/sendPhoto" \
-F "chat_id=${CHAT_ID}" \
-F "photo=@/tmp/chart.png" \
-F "caption=Analysis chart"
Send a voice message
curl -sS -X POST "https://api.telegram.org/bot${TOKEN}/sendVoice" \
-F "chat_id=${CHAT_ID}" \
-F "voice=@/tmp/reply.ogg" \
-F "caption=Voice response"
Send a document
curl -sS -X POST "https://api.telegram.org/bot${TOKEN}/sendDocument" \
-F "chat_id=${CHAT_ID}" \
-F "document=@/tmp/report.pdf" \
-F "caption=Weekly report"
Step 3: Local Endpoint (Secondary / Fallback)
The local CLI-JAW server exposes a Telegram send endpoint at:
POST http://localhost:3457/api/telegram/send
Content-Type: application/json
Accepts: type, text, file_path, caption
Text message (primary use of local endpoint)
curl -sS -X POST http://localhost:3457/api/telegram/send \
-H "Content-Type: application/json" \
-d '{"type":"text","text":"Deployment complete!"}'
Media fallback via local endpoint
curl -sS -X POST http://localhost:3457/api/telegram/send \
-H "Content-Type: application/json" \
-d '{"type":"photo","file_path":"/tmp/chart.png","caption":"Analysis chart"}'
Step 4: Verify Delivery
A successful send returns a JSON response with "ok": true:
{"ok":true,"chat_id":8231528245,"type":"text"}
The agent checks this response before reporting success to the user. If the response indicates failure, and the primary method was Bot API, one retry is attempted via the local endpoint.
Supported Message Types
| Type | Bot API Method | Required Fields | Optional Fields |
|---|---|---|---|
photo | sendPhoto | chat_id, photo (file) | caption, parse_mode |
voice | sendVoice | chat_id, voice (file, OGG format) | caption, duration |
document | sendDocument | chat_id, document (file) | caption, parse_mode |
text | sendMessage / local endpoint | chat_id, text | parse_mode, disable_notification |
Configuration
The skill reads all configuration from ~/.cli-jaw/settings.json. No separate config file is needed.
// ~/.cli-jaw/settings.json (relevant keys)
{
"telegram": {
"token": "123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11",
"allowedChatIds": [8231528245]
}
}
| Key | Type | Description |
|---|---|---|
telegram.token | string | Telegram Bot API token from @BotFather |
telegram.allowedChatIds | number[] | Array of allowed chat IDs. The skill uses the last entry by default. |
allowedChatIds may be empty. The skill will auto-discover your chat ID by sending a probe message via the local endpoint and reading the chat_id field from the response.
Dependencies
This skill requires only standard Unix tools that are pre-installed on macOS and most Linux distributions.
Pre-installed on macOS and Linux
brew install jq
Verify dependencies
# Check curl
curl --version
# Check jq
jq --version
# Install jq if missing (macOS)
brew install jq
# Install jq if missing (Ubuntu/Debian)
sudo apt-get install -y jq
Safety Rules
The skill enforces strict security practices around token handling:
| Rule | Detail |
|---|---|
| No token printing | The bot token is never echoed, printed, or included in agent text output. It exists only in shell variables. |
| Shell-only storage | Tokens are read into $TOKEN and used inline. They are not written to temp files or exported to the environment. |
| No log leakage | Commands use -sS flags to suppress progress bars while still showing errors, avoiding accidental token exposure in verbose logs. |
| Single retry limit | If Bot API fails, only one fallback attempt via local endpoint is permitted. No infinite retry loops. |
| Allowed chat IDs | The skill only sends to chat IDs listed in telegram.allowedChatIds, preventing accidental messages to unauthorized chats. |
Quick Verification
To test that the Telegram integration is working, run this ping command:
curl -sS -X POST http://localhost:3457/api/telegram/send \
-H "Content-Type: application/json" \
-d '{"type":"text","text":"ping"}'
Expected response:
{"ok":true,"chat_id":8231528245,"type":"text"}
If you receive an error, check that:
- The CLI-JAW server is running (
jaw server status) - The bot token is configured in
~/.cli-jaw/settings.json - You have sent at least one message to the bot on Telegram (to establish the chat)
"~해줌" Usage Examples
Real-world examples showing how to trigger the telegram-send skill in natural language. Korean and English both work.
sendPhoto endpoint. The agent locates the chart file from the current task context and attaches it automatically.sendVoice. If TTS generation is available, the agent produces the audio first, then delivers it.sendDocument. The caption is set to a brief description of the file. The agent checks for the file at output/pdf/ or the path specified by the user.screen-capture skill output with telegram-send.Integration with Other Skills
The telegram-send skill is often the final step in a multi-skill workflow. It pairs naturally with any skill that produces output files or status updates.
| Workflow | Skills Involved | Example |
|---|---|---|
| Report generation + delivery | pdf + telegram-send | "보고서 PDF 만들어서 텔레그램으로 보내줌" |
| Chart + notification | dev-data + telegram-send | "매출 차트 만들어서 텔레그램에 공유해줌" |
| Screenshot capture + send | screen-capture + telegram-send | "화면 찍어서 텔레그램으로 바로 보내줌" |
| Voice reply | video (TTS) + telegram-send | "이 내용 음성으로 변환해서 텔레그램에 보내줌" |
| Multi-channel broadcast | telegram-send + whatsapp + xurl | "이 공지사항 텔레그램, 왔츠앱, X 전부 보내줌" |
| Deploy notification | cloudflare + telegram-send | "Workers 배포하고 결과 텔레그램으로 알려줌" |
API Reference
Bot API Endpoints Used
| Endpoint | Method | Purpose |
|---|---|---|
/bot<TOKEN>/sendPhoto | POST (multipart/form-data) | Send an image file |
/bot<TOKEN>/sendVoice | POST (multipart/form-data) | Send an OGG voice message |
/bot<TOKEN>/sendDocument | POST (multipart/form-data) | Send any file as a document |
/bot<TOKEN>/sendMessage | POST (application/json) | Send a text message (fallback for text type) |
Local Endpoint
| Endpoint | Method | Body |
|---|---|---|
http://localhost:3457/api/telegram/send | POST | {"type": "photo|voice|document|text", "text": "...", "file_path": "...", "caption": "..."} |
Response Format
// Success
{"ok": true, "chat_id": 8231528245, "type": "text"}
// Failure (example)
{"ok": false, "error": "Bot token not configured"}
Troubleshooting
Chat ID is null
If jq -r '.telegram.allowedChatIds[-1]' returns null, the bot has not received any messages from you yet. Send any message to the bot on Telegram first, then the chat ID will be recorded in settings. Alternatively, the agent will auto-recover by probing the local endpoint.
Bot API returns 401 Unauthorized
The bot token is invalid or expired. Generate a new token from @BotFather and update ~/.cli-jaw/settings.json.
Bot API returns 400 Bad Request
Common causes:
- Invalid chat_id: The chat ID does not correspond to an active conversation with the bot.
- File too large: Telegram Bot API limits files to 50 MB for uploads. For larger files, use the local endpoint which may handle chunked uploads.
- Wrong file format for voice: Voice messages must be in OGG format with OPUS encoding. Other audio formats should be sent as
documentinstead.
Local endpoint connection refused
The CLI-JAW server is not running. Start it with:
jaw server start
# Or check status
jaw server status
jq not found
Install jq to parse the settings file:
# macOS
brew install jq
# Ubuntu/Debian
sudo apt-get install -y jq
# Verify
jq --version
Comparison with Telegram Guide
CLI-JAW documentation covers Telegram in two places. They serve different purposes:
| This page (Skill Reference) | Telegram Guide | |
|---|---|---|
| Focus | Technical details of the telegram-send skill — API commands, delivery policy, safety rules | End-to-end setup guide for connecting Telegram to CLI-JAW |
| Audience | Users who want to understand exactly what the agent does when sending to Telegram | New users setting up Telegram integration for the first time |
| Covers | SKILL.md internals, Bot API calls, fallback logic, troubleshooting | Bot creation, token setup, initial message pairing, dashboard config |