Skip to main content

telegram-tools

Site: cli-tools-site.vercel.app

A command-line tool for your own Telegram account. Find the real IDs of your chats and forum topics, search and export messages, keep an archive you can search offline, send and schedule messages, and run your groups — admins, members, invites, topics, settings — from a menu, a terminal or a script.

The telegram-tools menu: 1 Find IDs, 2 Read, 3 Write, 4 Build, 5 Clear messages, 6 Manage, 7 Watch, 8 Identity, 9 Check setup, 0 Exit

Run telegram-tools with no arguments and that is what you get. Try it before you install: the website lets you click through the real menu in your browser, and its guide goes further into most commands.

The tool also empties a forum topic without deleting the topic, the one job the Telegram app won't do.

Everything runs on your machine with your own API key: no server, no third party, nothing leaves your computer except the Telegram calls you asked for and the downloads you approve. Built on Telethon.

Install

pipx install telegram-tools
# or
uv tool install telegram-tools
# or
pip install telegram-tools

Needs Python 3.11+, and uv downloads one for you if it's missing. pipx and uv keep the tool in an environment of its own; pip installs it into whichever one is active.

The newest version reaches GitHub before PyPI:

pipx install git+https://github.com/banozz0/telegram-tools.git
# or
uv tool install git+https://github.com/banozz0/telegram-tools.git

Two optional extras: proxy to connect through a proxy, and qr to log in by QR code — pipx install 'telegram-tools[proxy,qr]'. Without its extra, a command that needs one refuses instead of quietly doing without.

Set up (once, about two minutes)

The tool signs in as you, not as a bot, so it needs your own Telegram API key:

  1. Log in at https://my.telegram.org/apps with your phone number.
  2. Create an application — any name works; platform "Desktop".
  3. Save its api_id and api_hash, and treat the hash like a password:
mkdir -p ~/.telegram-tools
cat > ~/.telegram-tools/.env <<'EOF'
TELEGRAM_API_ID=123456
TELEGRAM_API_HASH=your-api-hash-here
EOF

Then log in and check the setup:

telegram-tools auth       # your phone number, then the code Telegram sends
telegram-tools doctor     # says what's missing, and never prints a secret

auth --qr logs in by scanning a code with a phone that's already signed in (Settings → Devices → Link Desktop Device). A two-step-verification password is asked at the prompt and stored nowhere. Environment variables and a .env in the current directory also work, and win over ~/.telegram-tools/.env.

Quick start

telegram-tools                                    # no arguments: the menu
telegram-tools discover                           # your chats and topics with their real IDs (--all for every chat)
telegram-tools search --chat @mygroup --keyword deploy
telegram-tools search --chat @mygroup --topic 141 --output topic-141.json    # or --format csv|jsonl|markdown|html
telegram-tools archive sync                       # a local copy of everything you can read...
telegram-tools archive search --query "deploy AND green"                     # ...searched offline
telegram-tools send --chat -1001234567890 --topic 141 --text "deploy is green"   # shows it, then asks y/N
telegram-tools clear-messages --chat @mygroup --topic 141                    # dry-run; --execute to delete

Every command has --help with all of its flags.

The menu

Run telegram-tools with no arguments and you get the nine rows pictured at the top; once it has connected, the line above them names the account it acts as. Every command has a row, so you never need to remember a flag. You pick chats, topics and bots from live lists instead of typing IDs, and 0 steps back. The menu asks exactly what the commands ask, and has no --yes at all.

What it can do

Command What it does
discover Lists your chats, channels and forum groups with their numeric IDs, and every forum topic's ID.
search Finds messages in one chat by text, sender, date or topic. Prints a table, or exports JSON, CSV, JSON lines, Markdown or HTML. --archive answers from the local archive, offline.
archive A local, full-text-searchable copy of everything your account can read. sync resumes where it stopped, and sync --full also marks what was deleted since; search, export and status never connect; retention and forget prune it.
review Links and files the archive saw, waiting for you — the only way anything is ever downloaded. You approve a fetch, it lands in quarantine through eleven checks — the last a local ClamAV, if you have one — and you accept or reject it.
send Posts text, files or both to a chat or one forum topic, optionally as a reply.
message What a message's long-press menu does: reply, edit, delete, forward, copy, react, pin, poll, typing, mark a chat read or unread, bookmark, draft — and pins lists what a chat has pinned.
create, delete Make or remove a supergroup, a broadcast channel or a forum topic. delete removes only what create can make again.
clear-messages Empties forum topics and keeps the topics and their IDs.
leave Takes your account out of a group or channel. Nothing in it is deleted.
structure A chat's shape as a file: export a blueprint (topics, default rights, slow mode — never people or messages), diff it against another chat, apply it.
admin, member, join-requests, invite, settings Running a group: admins and their rights; bans, kicks, mutes and restrictions; join requests; invite links; a chat's or a topic's settings.
folders Your chat folders — the tabs above your chat list: list, create, edit, delete.
watch Rules over live events — alert, tag, bookmark, archive, queue for review, never download or change anything — and the foreground runner that fires them. An alert's destination answers to your send allowlist, checked when the rule is written and again when it fires.
schedule Messages posted later. send --at is server-held: Telegram posts it even with your machine off. schedule post is runner-held: watch run posts it, only while it's up — and it is the only way to repeat one. Because that post goes out with nobody watching, the chat has to be in your send allowlist before the schedule is written.
bots The bots you own, and what @BotFather edits: name, bio, description, commands, photo, default admin rights.
auth, profiles Log accounts in and out, list them, remove one.
doctor Checks your setup without printing a secret.
skill install Copies the agent skill this release ships into your agent's skills folder.

