Complete guide · v0.6.1

Know where every
command runs.

Telegram CLI moves between the Telegram network, a private SQLite database, local files, and deliberate remote writes. This guide makes that boundary visible while documenting the complete tg surface.

first session Node.js 22.12.0+
 npm install -g @will-17173/telegram-cli
 tg account add
 tg chats --json
 tg sync @team
 tg search "release" --chat @team
Live Persist Local Files Write
On this page

01 · Start

From install to local search.

Authenticate once in an interactive terminal, discover a stable chat identifier, then choose whether to read online or build a local message history.

Requires Node.js 22.12.0 or later
Package @will-17173/telegram-cli
Binary tg
  1. Install the CLI

    Install it globally from npm so tg is available in any directory.

    npm install -g @will-17173/telegram-cli
    tg --version
  2. Add an account

    The login flow may ask for a phone number, Telegram code, and 2FA password. Run it directly in a TTY; never pipe credentials.

    tg account add
    tg status
    tg whoami
  3. Discover a chat

    Names and usernames work interactively. For scripts, prefer the numeric ID returned by structured output. Chat types are user, group, supergroup, channel, and unknown.

    tg chats --json
    tg chats --type supergroup
    tg info @team --json
  4. Sync, then search locally

    sync stores new messages in the selected account’s SQLite database. A chat not yet present locally is capped at 500 messages on its first sync, even when a larger limit is requested.

    tg sync @team
    tg search "release" --chat @team
    tg search "release" --account work --json

02 · Boundaries

Five scopes, one command surface.

A command’s scope tells you whether it needs Telegram, changes local state, or mutates remote state. Check the scope before choosing a command for a script.

Live

Read from Telegram

Connects with the selected session and returns current server state. Message results are not inserted into SQLite.

inbox · read · search-online
Persist

Telegram → SQLite

Fetches Telegram history and stores it in the selected account’s local message database for later queries.

history · sync · sync-all · refresh
Local

Read local SQLite

Works without Telegram. Freshness is exactly the last data you synchronized for that account.

search · recent · stats · export
Write

Change Telegram

Mutates messages, notifications, folders, or group state. The local write-access gate must be enabled.

send · edit · delete · group actions
Files

Write a Markdown archive

Reads Telegram history into incremental Markdown and optional media files. It does not populate SQLite.

archive
Task Network Destination Key behavior
Online read Telegram Output only read and search-online do not populate SQLite.
Synchronization Telegram SQLite history backfills older messages from the local oldest row; sync commands update from the local newest row.
Local analysis None Output or export file Account databases stay isolated; synchronize first when freshness matters.
Archive Telegram Markdown + media files Does not populate SQLite; later runs resume from archive state.
Remote write Telegram Telegram Blocked before mutation when write access is off.

03 · Recipes

Everyday workflows.

These recipes keep the account explicit and use structured output where a machine will consume the result.

Live 01

Triage without storing

List unread dialogs without marking them read, inspect one chat, or search Telegram globally.

tg inbox --limit 50 --account work --json
tg read @ops --since 2h --account work --json
tg search-online "incident" --until 2026-07-14T10:00:00+08:00 --json

Relative time bounds use s, m, h, d, or w. Absolute timestamps require an ISO 8601 zone.

Persist 02

Build a searchable memory

Backfill a bounded number of messages, increment one chat, or refresh many chats before local analysis.

tg history @ops --limit 1000 --delay 1 --account work
tg sync @ops --limit 5000 --account work
tg refresh --max-chats 20 --delay 1 --account work --json
tg search "incident" --chat @ops --hours 168 --json

refresh can be top-level successful while individual chats fail; inspect data.failures. sync-all omits failure details, so prefer refresh when partial failures matter.

Local 03

Analyze without reconnecting

Query the selected account’s SQLite database by keyword, sender, time, regular expression, or aggregate.

tg search "error|failed" --regex --account work --json
tg recent --sender alice --hours 6 --limit 100
tg top --chat @ops --hours 168
tg timeline --chat @ops --by hour --json

An empty result may simply mean the correct chat or account has not been synchronized yet.

Write 04

Send, then synchronize

Check the safety gate, send text or a media group, then sync if the sent message must be available to local queries.

tg config write-access status --json
tg send @team "Release is ready" --account work --json
tg send @team "Build artifacts" --file ./app.zip --file ./checks.txt
tg sync @team --account work

send has no confirmation prompt and does not insert its result into SQLite. Repeat --file to preserve media-group order.

