tgcli
If tgcli is not found, install it: npm install -g @dapi/tgcli then run tgcli auth for first-time login.; tgcli auth only authenticates the Telegram session. Use tgcli sync --once or tgcli sync --follow to seed/archive dialogs.; Always add --json for agent workflows.
Works with
Agent Skills format with YAML frontmatter. Claude Code reads it as-is.
--- name: "tgcli" description: "If tgcli is not found, install it: npm install -g @dapi/tgcli then run tgcli auth for first-time login.; tgcli auth only authenticates the Telegram session. Use tgcli sync --once or tgcli sync --follow to seed/archive dialogs.; Always add --json for agent workflows." license: "MIT" --- # tgcli Telegram CLI skill for AI agents. ## Install Install this skill from GitHub: ```bash npx skills add dapi/tgcli --skill tgcli --agent '*' -g -y ``` Install CLI: ```bash npm install -g @dapi/tgcli ``` Authenticate once: ```bash 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 (join requests, 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 `tgcli` is not found, install it: `npm install -g @dapi/tgcli` then run `tgcli auth` for first-time login. - `tgcli auth` only authenticates the Telegram session. Use `tgcli sync --once` or `tgcli sync --follow` to seed/archive dialogs. - Always add `--json` for agent workflows. - Add `--timeout 30s` by default; use `--timeout 90s` for heavy archive fallback reads. - Prefer explicit `--source archive|live|both` instead of relying on defaults. - Never use `--since`; tgcli uses `--after` and `--before` with ISO timestamps. - Never use `tgcli sync --chat ...`; top-level `sync` only runs workers via `--once` / `--follow`. - To sync a specific chat: `tgcli channels sync --chat <id|@username> --enable` and/or `tgcli sync jobs add --chat <id|@username>`, then run `tgcli sync --once` or `tgcli sync --follow`. - If command shape is uncertain, verify it first with `tgcli <command> --help` instead of guessing flags. - Select named accounts with the global `--account <id|alias|phone>` option before the command, or with `TGCLI_ACCOUNT`. Selection precedence is `--account` → `TGCLI_ACCOUNT` → `default`. - The `default` profile keeps the legacy store and existing authorization. Never run `auth logout`, move a session, or copy session files merely because a named profile is not visible. - Named profiles have physically isolated config, session, messages database, locks, downloads, sync jobs, and service state. Always use the same account selector for auth, reads, writes, sync, and service commands belonging to that profile. - If account commands unexpectedly show no profiles or report missing configuration, inspect `TGCLI_STORE`: an inherited temporary/test store can hide the production profile registry. Resolve the intended base store before considering any auth change. - For sending format control: - `--parse-mode markdown|html|none` (case-insensitive) - for `send photo` and `send file`, `--parse-mode` requires `--caption` - `--reply-to <messageId>` replies to a specific message; if both `--reply-to` and `--topic` are passed, `--reply-to` wins - `--silent` sends without notification sound - `--no-forwards` protects message from forwarding/saving - `--schedule <iso>` schedules message for future delivery (ISO 8601, must be in the future, within 365 days) - `--caption-above` shows caption above media (`send photo`/`send file`, requires `--caption`) - `--spoiler` blurs media until tapped (`send photo`/`send file`) - `--retries <n>` retries transient network/transport failures for `send photo` - `--retry-backoff <ms|constant|linear|exponential>` controls retry delay for `send photo` - `--force-document` sends photo/video as uncompressed document (`send file` only) - `--retries <n>` retry on failure with exponential backoff (default 0); JSON output includes `retry_log` and `attempts` when 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 - Never delete lock files (`LOCK`, `database is locked`): wait and retry. - For multiline text or arbitrary user-authored text, use `scripts/send_text.py` and pass the body through stdin. It invokes `tgcli` without a shell, preserving real line breaks and punctuation exactly. - Never construct a shell command with `JSON.stringify(message)` and never put literal `\\n` sequences in `--message`: Telegram will display the backslash and the letter `n` instead of a line break. - After sending multiline text, read the message back and verify that `text` contains real newline characters, not literal `\\n` sequences. ## Core Command Patterns ### Accounts ```bash # Existing commands without a selector continue to use the default profile. tgcli auth status --json --timeout 30s # Register an isolated profile without contacting Telegram. tgcli accounts add work --phone "+7 707 111 22 33" --alias office tgcli accounts list --json # Authenticate and use exactly one named profile. tgcli --account work auth tgcli --account office auth status --json --timeout 30s tgcli --account +770****2233 messages search "invoice" --source live --json --timeout 30s # Environment selection is useful for a dedicated service/process. TGCLI_ACCOUNT=work tgcli sync --follow ``` Account selectors resolve by stable profile ID, normalized phone number, or alias. If selection is ambiguous or the stored Telegram user ID does not match the session, stop and inspect the profile; never fall back to another account. For login codes delivered in-app, read Telegram's official service chat `777000` through the same already-authorized target profile. Codes may be localized, for example `Код для входа в Telegram:` or `Login code:`. Filter by the authorization request timestamp and pass the code over stdin rather than putting it in command arguments or logs. ### Read ```bash 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 ```bash 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` (alias `--chat`) for the destination; then `--message` (alias `--text`) for text body, `--photo` for photo uploads, and `--file` for generic files.** For multiline text, use the stdin helper with a single-quoted heredoc delimiter: ```bash python3 ~/.agents/skills/tgcli/scripts/send_text.py --to <id|@username> <<'TGCLI_MESSAGE' Первая строка. 1. Первый пункт. 2. Второй пункт. TGCLI_MESSAGE ``` The quoted delimiter prevents shell expansion, while stdin preserves actual line breaks. Direct `tgcli send text --message "..."` remains suitable for short, static, single-line messages. ```bash 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 photo` for local PNG/JPG when Telegram should render a photo preview. - Use `tgcli send file` for 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 ```bash 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 ```bash 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 ```bash 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 ```bash 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 ```bash tgcli groups list --query "dev" --limit 20 --json --timeout 30s tgcli groups info --chat <id|@username> --json --timeout 30s tgcli groups requests list --chat <id|@username> --limit 100 --json --timeout 30s tgcli groups requests list --chat <id|@username> --query "alex" --json --timeout 30s tgcli groups requests list --chat <id|@username> --link <invite-url> --json --timeout 30s tgcli groups requests approve --chat <id|@username> --user <userId> --json --timeout 30s tgcli groups requests decline --chat <id|@username> --user <userId> --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 ``` Join-request commands require group administrator permissions. Never combine `--query` and `--link`. Approve or decline only the exact `userId` returned by the latest `groups requests list` result; a request may already have been handled by another administrator. ### Tags (Channel Classification) ```bash 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) ```bash 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 ```bash 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 ```bash 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) ```bash 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 ```bash 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 # Route via SOCKS5 (stored in config.json) tgcli config set proxy socks5://127.0.0.1:1080 --json --timeout 30s # Route via MTProxy (Telegram t.me link format also accepted) tgcli config set proxy "https://t.me/proxy?server=HOST&port=PORT&secret=SECRET" --json --timeout 30s # Or via env variable (overrides config.json; put in dotfiles/envrc): # export TELEGRAM_PROXY="https://t.me/proxy?server=HOST&port=PORT&secret=SECRET" # Remove the configured proxy tgcli config unset proxy --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": 1. Resolve chat: - `tgcli channels list --query "<name>" --json --timeout 30s` - optionally `tgcli groups list --query "<name>" --json --timeout 30s` 2. Ensure archive flow: - `tgcli channels sync --chat <id> --enable` - `tgcli sync jobs add --chat <id> --depth 500` - `tgcli service status --json --timeout 30s` — check if running - `tgcli service install --json --timeout 30s` — if not installed yet - `tgcli service start --json --timeout 30s` — start daemon 3. Read archive first: - `tgcli messages list --chat <id> --source archive --limit 500 --json --timeout 30s` 4. If archive is still empty, fallback to live: - `tgcli messages list --chat <id> --source live --limit 500 --json --timeout 90s` 5. 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. 1. Enable sync for each channel: - `tgcli channels sync --chat <id|@username> --enable --json --timeout 30s` - repeat for each channel to monitor 2. Add backfill jobs (optional, pulls history): - `tgcli sync jobs add --chat <id|@username> --depth 1000 --json --timeout 30s` 3. Start the background daemon: - `tgcli service install --json --timeout 30s` — first time only - `tgcli service start --json --timeout 30s` 4. Verify it's running: - `tgcli service status --json --timeout 30s` - `tgcli sync status --json --timeout 30s` — shows per-channel sync progress 5. Check for errors: - `tgcli sync jobs list --status error --json --timeout 30s` - `tgcli sync jobs retry --all-errors --json --timeout 30s` 6. 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 exit - `tgcli 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.
More General & Other skills
find-skills
vercel-labs/skills
Helps users discover and install agent skills when they ask questions like "how do I do X", "find a skill for X", "is there a skill that can...", or express interest in extending capabilities. This skill should be used when the user is looking for functionality that might exist as an installable skill.
grill-me
mattpocock/skills
A relentless interview to sharpen a plan or design.
grill-with-docs
mattpocock/skills
A relentless interview to sharpen a plan or design, which also creates docs (ADR's and glossary) as we go.