What it won't do (on purpose)

  • Download anything you didn't approve. A sync notes links and files and fetches none. A download needs your y/N at a terminal, then runs eleven checks in quarantine — scheme, every redirect, private-network addresses, file path, size, time, archive bombs, type against magic bytes, checksum, duplicates, and the scanner — and needs a second y/N to keep. No rule, schedule or --yes can do either step.
  • Call a file clean because nobody looked. The only scanner is a local ClamAV; without one, the verdict is UNSCANNED.
  • Run in the background. watch run is a foreground process you start and stop. Nothing installs a service.
  • Copy people or history. A blueprint carries a chat's structure — never members, admins, messages or invite links.
  • Manage bot accounts. Creating or deleting bots, a bot's @username and its token stay with @BotFather. bots edits settings and never runs a bot.
  • Use a cloud. Credentials, sessions, the archive and the audit log stay in ~/.telegram-tools/.

Safety model

How much a command asks before it acts depends on how hard its change is to undo:

Kind of command What it asks before acting
Reads — discover, search, archive search, every list, show and status, doctor Nothing.
Changes — send, the message verbs, create, bots, settings set, admin, member, join-request, invite and folder changes, skill install A preview, then y/N.
Hard to undo — clear-messages, message delete, delete, leave, member ban and kick, admin demote, settings set --forum off, folders delete, structure apply, archive retention and forget A dry-run by default. For real: --execute and typing a confirmation — DELETE, or the exact title or name of what you're touching. No --yes.

--yes answers the y/N in advance, for scripts. On send and the message verbs it works only for a chat in your send allowlist, and there, as on create and bots, it skips the preview too; the admin, member, join-request, invite and folder changes and skill install still print theirs. It doesn't exist on auth, profiles remove, settings set, schedule post, or the review queue's approve, accept and reject.

Whichever row it's in, every write:

  • Says who's acting, on what. Every command opens with the account and the target: Acting as: Sven (@sven) · account · Target: Agency › 💻 Deploys (-1001234567890).
  • Checks your rights first. Before a write to a chat, it asks Telegram what your account holds there, and refuses by name when a right is missing.
  • Re-checks the target after you answer. A chat renamed or replaced in the meantime refuses, instead of acting on whatever holds the name now.
  • Reads back the result. A Read back: line says what it found afterwards, or unverified: and why. On most writes an unverified readback still reports ok — leave and structure apply report partial — so a script should check evidence.readback.
  • Logs it. One line per executed write goes to ~/.telegram-tools/audit.jsonl, from the menu too. No token, phone number or API hash can reach it, or any envelope or error message.
  • Guards its own files. Sessions are 0600 in 0700 folders, and every write refuses while anything in ~/.telegram-tools but exports/ is readable by others; doctor prints the chmod that fixes it.

Command by command: the guide's safety section, and each command's --help.

More accounts, bots and options

More than one account

telegram-tools --profile work auth        # log a second account in
telegram-tools --profile work discover    # act as it: the flag goes before the command
export TELEGRAM_TOOLS_PROFILE=work        # or make it this shell's default
telegram-tools profiles                   # which accounts this machine is logged in as

Each profile keeps its own session under ~/.telegram-tools/profiles/<name>/. auth --logout ends one after you type its name. All profiles share one archive: each message records the account that synced it, and --identity tg:user:ID narrows an archive search, export or status to one.

Posting as one of your bots

Store each bot's token under a nickname you choose, then put --as-bot NICK before the command:

# in ~/.telegram-tools/.env
TELEGRAM_BOT_TOKENS=mybot:12345:AAExampleToken,alerts:67890:BBExampleToken
telegram-tools --as-bot alerts send --chat -1001234567890 --topic 141 --text "deploy is green"

Every screen then names both identities: Acting as: @alertsbot · bot (via Sven (@sven)). A bot can send (not --at), create topic, use most message verbs, run the admin commands where it's an admin, leave and watch; anything else refuses before connecting. The same tokens let bots make the three edits only a bot can: its commands, removing its photo, and its default admin rights. The tool only reads tokens — it never writes or prints one.

Sending without the prompt

--yes skips the y/N, and nobody sees where the message goes, so it only works for destinations you named in advance:

# in ~/.telegram-tools/.env
TELEGRAM_SEND_ALLOWLIST=-1001234567890:141,-1009876543210,@myalerts