Live stream 05

Listen continuously

Listen globally or to selected chats. Interactive TTY mode uses Ink; plain mode emits streaming text.

tg listen @team --persist --retry-seconds 5
tg listen @team @ops --send-to @team
tg listen --no-interactive --auto-download --no-media

--persist means reconnect automatically; it is not a database option. listen exposes no JSON, YAML, or Markdown format flags. Auto-download saves normalized attachments under ~/Downloads/telegram-cli, even when --no-media hides rendered media rows.

Files 06

Archive to Markdown

Select explicit chats or --all, never both. The first unbounded run defaults to the preceding seven days.

tg archive @team --download-media --account work
tg archive @team --since 30d --until 2026-07-14T00:00:00Z
tg archive --all --full --output ./telegram-archive --json

Later runs are incremental. --rebuild replaces chat files; --download-media retries referenced files that are still missing. Archive files do not populate SQLite. Custom --output directories are not reset automatically.

04 · Identity

Accounts and configuration.

Each registered account owns an isolated Telegram session and SQLite database. API credentials and proxy configuration are shared across registered accounts.

Add

Authenticate a new account

The first account becomes current. Adding later accounts does not switch the default.

tg account add
Select

Keep scripts explicit

Use --account for one invocation without changing the current account.

tg chats --account work --json
Log out

Retain local history

Logout invalidates the Telegram session but keeps registration and SQLite messages.

tg account logout work --yes
Remove

Delete local account data

Removal deletes the account’s local session and data; --force skips confirmation.

tg account remove work --force

Account lifecycle

tg account list --json
tg account current
tg account switch work
tg account logout work --yes
tg account login work
tg account remove work --force

account login reauthenticates an existing logged-out registration and replaces its session safely while retaining its database. Login and ownership transfer require interactive input; adding --json does not make authentication non-interactive. If a failed replacement reports recovery_path or recovery_paths, preserve those files during recovery.

Credential and proxy precedence

Setting One-command override Persisted setting Fallback
API credentials TG_API_ID + TG_API_HASH tg config set --api-id … --api-hash … Restricted built-in credentials
Telegram proxy TG_PROXY tg config set --proxy <url> Direct connection
Storage root DATA_DIR=/path/to/data OS-specific default

Set TG_API_ID and TG_API_HASH together; supplying only one is an error. Supported proxy schemes are SOCKS4, SOCKS5, HTTP, HTTPS, and MTProxy. The proxy applies to account login and every Telegram-backed command.

tg config set --proxy socks5://127.0.0.1:1080
TG_PROXY=http://127.0.0.1:8080 tg status
tg config list --json
tg config list --show-secrets

Local layout

DATA_DIR changes the root for configuration, the account registry, sessions, databases, and default archives. Important paths are:

config.json
accounts.json
accounts/<name>/session
accounts/<name>/messages.db
accounts/<name>/archive/

05 · Reference

All 33 top-level commands.

Examples show the representative route, not every option. Run tg <command> --help for the installed version’s exact arguments and flags.

