tgcli
Telegram CLI skill for AI agents.
Install
Install this skill from GitHub:
npx skills add dapi/tgcli --skill tgcli --agent '*' -g -y
Install CLI:
npm install -g @dapi/tgcli
Authenticate once:
tgcli auth
Tool Boundary: tgcli vs telegram-mcp
| Use tgcli for | Use telegram-mcp for |
|---|---|
| Read/search/archive messages | edit/delete/forward |
| Send text/photo/files and topic posts | reactions |
| Forum topics listing/search | inline bot buttons |
| Download media from messages | advanced interactive actions |
| Group admin (rename, members, invite, join/leave) | ban/kick/promote with granular permissions |
| Channel/contact tags and metadata | |
| Sync jobs and archive monitoring | |
| JSON output for automation |
Execution Rules
- If
tgcliis not found, install it:npm install -g @dapi/tgclithen runtgcli authfor first-time login. tgcli authonly authenticates the Telegram session. Usetgcli sync --onceortgcli sync --followto seed/archive dialogs.- Always add
--jsonfor agent workflows. - Add
--timeout 30sby default; use--timeout 90sfor heavy archive fallback reads. - Prefer explicit
--source archive|live|bothinstead of relying on defaults. - Never use
--since; tgcli uses--afterand--beforewith ISO timestamps. - Never use
tgcli sync --chat ...; top-levelsynconly runs workers via--once/--follow. - To sync a specific chat:
tgcli channels sync --chat <id|@username> --enableand/ortgcli sync jobs add --chat <id|@username>, then runtgcli sync --onceortgcli sync --follow. - If command shape is uncertain, verify it first with
tgcli <command> --helpinstead of guessing flags. - For sending format control:
--parse-mode markdown|html|none(case-insensitive)- for
send photoandsend file,--parse-moderequires--caption --reply-to <messageId>replies to a specific message; if both--reply-toand--topicare passed,--reply-towins--silentsends without notification sound--no-forwardsprotects message from forwarding/saving--schedule <iso>schedules message for future delivery (ISO 8601, must be in the future, within 365 days)--caption-aboveshows caption above media (send photo/send file, requires--caption)--spoilerblurs media until tapped (send photo/send file)--retries <n>retries transient network/transport failures forsend photo--retry-backoff <ms|constant|linear|exponential>controls retry delay forsend photo--force-documentsends photo/video as uncompressed document (send fileonly)--retries <n>retry on failure with exponential backoff (default 0); JSON output includesretry_logandattemptswhen retries occurred
- Telegram markdown formatting (when
--parse-mode markdown):- Bold:
**text** - Italic:
__text__(double underscores, NOT single_) - Bold+Italic:
**__text__**(bold wraps italic) - Single
_text_does NOT work for italic — renders as literal underscores - Single
*text*does NOT work for bold — renders as literal asterisks - Monospace inline:
`text` - Code block: triple backticks
- Telegram markdown differs from standard Markdown — always use double markers
- Bold:
- Never delete lock files (
LOCK,database is locked): wait and retry.
Core Command Patterns
Read
tgcli messages list --chat <id|@username> --limit 50 --source archive --json --timeout 30s
tgcli messages list --chat <id|@username> --chat <id2> --limit 50 --source archive --json --timeout 30s
tgcli messages list --chat <id|@username> --topic <topicId> --after 2025-01-01T00:00:00Z --limit 100 --source archive --json --timeout 30s
tgcli messages show --chat <id|@username> --id <msgId> --source archive --json --timeout 30s
tgcli messages context --chat <id|@username> --id <msgId> --before 5 --after 5 --source archive --json --timeout 30s
Never use --since here; the correct flag is --after.
Search
tgcli messages search "Claude Code" --chat <id|@username> --source archive --json --timeout 30s
tgcli messages search --query "Claude Code" --chat <id|@username> --source archive --json --timeout 30s
tgcli messages search --regex "claude\\s+(code|agent)" --chat <id|@username> --source archive --json --timeout 30s
tgcli messages search --tag ai --chat <id|@username> --source archive --json --timeout 30s
tgcli messages search --tags "ai,dev" --chat <id|@username> --source archive --json --timeout 30s
tgcli messages search "release" --chat <id|@username> --after 2025-06-01T00:00:00Z --before 2025-06-30T00:00:00Z --source archive --json --timeout 30s
tgcli messages search "Release" --case-sensitive --chat <id|@username> --source archive --json --timeout 30s
Both positional query and --query flag work. --chat accepts multiple values. Use --regex for pattern matching, --tag/--tags to filter by channel tags, --after/--before for date range, --case-sensitive to disable case-insensitive search.
Send Text/Photo/File
⚠ send uses --to for the destination; then --message for text, --photo for photo uploads, and --file for generic files.
tgcli send text --to <id|@username> --message "Hello" --json --timeout 30s
tgcli send text --to <id|@username> --topic <topicId> --message "**Hello**" --parse-mode markdown --json --timeout 30s
tgcli send text --to <id|@username> --message "Done" --reply-to <messageId> --json --timeout 30s
tgcli send text --to <id|@username> --message "https://example.com check this" --no-preview --json --timeout 30s
tgcli send text --to <id|@username> --message "Nightly report" --silent --json --timeout 30s
tgcli send text --to <id|@username> --message "Confidential" --no-forwards --json --timeout 30s
tgcli send text --to <id|@username> --message "Good morning!" --schedule "2025-01-15T09:00:00+03:00" --json --timeout 30s
tgcli send text --to <id|@username> --message "Hello" --retries 3 --json --timeout 30s
tgcli send photo --to <id|@username> --photo /path/to/image.png --caption "Report" --json --timeout 30s
tgcli send photo --to <id|@username> --photo /path/to/image.png --caption "**Report**" --parse-mode markdown --json --timeout 30s
tgcli send photo --to <id|@username> --photo /path/to/image.png --reply-to <messageId> --json --timeout 30s
tgcli send photo --to <id|@username> --photo /path/to/image.png --caption "Breaking news" --caption-above --json --timeout 30s
tgcli send photo --to <id|@username> --photo /path/to/image.png --spoiler --json --timeout 30s
tgcli send photo --to <id|@username> --photo /path/to/image.png --retries 3 --retry-backoff exponential --json --timeout 30s
tgcli send file --to <id|@username> --file /path/to/file --caption "Report" --json --timeout 30s
tgcli send file --to <id|@username> --file /path/to/file --caption "<b>Report</b>" --parse-mode html --json --timeout 30s
tgcli send file --to <id|@username> --file /path/to/file --filename custom-name.pdf --json --timeout 30s
tgcli send file --to <id|@username> --file /path/to/file --reply-to <messageId> --json --timeout 30s
tgcli send file --to <id|@username> --file /path/to/file --caption "Breaking news" --caption-above --json --timeout 30s
tgcli send file --to <id|@username> --file /path/to/photo.jpg --spoiler --json --timeout 30s
tgcli send file --to <id|@username> --file /path/to/photo.jpg --force-document --json --timeout 30s
Photo Preview vs Document Upload
- Use
tgcli send photofor local PNG/JPG when Telegram should render a photo preview. - Use
tgcli send filefor generic uploads and explicit document-style attachments. - For draft/approval flow, send to Saved Messages first, review in Telegram, then resend to the target chat.
Media Download
tgcli media download --chat <id|@username> --id <msgId> --json --timeout 30s
tgcli media download --chat <id|@username> --id <msgId> --output /path/to/save --json --timeout 30s
Channels
tgcli channels list --query "ai" --limit 20 --json --timeout 30s
tgcli channels show --chat <id|@username> --json --timeout 30s
tgcli channels sync --chat <id|@username> --enable --json --timeout 30s
tgcli channels sync --chat <id|@username> --disable --json --timeout 30s
Topics
tgcli topics list --chat <id|@username> --limit 50 --json --timeout 30s
tgcli topics search --chat <id|@username> --query "release" --limit 20 --json --timeout 30s
Contacts
tgcli contacts search "alex" --limit 20 --json --timeout 30s
tgcli contacts show --user <id> --json --timeout 30s
tgcli contacts alias set --user <id> --alias "Alex" --json --timeout 30s
tgcli contacts alias rm --user <id> --json --timeout 30s
tgcli contacts tags add --user <id> --tag coworker --tag ai --json --timeout 30s
tgcli contacts tags rm --user <id> --tag ai --json --timeout 30s
tgcli contacts notes set --user <id> --notes "Met at meetup" --json --timeout 30s
Groups
tgcli groups list --query "dev" --limit 20 --json --timeout 30s
tgcli groups info --chat <id|@username> --json --timeout 30s
tgcli groups rename --chat <id|@username> --name "New Name" --json --timeout 30s
tgcli groups members add --chat <id|@username> --user <userId> --user <userId2> --json --timeout 30s
tgcli groups members remove --chat <id|@username> --user <userId> --json --timeout 30s
tgcli groups invite get --chat <id|@username> --json --timeout 30s
tgcli groups invite revoke --chat <id|@username> --json --timeout 30s
tgcli groups join --code <invite-code> --json --timeout 30s
tgcli groups leave --chat <id|@username> --json --timeout 30s
Tags (Channel Classification)
tgcli tags list --chat <id|@username> --json --timeout 30s
tgcli tags set --chat <id|@username> --tag ai --tag dev --json --timeout 30s
tgcli tags search --tag ai --limit 20 --json --timeout 30s
tgcli tags auto --limit 50 --json --timeout 90s # AI-powered: generates tags from channel metadata/content
tgcli tags auto --chat <id|@username> --source manual --json --timeout 90s
tgcli tags auto --limit 50 --no-refresh-metadata --json --timeout 90s
Metadata (Channel Cache)
tgcli metadata get --chat <id|@username> --json --timeout 30s
tgcli metadata refresh --chat <id|@username> --force --json --timeout 30s
tgcli metadata refresh --only-missing --limit 50 --json --timeout 90s
Folders
tgcli folders list --json --timeout 30s
tgcli folders show <name|id> --json --timeout 30s
tgcli folders show <name|id> --resolve --json --timeout 30s
tgcli folders create --title "Name" --emoji "🤖" --json --timeout 30s
tgcli folders edit <name|id> --title "New Name" --json --timeout 30s
tgcli folders delete <name|id> --json --timeout 30s
tgcli folders order <id1> <id2> <id3> --json --timeout 30s
tgcli folders add-chat <folder> --chat <id> --json --timeout 30s
tgcli folders remove-chat <folder> --chat <id> --json --timeout 30s
tgcli folders join --link "https://t.me/addlist/slug" --json --timeout 30s
Use --resolve with folders show to resolve peer IDs to readable channel/user names (slower, requires API calls per peer). Without --resolve, peers are shown as typed IDs (e.g., channel:123).
Sync Jobs
tgcli sync status --json --timeout 30s
tgcli sync jobs list --json --timeout 30s
tgcli sync jobs list --status error --json --timeout 30s
tgcli sync jobs list --channel <id|@username> --json --timeout 30s
tgcli sync jobs add --chat <id|@username> --depth 500 --json --timeout 30s
tgcli sync jobs add --chat <id|@username> --min-date 2025-01-01T00:00:00Z --json --timeout 30s
tgcli sync jobs retry --all-errors --json --timeout 30s
tgcli sync jobs retry --job-id <id> --json --timeout 30s
tgcli sync jobs retry --channel <id|@username> --json --timeout 30s
tgcli sync jobs cancel --job-id <id> --json --timeout 30s
tgcli sync jobs cancel --channel <id|@username> --json --timeout 30s
Do not write tgcli sync --chat ...; queue work with sync jobs add --chat ..., then process it with tgcli sync --once or tgcli sync --follow.
Service (Background Sync Daemon)
tgcli service status --json --timeout 30s
tgcli service install --json --timeout 30s
tgcli service start --json --timeout 30s
tgcli service stop --json --timeout 30s
tgcli service logs --json --timeout 30s
Config & Auth
tgcli auth --json --timeout 30s
tgcli auth --qr --json --timeout 30s
tgcli auth status --json --timeout 30s
tgcli auth logout --json --timeout 30s
tgcli config list --json --timeout 30s
tgcli config get <key> --json --timeout 30s
tgcli config set <key> <value> --json --timeout 30s
tgcli config unset <key> --json --timeout 30s
tgcli doctor --json --timeout 30s
tgcli doctor --connect --json --timeout 30s
Archive + Analysis Workflow
For tasks like "analyze chat history", "what happened this week", "digest/news":
- Resolve chat:
tgcli channels list --query "<name>" --json --timeout 30s- optionally
tgcli groups list --query "<name>" --json --timeout 30s
- Ensure archive flow:
tgcli channels sync --chat <id> --enabletgcli sync jobs add --chat <id> --depth 500tgcli service status --json --timeout 30s— check if runningtgcli service install --json --timeout 30s— if not installed yettgcli service start --json --timeout 30s— start daemon
- Read archive first:
tgcli messages list --chat <id> --source archive --limit 500 --json --timeout 30s
- If archive is still empty, fallback to live:
tgcli messages list --chat <id> --source live --limit 500 --json --timeout 90s
- Build digest/synthesis from JSON payload.
Continuous Sync Workflow
For tasks like "monitor these channels", "keep syncing my subscriptions":
Architecture: channels sync --enable marks channels for watching → sync jobs add creates backfill tasks → service start runs a persistent daemon that processes jobs and pulls realtime updates.
- Enable sync for each channel:
tgcli channels sync --chat <id|@username> --enable --json --timeout 30s- repeat for each channel to monitor
- Add backfill jobs (optional, pulls history):
tgcli sync jobs add --chat <id|@username> --depth 1000 --json --timeout 30s
- Start the background daemon:
tgcli service install --json --timeout 30s— first time onlytgcli service start --json --timeout 30s
- Verify it's running:
tgcli service status --json --timeout 30stgcli sync status --json --timeout 30s— shows per-channel sync progress
- Check for errors:
tgcli sync jobs list --status error --json --timeout 30stgcli sync jobs retry --all-errors --json --timeout 30s
- Stop monitoring a channel:
tgcli channels sync --chat <id|@username> --disable --json --timeout 30s
Alternative without systemd service (one-shot or foreground):
tgcli sync --once— run one sync pass and exittgcli sync --follow— keep syncing in foreground (ctrl-c to stop)tgcli sync --follow --idle-exit 5m— auto-exit after 5 minutes idle
Sync Semantics
- "My channels/subscriptions" ->
tgcli channels list ... - "Monitored/synced channels" ->
tgcli sync status --json --timeout 30s
Trigger Examples
Should trigger
- "read messages in <channel>"
- "search telegram for <query>"
- "send this text/file to telegram"
- "download file from telegram message"
- "summarize what was discussed this week"
- "what's new in <chat>?"
- "show my mentions in <channel>"
- "tag channels by topic"
- "add user to telegram group"
- "get invite link for group"
- "reply to a specific telegram message"
- "start syncing this channel"
- "monitor my telegram channels"
- "прочитай сообщения в канале"
- "найди в телеграме про релиз"
- "отправь сообщение в канал"
- "дай сводку по чату"
- "скачай файл из сообщения"
- "опубликуй пост с картинкой"
- "отправь фото с подписью в канал"
- "post with cover image"
Should not trigger
- "edit/delete/forward telegram message"
- "react with emoji to message"
- "click inline button in bot"
- "ban/kick/promote user with granular permissions"
Use telegram-mcp for those operations.