Each entry is a chat ID or @username, optionally :topic-id for one topic. Unset, every --yes send is refused. The same list covers the message verbs, the alerts a watch rule sends, and schedule post — which has no --yes at all, but hands the runner a message to post hours later with nobody there, so it refuses a chat off the list while you are still at the keyboard to read why. watch rules add and edit refuse an --alert-to for the same reason, with one honest limit: a rule is written with nothing connected, so its rid is never resolved into a chat. An ID on the list settles it either way; an entry naming that chat by @username cannot be read against a rid at all, so the rule is written, the command names the entries it could not decide, and the runner settles it when the alert fires.

Through a proxy

Add TELEGRAM_PROXY=socks5://127.0.0.1:1080 to the .env (socks5, socks4 or http, optionally with user:password@). It needs the proxy extra; without it the command refuses rather than connect from your own address.

Typing a time

A time with no offset is this machine's local time, in every flag and prompt that takes one; a trailing Z or an offset like +05:00 always wins. Previews echo the moment with its offset, and everything written for machines — --json, exports, the archive, the audit log — stays UTC.

For scripts and agents

Put --json before the command and it prints exactly one JSON object on stdout; tables, previews and prompts move to stderr. --jsonl streams one line per record first.

telegram-tools --json discover
telegram-tools --json send --chat -1001234567890 --topic 141 --text "deploy is green" --yes

The object carries a status (ok, empty, partial, dry_run, cancelled, refused, failed), the result, the identity and target the run acted on, and on a refusal a stable error.code, with an error.hint naming the command or edit that fixes it when there is one.

Exit Meaning
0 done — ok, empty, dry_run
1 not done — cancelled, declined, or partial
2 refused — usage, config, permission, a platform error
3 needs a person — the command asks for confirmation and there is no terminal to ask on
130 interrupted

Under --json, a command that needs an answer and has no terminal to ask on exits 3 with APPROVAL_REQUIRED instead of waiting, and error.hint is the command for a person to run. --yes answers only a y/N, and only where the Safety model says it does. skill/SKILL.md is a ready-made agent skill: every command, field and rule an agent needs.

The package carries the skill that matches its own version, and one command puts it where Claude Code loads skills from, ~/.claude/skills/telegram-tools:

telegram-tools skill install

It shows the file and both versions and asks y/N; an identical copy asks nothing, and before your first auth it installs unsigned, with a warning and no audit line. --dir names another agent's folder (--dir ~/.codex/skills/telegram-tools), and --yes answers for a script. Run it again after you upgrade — an installed copy does not update itself, and doctor says whether yours is current. A version before 3.38.0 has no skill install; for one of those, or for the skill on main, fetch the file:

mkdir -p ~/.claude/skills/telegram-tools
curl -fsSL https://raw.githubusercontent.com/banozz0/telegram-tools/main/skill/SKILL.md -o ~/.claude/skills/telegram-tools/SKILL.md

Where your files live

Everything is in ~/.telegram-tools/: the .env, one folder per login under profiles/, the archive (archive.sqlite), the review queue's quarantine/ and media/, exports/, watch rules/, config.json and the audit.jsonl log. Nothing is uploaded anywhere.

Status

Used regularly by its author, and still growing — see the changelog. This is a solo project whose code was written by AI agents under review: issues are welcome, fixes are best-effort, and there is no support promise. Before contributing, read CONTRIBUTING.md.

License

MIT. See LICENSE.

Metadata

Release files for telegram-tools 3.39.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for telegram-tools 3.39.1
File Size Uploaded
telegram_tools-3.39.1.tar.gz 799.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for telegram-tools 3.39.1
File Interpreter ABI Platform
telegram_tools-3.39.1-py3-none-any.whl Python 3 none any Details

Total release size: 1.2 MB

Release files / telegram_tools-3.39.1.tar.gz

Download URL telegram_tools-3.39.1.tar.gz
Size 799.8 kB
Tags Source
SHA-256 checksum
How to use checksums
1b3c9bac01435ea0abe4780406fc7764440b7a51acb33da0bf7f1d5cc74201f4
BLAKE2b-256 checksum
How to use checksums
5b9dd5855b4bcbbfe4cccf8ceab40817ede5a345ba96f57f1f5a3f734cfc9452
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.13

Release files / telegram_tools-3.39.1-py3-none-any.whl

Download URL telegram_tools-3.39.1-py3-none-any.whl
Size 434.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
4eea04afa493607ad4f97b8807876258d9ad4533a210f5aa7ffc37d8a9e8f1cb
BLAKE2b-256 checksum
How to use checksums
21dcb2256b0f3d9f5fb40b6456d42289b068d300d315086d18798f460284d5f8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.13

Release history Release notifications | RSS feed

3.40.0

2 release files

This release

3.39.1 This release

2 release files

3.36.0

2 release files

3.35.0

2 release files

3.34.0

2 release files

3.6.0

2 release files

3.4.1

2 release files

3.4.0

2 release files

3.3.0

2 release files

3.2.0

2 release files

3.1.0

2 release files

3.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page