Live read Persist Local Remote write Files
Command Scope Purpose and representative syntax
search Local Search stored messages by keyword, chat, sender, time, or regex.tg search "release" --chat @team --hours 168 --json
recent Local Show recently stored messages; defaults to 24 hours and 50 results.tg recent --sender alice --hours 6 --limit 100
stats Local Summarize local message and chat statistics.tg stats --account work --json
top Local Rank the most active stored-message senders.tg top --chat @team --hours 168 --limit 20
timeline Local Aggregate local message activity by day or hour.tg timeline --chat @team --by hour --json
today Local Show messages stored today, optionally for one chat.tg today --chat @team
filter Local Filter stored messages using space-separated keywords.tg filter "release urgent" --hours 24 --json
archive Files Build incremental Markdown archives from Telegram history; SQLite is unchanged.tg archive @team --download-media --json
export Local Export one chat’s stored messages to text, JSON, or YAML.tg export @team --format json --output ./messages.json
purge Local Delete one chat’s locally stored messages only; requires confirmation.tg purge @team --yes --json
data Local reset Manage account-scoped local data. Breaking media-schema upgrades require deleting old databases/default archives, then syncing again.tg data reset --yes --json
tg sync-all
status Live Check whether the selected Telegram account is authenticated.tg status --account work --json
whoami Live Show identity information for the authenticated account.tg whoami --account work --json
chats Live List Telegram dialogs and filter by user, group, supergroup, or channel.tg chats --type channel --json
history Persist Fetch and store older messages before the local oldest row; default limit 1000.tg history @team --limit 1000 --delay 1
sync Persist Incrementally store new messages for one chat; default limit 5000.tg sync @team --delay 1 --json
sync-all Persist Incrementally synchronize multiple dialogs; projected output omits failure details.tg sync-all --max-chats 20 --limit 5000
refresh Persist Bulk-sync dialogs and retain per-chat failures in data.failures.tg refresh --max-chats 20 --json
info Live Show metadata for a Telegram chat.tg info @team --account work --json
send Write Send text, files, a captioned media group, or a reply; no confirmation prompt.tg send @team "Hello" --file ./photo.jpg --json
edit Write Edit a Telegram message’s text.tg edit @team 814 "Updated text" --json
delete Write Delete one or more Telegram messages.tg delete @team 814 815 --json
download Files Download all media from one message, a selected attachment, a grouped album, a range, a date, or an entire chat. Attachment numbers are one-based; albums flatten by message ID and local index. Stable media errors include attachment_changed and media_access_denied.tg download @channel 42 --attachment 2
listen Live stream Stream incoming messages interactively or as plain text; no finite-output flags. Persisted structured rows use ordered lowercase attachments[].tg listen @team --persist --auto-download
contact Live List Telegram contacts or resolve one by ID, username, or phone.tg contact info @alice --json
inbox Live List unread dialogs without marking their messages read.tg inbox --limit 50 --markdown
read Live Read a bounded online message range without persisting it.tg read @team --since 7d --until 2d --json
search-online Live Search Telegram globally or in one chat without storing results.tg search-online "incident" --chat @team --json
dialog Live Alternate family for inbox, read, online search, and managed groups.tg dialog search "incident" --chat @team --json
group Inspect Manage Inspect groups, members, and audit events, or run the 48 management actions below.tg group members @team --type admins --json
folder Inspect Manage List and inspect folders, or add/remove explicit chat membership.tg folder chat add 3 @team --json
notification Inspect Manage Inspect, mute, or unmute a chat’s notification settings.tg notification mute @team 8h --json
account Registry Session Add, list, select, log out, reauthenticate, or remove isolated accounts.tg account list --json
config Local Save credentials/proxy settings, inspect effective config, and control write access.tg config write-access status --json
web Local Start the local-only React management UI on 127.0.0.1 to browse stored messages and trigger read-only sync for the selected chat.tg web --port 8734

06 · Groups

Inspect first. Manage deliberately.

The group surface combines read-only inspection with generated actions for members, administrators, chat settings, invitations, forum topics, and messages.

Read-only

Group and member state

tg group info @team --json
tg group list --admin --limit 100
tg group members @team --type admins --query alice --limit 50
tg group member info @team @alice --json
Admin read

Audit events

tg group audit @team \
  --user @alice \
  --type member_invited \
  --type invite_changed \
  --limit 100 --json

group members defaults to type recent and 100 results, with a maximum of 200. Its seven types are recent, all, admins, banned, restricted, bots, and contacts. Telegram may return fewer rows than its reported total.

group audit requires administrator rights, defaults to 100 events, and accepts up to 500. Repeat --user for action authors and --type for event groups including chat/settings changes, member actions, admin changes, message changes, invites, topics, and other.

Remote actions

Generated action grammar

tg group <family> <action> <chat> [arguments] [options]

Every action below is part of the v0.6.1 catalog. “Confirm” actions reject execution without --yes. “Direct” writes have no built-in prompt, but still require authorization and enabled write access. The four actions labeled “Read” do not mutate Telegram.

7 actions

member

Targets must be explicit @username values or numeric user IDs.

  • member add <chat> <users...>Add one or more members.
    Direct
  • member kick <chat> <user>Remove a member.
    Confirm
  • member ban <chat> <user>Ban a member.
    Confirm
  • member unban <chat> <user>Lift a member ban.
    Confirm
  • member mute <chat> <user> [duration]Restrict sending temporarily or indefinitely.
    Confirm
  • member unmute <chat> <user>Restore member permissions.
    Confirm
  • member purge <chat> <user>Delete all messages from a member.
    Confirm
4 actions

admin

Requires administrator rights; ownership transfer requires the creator role.

  • admin promote <chat> <user> [permissions]Promote a member.
    Confirm
  • admin demote <chat> <user>Remove administrator privileges.
    Confirm
  • admin rank <chat> <user> <text...>Set a custom administrator title.
    Confirm
  • admin transfer-owner <chat> <user>Transfer ownership after a secure 2FA prompt.
    Confirm
