Changelog
Notable changes to @leemour/tg-cli. One section per version, newest first; versions follow
semantic versioning, so before 1.0.0 the command interface may still change.
Unreleased
What's new
tg bot messages send|list|show|edit|delete|pin|unpinandtg bot chats show|leave|action— the bot writes to a chat by id or title, or to a person asuser:<id>, with--md,--html, a file or a photo. Telegram gives a bot no history, solistandshowanswer from what this bot sent and received on this computer. A delete asks first;--allow-dangerousanswers.- Your own AI agent can link a group's conversations, when you ask it to:
tg skill show link-conversationsis its guide. It says how much text it would read and waits for your yes, then answers the chat a batch at a time (tg conversations batches next,tg conversations links add);tg conversations links cleardrops its answers. tg calls no model itself. See the archive.
0.21.0 — 01.10.2026
What's new
tg bot— a Telegram bot, through the official Bot API and its token:bot auth set|show|remove,bot list [--check],bot chats list,bot recipients list|add|remove|clearandbot sends list, the same commandsmax bothas. Several bots, each under its own name; the token lives in the keyring asbot:<name>, or inTG_BOT_TOKEN. See the bot page.tg conversations batches status|next --chat <chat> [--size <n>]: a group chat in batches for your own AI agent to link into conversations.statussays how many messages and batches are left before you start;nextprints the next batch. tg itself calls no model.tg skill install [--for claude|agents|all]writes tg's guide for AI agents where Claude Code and other agents look for it. When an agent runs tg and no copy is installed, tg says so once a day on stderr;tg config set skillHint false --defaultsturns that off.tg store clear --leftdeletes the chats you have left from the local store, with their messages. It asks for--allow-dangerousand otherwise says how much it would delete.tg conversations build|list|showandtg messages links, with the MCP toolstg_conversations_listandtg_conversations_show: the conversations inside a group, found in the stored messages by replies, mentions and who wrote next — no Telegram request, no AI. Nothing is built until you runbuild. See the store.- A mention by name is kept: when someone is mentioned by name rather than by @username, the stored message remembers whom, so conversations follow it.
tg chats rules show|set|unsetandtg chats moderate, with the MCP toolstg_chats_rules_showandtg_chats_moderate: a group's rules say what to look for — links, invite links, forwards, floods, blocked people — and how far a run may go: deny, report only, ask (the default), or act. Nothing runs in the background. See groups.tg messages list --before-timereads back from a moment: ISO 8601, or2h/1dago.tg contacts add|remove|block|unblock|rename|importandtg account update,tg account sessions end --others, with the MCP toolstg_contacts_add|remove|block|unblock|renameandtg_account_update.contacts importreadsnumber, namelines from a file and prints only counts and who Telegram knew. Ending other sessions logs your phone out too: it asks first, and no agent is ever offered it.tg chats folders list|create|update|delete, with the MCP toolstg_chats_folders_list|create|update|delete. Changing a folder's chats keeps the others in it; "All chats" is not listed, since nobody can change it.tg chats members add|removeandtg chats admins add|remove, with the MCP toolstg_chats_members_add|removeandtg_chats_admins_add|remove.--cantakes members, admins, info, pin, link, post, edit and delete; Telegram has no separate right to read. Adding answers who could not be added; each person added counts toward the hourly limit.tg chats update <chat>—--title,--description,--all-can-pin on|off,--only-admins-add on|off— andtg chats link show|reset, with the MCP toolstg_chats_update,tg_chats_link_show,tg_chats_link_reset.tg chats showadds a group's description, invite link and settings.tg chats create <title> [person...],tg chats join <link>,tg chats leave <chat>, and the MCP toolstg_chats_create,tg_chats_join,tg_chats_leave. A new group is always a supergroup (--channelmakes a channel); people who cannot be added are listed in the answer. See usage.- Permissions: one level per command, for you and for an AI agent alike. A profile's
permissionssetting gives each command path a level:deny(not even reading),readonly,askorallow; the most specific key wins —tg config set permissions.messages.delete allow. By default everything is allowed except deleting messages and ending other sessions, which ask.askasks y/N in the terminal;--allow-dangerous(deleting) or the new--yes(any other write) says yes in a script.readOnlyandallowstill work. See security. tg messages send --voice <file>sends an Ogg Opus file as a voice message, and a.mp4or.movgiven with--filenow plays in the chat as a video;--as-filekeeps it a file to download.tg messages list --mark-readmarks the chat read up to the newest message shown. Nothing else that reads marks anything read.--modelbeside--transcribeontg messages listandtg inbox, andtg review --transcribe: voice messages in a review come with their text.tg store fetch --last <n>stops once the newest n messages of the chat are held, so a later run with the same--lastasks Telegram for one page and stops.tg polls create --revotelets people change their vote.tg store export --output <file> --since-time <time>. The export goes into a new file only you can read, never over one, and can start from a time.tg account showprints the phone's last four digits, and the whole number with--show-phone. The MCP tooltg_account_showalways prints only the last four.tg messages forward --send-id. A forward that got no answer is repeated with the send id from the error, and Telegram keeps one copy, as with a send. The--jsonanswer carriessendId; MCP'stg_messages_forwardtakessend_id.tg messages edit --mdformats the new text asmessages send --mddoes; MCP'stg_messages_edittakesmarkdown.- Looking after the message store:
tg store info,check,migrate,backup,restore.infosays wheremessages.dbis, its size, its schema and how many rows it holds.checkreports whether it is healthy — integrity, foreign keys, the search indexes, free disk — and names every chat whose stored history stops before the chat's newest message; it repairs nothing.migratebrings the file up to this version and normalizes the messages stored before it.backup <file>copies the store while it is in use, readable by you alone, never over a file.restore <file>puts a backup in place and keeps the store it replaces beside it; it refuses whiletg serveruns or any process has the store open. The same file serves max-cli, so restart any runningserveormcpof either CLI afterwards. - Every write has its own id,
operationId. A send, edit, forward, deletion, pin, reaction, mark-read and poll vote prints it in its--jsonanswer and MCP result, and the send journal and--tracename it, so one write can be followed from the answer to the log. A send'soperationIdis itssendId. - About 16 MB less to install: cli-messaging 0.60.0 bundles its database layer instead of depending on it.
Changed — may break scripts
tg server status --jsonanswers the fields both tools share:sinceisstartedAt,listeningisconnected,listeningSinceisconnectedAt; new arecliVersion,log, andstalewhen aservethat is gone left its lock behind.tg server startanswersstartedAtandconnectedAtthe same way, andtg server stopsays who had started it (by). The lines say "connected" where they said "listening".tg messages send --atis now--at-time, as every option that takes a time names it.- The MCP tools' arguments carry their option's name:
tg_messages_listtakesbefore_id,before_time,after_id,after_time;tg_messages_contextbefore_n,after_n;sinceissince_timeintg_inbox,tg_reviewandtg_chats_events, whoseeventistype;tg_messages_sendtakesmdandat_time. - Options name the kind of value they take. The old names are refused as unknown options; there
are no aliases. The MCP tools' arguments do not change.
tg messages list --beforeis now--before-id;--afteris--after-idfor a message id and--after-timefor a time, so an id is never read as a time.tg messages context --beforeand--afterare now--before-nand--after-n.--sinceis now--since-timeintg inbox,tg review,tg chats eventsandtg store fetch.tg messages download --outputis now--output-dir.tg chats events --eventis now--type.
tg review --unansweredtakes a duration —4h,1d— not bare hours;--unanswered 4is refused. Without a value it is 24 hours, as before. MCP'stg_reviewstill takes hours.tg chats events --jsonprints{ items, page, limit, hasMore, chatId, since }:eventsmoved toitemsandmoretohasMore.tg server logs --jsonmovedlinestoitems.--jsonlis unchanged.- A
.mp4or.movsent with--fileplays in the chat as a video; it arrived as a file before. Add--as-fileto keep it a file to download. tg mcpoffers tools by the profile's permissions, not by flags. With the default settings an agent can now send, edit, forward, react, vote and mark read without--allow-send, and without a form; deleting shows you a form first (tg mcp --allow-dangerousskips it). To keep an agent read-only, give it a profile withreadOnly— mcp shows how.--allow-send,--allow-mark-readand--allow-deletedecide nothing now and print a warning;--confirm-sendstill shows every write in a form.tg messages deleteasks in the terminal when--allow-dangerousis missing, instead of refusing; with no terminal it is refused as before.tg store fetch --max <n>is gone;--limit <n>caps a run instead, in messages (1000 by default, as before), and--page-size <n>sets how many one request asks for (100 by default). The same names as max-cli's.--maxis not kept as an alias.- A poll made without
--revoteno longer lets people change their vote, as in max-cli; Telegram allowed it by default. Add--revoteto keep the old behaviour. tg polls voteandtg polls close --jsonprint{ operationId, poll }instead of the poll alone; read the poll from.poll. The MCP toolstg_polls_voteandtg_polls_closeanswer the same.tg runs list,tg sends listandtg recipients list --jsonprint{ items, page, limit, hasMore }instead of a bare array, as every other list does; read the rows from.items.--jsonlis unchanged.
Fixed
-
tg chats listno longer lists a pinned chat twice. With archived chats included, Telegram's pages brought the pinned chats again further down; on one account 8 of 1361 chats appeared twice. A pinned chat's title also matched itself as two chats, so typing it could be refused as ambiguous. -
tg server stopand Ctrl-C endserveandwatchcleanly. The serve went down before it could clean up, sotg server statusreported a leftover lock (stale) after every stop. -
tg serverin a development checkout leaves the installed tg's systemd unit alone. A checkout with its ownTG_STATE_DIRor store gets a unit of its own name; the installed tg keepstg-serve-<profile>.service. -
A chat you have left no longer shows in
chats list --offline. It drops out the next timetg chats listreads your whole chat list; its messages stay untiltg store clear --left, and a chat you rejoin comes back. -
Two refusals say what to do. Adding back someone who left or was removed, when you are not each other's contacts, now says to send them the invite link (
tg chats link show <chat>); naming a person by an id this account has never seen now says to use an @username, or to read a chat they are in first. -
An argument Telegram's library refused no longer repeats what you typed. The error said the library's own words, which could quote a chat's title or a link. It now says what kind of input was wrong where tg can tell — a chat you have not joined, a message or invite link, a phone number, a login code or password — and otherwise that Telegram refused an argument.
-
A conversation reads in English. Your own messages are
you, and day headings read26 September 2026; they were Russian. -
A chat or message tg cannot find is
not_found, and a chat of the wrong kind for the command isvalidation_error. They were an unknown failure with exit code 1 and the library's own words, which could repeat a chat's title. -
The "not logged in" error names your profile:
tg <profile> session start, as the other login hints already did. -
Downloads and exports get your usual file permissions again. Since the first release, opening a session made every file tg wrote afterwards readable only by you. The session file and its companions stay owner-only.
0.20.0 — 30.09.2026
What's new
- A message's sender keeps their @username in the local store, so
--from @nameand the coming conversation view can match a mention to the person. Takes effect with cli-messaging 0.57.0 or later; history already downloaded gains it the next time it is fetched. tg store fetch <chat> --since <time>stops once it reaches messages older than the time:2026-09-01, or2h/1dago.
Changed — may break scripts
Commands follow one naming standard: a noun, then a verb. The old names are gone, with no aliases — a script that uses one now fails with "unknown command" or "unknown option".
tg export <chat>istg store export <chat>,tg sync status [chat]istg store status [chat],tg backfill <chat>istg store fetch <chat>, andtg backfill list|status|cancelistg store jobs list|show|cancel.store fetchfetches by default;--estimateonly estimates.--paceis--pausethere and intg messages download --all.--maxkeeps its name: it counts messages.tg messages replyis gone:tg messages send <chat> [text] --reply-to <id>answers a message, and every send option (--file,--photo,--silent,--at, …) now works with it. Themsg:telegram/…form has no replacement; give the chat and the message id.tg chats readistg chats mark-read; the MCP tooltg_chats_readistg_chats_mark_read.tg recipients offistg recipients clear.tg update [--check]istg upgrade [--check], and the daily line about a newer version namestg upgrade.tg messages search <words…>names its argument<text…>; the search is unchanged.
0.19.0 — 30.09.2026
Fixed
- tg always exits once a command has finished. Once, a download printed its answer and then stayed
running for half an hour,
--timeoutor not. If anything is still open five seconds after a command is done, tg now names it on stderr and exits with the command's own exit code. Output still being written is waited for.
0.18.0 — 30.09.2026
Fixed
- A supergroup or channel first seen through one of its messages no longer loses messages to a deletion
in a private chat (cli-messaging 0.54.0). 0.16.0 left such a chat exposed because the store did not know
its kind yet; its
-100…id now says enough. - Messages a deletion elsewhere marked deleted by mistake come back the next time their chat is read
(
messages list,messages context, or an edit arriving live). A deletion newer than the read stays.
0.17.0 — 30.09.2026
What's new
tg messages download <chat> --allsaves every file of a chat — photos, documents, videos, voice notes — into--output, newest first. Cut short by--timeoutor Ctrl-C, it continues where it stopped the next time, and picks up newer messages too; where it got to is kept in a.download-<chat>.jsonbeside the files. Telegram's "wait N seconds" is sat out up to five minutes, and--pace(1 s) spaces the pages. A file name another message already took gets the message id in front; nothing is overwritten. (cli-messaging 0.53.0)
0.16.0 — 30.09.2026
Fixed
- A message deleted in a private chat or a basic group no longer marks other chats' messages deleted (cli-messaging 0.52.0). Telegram reports such a deletion without the chat, and the local store marked every stored message with that number deleted — channel and supergroup messages included. Messages already marked that way stay marked; their text is kept.
0.15.0 — 30.09.2026
Fixed
- A speech model on this machine no longer drops quietly spoken words. A quiet stretch in the
middle of a voice message was taken for silence and left out of the text; now it is heard, by
Parakeet and GigaAM alike. Voice messages a local model heard before are heard again the next time
--transcribeasks for them; Telegram's transcripts stay. (cli-messaging 0.51.0)
0.14.0 — 30.09.2026
What's new
Changing messages other people see — each through the send guard, as messages send is: a
read-only profile refuses, allow must name the permission, the recipient list and the hourly limit
apply where they count, and tg sends list records it without the text.
tg messages edit <chat> <id> [text]: the new text of your own message. Repeating the same edit changes nothing.tg_messages_editwithmcp --allow-send.tg messages forward <chat> <id> --to <chat> [--silent], checked against the chat it goes to. After an unknown outcome, look in that chat before forwarding again.tg_messages_forward.tg messages pin|unpin <chat> <id>, quiet unless--notify; in a one-to-one chat the pin is on your side only.tg_messages_pinandtg_messages_unpin.tg reactions add <chat> <id> <emoji>andtg reactions remove <chat> <id>; a reaction never counts toward the hourly limit.tg_reactions_addandtg_reactions_remove.tg chats read <chat> [--until id]marks a chat read — the other side sees it. Its tool,tg_chats_read, comes only with the newtg mcp --allow-mark-read, which--allow-senddoes not turn on.tg messages delete <chat> <id…> --allow-dangerous [--for-everyone]: at most 10, for you only unless--for-everyone, and nothing without--allow-dangerous. In a supergroup or a channel Telegram has no "for me only", so there it needs--for-everyone. The newtg mcp --allow-deleteofferstg_messages_delete, which only ever deletes your own copy.tg polls show|vote|close|create: a poll with its answer ids, a vote by those ids (never by position) or--retract, closing your own poll, and a new one — public unless--anonymous, with--send-idfor a safe retry.tg_polls_showreads;tg_polls_vote,_closeand_createcome with--allow-send.
0.13.0 — 30.09.2026
Changed — may break scripts
- The shared message store moves to version 6 (cli-messaging 0.49.0). The first
tgrun upgradesmessages.db; amaxolder than the one released the same day then refuses it and asks to be upgraded —npm install -g @leemour/max-cli@latest. Nothing intg's own commands changes.
0.12.0 — 30.09.2026
What's new
tg chats inspect <link>andtg_chats_inspect: what an invite or public link leads to — title, members, description, whether you are in it and whether joining needs approval — without joining.tg topics list <chat>andtg topics search <chat> <text>, andtg_topics_list: a forum group's topics, paged, with the id each message in a topic carries asthreadId.
0.11.0 — 30.09.2026
What's new
- Voice messages carry their text in
tg messages listandtg inbox. A transcript heard once is kept per profile in tg's cache and shows on every later read —transcriptin--json,🎤 …under the text for a person.--transcribehears the rest, by Telegram or the model on this machine, within two minutes for the whole list; what is left is inunheard. The same astranscribeontg_messages_listandtg_inbox. tg chats members list <chat>andtg_chats_members: a group's members, paged, each with a role and when Telegram last saw them — up to Telegram's own 10 000.tg contacts lookup: who has a phone number, where their privacy lets you find them. The number is piped in or typed when asked, never an argument. Alsotg_contacts_lookup.tg contacts sync: your Telegram contacts into the local store, answering how many were new or changed.tg account sessions listandtg_account_sessions: every device and app logged in to the account, without their IP addresses. It ends nothing.
0.10.0 — 29.09.2026
What's new
-
Voice to text on this machine.
tg models audio listandtg models audio download <id>fetch a speech model once — Parakeet v3 (25 languages, the default), GigaAM v3 or GigaAM v3 CTC (Russian) — into~/.cache/cli-common/models/audio, a folder every CLI of the family shares.tg messages transcribeasks Telegram first and falls back to the local model when the account has no Premium;--localor--model <id>skip Telegram. The profile'stranscribeWith(auto,messenger,local) andspeechModelset the defaults. Nothing downloads a model by itself. -
tg messages send --photo <path>or--file <path>, the text as the caption, andphotoandfileontg_messages_send. Hidden files and folders,~/.ssh, tg's own folders and the message store are refused unless the owner adds--allow-any-file; over MCP there is no way around it. The send journal records the attachment's kind and size, never its name. A retry with the same--send-idsends one message (measured on a photo). -
tg updaterestarts a running server with the new tg, so it stops running the old code; a serve started by hand is named, for you to restart.tg server statussays when the running serve is older than tg, as max-cli's does. -
tg chats events <chat> [--since] [--event]andtg_chats_events: who joined, left, was added or removed, and by whom — plus a chat created, renamed or a message pinned — from the chat's service messages, seven days back by default. At most ten pages of history a run;moresays there was more.
0.9.0 — 29.09.2026
What's new
tg session startsays who logged in, where the session file is, where the app keys are read from and what to run next, in sentences;--jsongainssessionandappKeys(environment,keyringorfile— never the keys).tg chats list --search <text> --kind <kind> --unread, and the same ontg_chats_list. The filters combine over the newest 200 chats;--searchtakes at least 3 characters.tg messages list --after <id-or-time>reads a chat forward: the oldest messages newer than a message id, or than a time (2h,1d, ISO 8601).afterontg_messages_list.tg messages send --silent --no-preview --md— without a notification, without a link's preview card, and with**bold**,_italic_,~~struck~~and`code`as Telegram formatting. The MCP send tool takessilent,no_previewandmarkdown. The send journal still holds only the length.tg messages send --at <time>hands the message to Telegram to send later —2h,1d, or2026-10-01T09:00in local time — andtg messages scheduled <chat>(MCPtg_messages_scheduled) lists what waits. A scheduled send is never repeated:--send-idis refused with it.
Changed — may break scripts
tg service …is nowtg server …—start|stop|restart|status|logs|install|uninstall, as in max-cli — andtg serve statusis gone:tg server statusanswers.tg server startwithout a unit runs serve in the background. A unit written bytg service installis still found. From cli-messaging 0.40.0.
0.8.0 — 29.09.2026
What's new
tg review: every message, yours too, in each chat that changed since--since(three days without it) — for sorting out who owes what. It ends by saying where the next review starts.--chatreads one chat,--unanswered [hours]keeps the questions nobody answered — a group's admins answer for it too — and--alltakes in muted and archived chats. The MCP tooltg_reviewand thereviewprompt do the same.
0.7.0 — 29.09.2026
What's new
tg messages transcribe <chat> <id>and the MCP tooltg_messages_transcribeturn a voice or video note into text with Telegram's own recognition — on a Premium account, or within Telegram's weekly free trial. Telegram usually needs a few seconds; tg asks again for up to a minute, then answers"pending": true. Refusals say why in plain words: not a voice message, too long, no Premium.- The MCP tool
tg_messages_photohands an agent a message's photo as an image to look at, up to 512 KB. A larger photo, a file, a video or a voice note is refused with thetg messages downloadcommand that saves it.
0.6.0 — 29.09.2026
What's new
tg inboxleaves out muted and archived chats unless they mention you or reply to you;--all(andallontg_inbox) shows them too. On a busy account most unread chats are muted, and they took the 20 chatsinboxreads at once. The JSON'squietcounts what was left out.- A chat carries
muted,archivedandunreadMentionsin--json.archivedmoved out ofproviderMetadata;mutedis absent when the chat follows the account's default.
Fixed
tg messages send --silent,--no-previewand--markdownrefuse the send instead of sending without them: they came with cli-messaging 0.32, and tg does not carry them to Telegram yet.
0.5.0 — 29.09.2026
What's new
tg service install|uninstall|start|stop|status|logsrunstg serveas a systemd user unit (Linux) or a launchd agent (macOS), one per profile.installonly writes the file; nothing starts untiltg service start.tg backfill <chat> --backgroundruns a backfill as a job that outlives the command;tg backfill list,status [job]andcancel <job>follow it. Ctrl-C orcancelstop a backfill after the page in hand, and it keeps that page.tg backfill <chat> --estimate— how many messages, requests and seconds a full backfill would still take, from the store; it asks Telegram nothing.tg export <chat> --format markdown— a chat as a transcript a person reads.tg messages search --regex '<pattern>'— a regular expression over the stored text.tg doctor report createwrites a problem report — versions, paths, the failed run, the recent send attempts — with no message text, and every chat, message and account id replaced by a label.tg session start --qr-file login.pngwrites the login QR code as a PNG instead of drawing it, so an agent can pass it on, and removes it after the login. With the app already stored it needs no terminal.tg messages download <chat> <id> [--output dir]saves a message's photo, file, video or voice note into a folder — the current one unless--outputnames another — and answers its path and size. A name the sender chose cannot leave the folder or hide the file, and a file already there is never overwritten. The message is fetched again each time, so an old one still downloads.
Fixed
tg messages list --jsonlandtg messages search --jsonlprint one message per line, as their--helpsays. They printed the whole page as one JSON line; a script that read.itemsfrom it must now read each line as a message.
0.4.0 — 29.09.2026
What's new
tg inbox— other people's unread messages in every chat;--newshows only what arrived since the last check, each message once. The MCP server offers it as thetg_inboxtool and thecatch-upprompt.tg skill showprints the instructions an agent is given for this tool.- MCP prompts and a chat resource: the
replyandfindprompts, andtg://chat/{id}.
0.3.0 — 28.09.2026
What's new
tg mcpserves a profile to an agent over MCP, on stdin and stdout. Read-only by default;--allow-sendoffers the send tool, and--confirm-sendshows the owner every send first.tg mcp configprints the entry for an MCP client's settings.
Changed — may break scripts
- A failure before a command runs is kept as a run — a usage error, a configuration that will
not load.
tg runs listshows it;--no-recordturns it off.
0.2.0 — 28.09.2026
What's new
tg updateupdates tg with the package manager that installed it;--checkonly looks.- A daily line on stderr when a newer version is on npm, at a terminal only and after the
command.
TG_NO_UPDATE_CHECK=1turns it off.
0.1.0 — 27.09.2026
The first release on npm.
What's new
- Log in by QR code or phone number (
tg session start); the app credentials from my.telegram.org are fetched by opening the site or by filling it in for you (--app auto), and kept in the OS keyring. - Read:
account show,chats list|show,contacts list|show,messages list|show|context. - Send with
messages sendandmessages reply, through a send guard: a recipient list, read-only profiles, a journal of every attempt (tg sends), and--send-idto repeat a send whose outcome is unknown without sending it twice. - A local archive: every read is kept in a store shared by the messenger CLIs;
--offlineanswers from it,messages searchsearches it,backfillfills it,watchandservekeep it current,sync statusandexportread it. - Run records (
tg runs),config,doctor,commandsand shell completion (complete).