13 actions

chat

Capabilities vary: some settings require a supergroup, creator, or administrator role.

  • chat title <chat> <text...>Change the chat title.
    Direct
  • chat description <chat> <text...>Change the description.
    Direct
  • chat username <chat> <username>Change the public username.
    Direct
  • chat photo <chat> <path>Set a photo from a local file.
    Direct
  • chat slowmode <chat> <duration>Set slow mode; use off to disable.
    Direct
  • chat ttl <chat> <duration>Set message auto-delete.
    Confirm
  • chat protect <chat> <enabled>Toggle content protection.
    Direct
  • chat join-requests <chat> <enabled>Toggle approval for new members.
    Direct
  • chat join-to-send <chat> <enabled>Require membership before posting.
    Direct
  • chat default-permissions <chat> <permissions>Set default member rights.
    Confirm
  • chat sticker-set <chat> <sticker|off>Set or remove the sticker set.
    Direct
  • chat leave <chat>Leave the selected chat.
    Confirm
  • chat delete <chat>Permanently delete the chat.
    Title + yes
10 actions

invite

Inspection is read-only; creation, changes, revocation, and join-request decisions are writes.

  • invite list <chat>List invite links.
    Read
  • invite show <chat> <invite>Show invite details.
    Read
  • invite create <chat> [options]Create a link with optional title, expiry, limit, or approval.
    Direct
  • invite edit <chat> <invite> [options]Edit an existing link.
    Direct
  • invite revoke <chat> <invite>Revoke a link.
    Confirm
  • invite members <chat> <invite>List members who used a link.
    Read
  • invite approve <chat> <user>Approve one join request.
    Direct
  • invite decline <chat> <user>Decline one join request.
    Direct
  • invite approve-all <chat>Approve every pending request.
    Confirm
  • invite decline-all <chat>Decline every pending request.
    Confirm

For create/edit, options include --title, --expire, --limit, and --request-needed.

10 actions

topic

Forum-only capabilities. Topic deletion also removes that topic’s messages.

  • topic list <chat>List forum topics.
    Read
  • topic create <chat> <title...>Create a topic.
    Direct
  • topic edit <chat> <id> <title...>Edit a topic title.
    Direct
  • topic close <chat> <id>Close a topic.
    Direct
  • topic reopen <chat> <id>Reopen a topic.
    Direct
  • topic pin <chat> <id>Pin a topic.
    Direct
  • topic unpin <chat> <id>Unpin a topic.
    Direct
  • topic reorder <chat> <ids...>Order pinned topics.
    Direct
  • topic delete <chat> <id>Delete a topic and its messages.
    Confirm
  • topic general-hidden <chat> <hidden>Toggle the general topic’s visibility.
    Direct
4 actions

message

Administrative message pinning and deletion inside the selected chat.

  • message pin <chat> <id>Pin a message.
    Direct
  • message unpin <chat> <id>Unpin one message.
    Direct
  • message unpin-all <chat>Unpin every message.
    Confirm
  • message delete <chat> <ids...>Delete messages from the chat.
    Confirm

Use slash commands while listening

Type / in interactive listen to open one command menu. Reply to a message or run a group action without repeating the selected chat:

/reply <message-id> <content>
/member mute @alice 2h

Matching checks exact paths, prefixes, then ordered fuzzy matches. /rep and /rpy find /reply. /ban finds /member ban.

When listening to more than one chat, set --send-to <chat> before group actions. Permission and availability checks remain active. Risky actions open a confirmation modal.

07 · Machines

Structured output and exit behavior.

Use JSON or YAML envelopes for automation. Human tables and Markdown are designed to be read, not parsed.

Explicit flag

Choose exactly one format on a finite command.

--json · --yaml · --markdown

Environment default

An explicit flag wins over the environment.

OUTPUT=json|yaml|markdown|rich

Automatic default

TTY output is rich; non-interactive output defaults to YAML.

OUTPUT=markdown tg inbox

Stable success envelope

{
  "ok": true,
  "schema_version": "2",
  "data": {}
}

Stable failure envelope

{
  "ok": false,
  "schema_version": "2",
  "error": {
    "code": "chat_not_found",
    "message": "..."
  }
}
01

Trust exit status

Every failure sets a nonzero process status. Successful finite output goes to stdout.

02

Read by code

Branch on error.code, not the human message. Inspect operation-specific error.details.

03

Know the stream

listen is unbounded and has no JSON, YAML, or Markdown flags; use --no-interactive for plain streaming text.

JSON/YAML structured failures are written to stdout in the requested format. Human-readable and Markdown failures go to stderr. Output-format conflicts also fail nonzero and use a stable YAML envelope on stdout. Do not combine output flags.

08 · Guardrails

Keep remote writes intentional.

The write-access switch is a local preflight gate for Telegram mutations. It does not replace explicit authorization, Telegram permissions, or command-specific confirmation.

Remote boundary

Inspect, enable, or disable

When disabled, gated commands fail with write_access_disabled before connecting for the mutation.

tg config write-access status --json
tg config write-access off
tg config write-access on
Operation Write gate Built-in confirmation Important caveat
send, edit, delete Required None Sending does not update SQLite.
Notification mute/unmute Required None Omitted mute duration means forever.
Folder chat add/remove Required None Prefer numeric folder IDs; titles can be ambiguous.
Group direct actions Required None “No prompt” does not mean low impact.
Group risky actions Required --yes Chat deletion also needs exact --confirm-title.
purge Not applicable --yes Deletes local SQLite rows, not Telegram messages.

What the gate does not block

Online reads, synchronization, history, archives, local queries, exports, local purge, account lifecycle, and configuration changes remain available. The gate is scoped only to remote mutations by message, notification, folder, and non-read-only group actions.

Protect credentials

Never commit .env, API values, authenticated sessions, proxy secrets, SQLite databases, or archive exports.

Respect rate limits

Large global searches, histories, and media archives can trigger FLOOD_WAIT. Respect the reported delay and keep request spacing.

Verify the target

Use numeric chat, folder, message, and user identifiers in automation to avoid ambiguous names.

Keep secrets interactive

Login codes, account 2FA, and ownership-transfer passwords belong only in secure TTY prompts—not arguments, environment values, or logs.

09 · Recovery

Troubleshoot by error code.

Structured errors are stable enough for branching. Human messages add context, but code—not message text—should select the recovery path.

account_required or account_not_found

Add the first account, or inspect registered names and correct --account. The first account becomes current automatically.

tg account add
tg account list --json
tg account switch <name>
account_logged_out or interaction_required

Local SQLite commands still work for a logged-out registration. Run login directly in an interactive terminal; never pipe the phone number, code, or 2FA password.

tg account login <name>
telegram_account_session_expired or AUTH_KEY_UNREGISTERED

The local session is no longer valid. Remove that registration and authenticate again. Removal deletes its local session/data, so preserve anything needed first.

tg account remove <name> --force
tg account add
account_identity_mismatch

The authenticated identity does not match the registered account. Stop, verify the intended account, and rerun interactive login for the correct name. Preserve any reported recovery paths.

chat_not_found or ambiguous_chat

For a local query, synchronize the chat into the same account database first. If a name matches more than one stored dialog, use the numeric chat ID from tg chats --json.

tg chats --account work --json
tg sync <numeric-chat-id> --account work
tg search "keyword" --chat <numeric-chat-id> --account work
contact_not_found

Telegram could not resolve the supplied numeric ID, @username, or phone number. Verify the value and remember that chats --type user lists private dialogs, while contact list lists contacts.

invalid_notification_duration

Use a positive integer with s, m, h, d, or w, or use forever. An omitted duration also means forever.

tg notification mute @team 8h
tg notification mute @team forever
folder_not_found, ambiguous_folder, or folder_operation_unsupported

List folders and use the returned numeric ID. If Telegram reports the operation unsupported, do not retry the same change automatically.

tg folder list --json
tg folder info 3 --json
archive_account_mismatch, archive_failed, or archive_partial_failure

An archive root belongs to one account. Use a separate output directory after an account mismatch. For partial failures, keep completed files, inspect completed/failed/warnings in structured details, and retry only failed work or missing media.

write_access_disabled

The local gate stopped a Telegram mutation before it connected for that write. Obtain authorization before enabling the gate, then obtain separate authorization for the specific mutation.

tg config write-access status --json
tg config write-access on
password_required, password_invalid, password_too_fresh, or session_too_fresh

Ownership transfer must be completed by the creator in an interactive TTY. Prompt again after missing/invalid credentials. For freshness errors, report Telegram’s wait details and do not retry early.

flood_wait or FLOOD_WAIT

Stop aggressive retries, respect the reported delay, retain page/chat delays, narrow the request, and configure personal API credentials if you are using the restricted defaults.