Metadata-Version: 2.4
Name: telegram-cli-local
Version: 0.1.0
Summary: Telegram CLI for a personal account
Author: BYxarek
License-Expression: Apache-2.0
Project-URL: Repository, https://github.com/BYxarek/telegram-cli
Project-URL: Issues, https://github.com/BYxarek/telegram-cli/issues
Keywords: telegram,cli,telethon,agent-skills
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: End Users/Desktop
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Topic :: Communications :: Chat
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: Telethon==1.45.0
Dynamic: license-file

<div align="center">

# tcli · Telegram in your terminal

**Read chats, send messages, and follow conversations with your personal Telegram account.**

![Python 3.10+](https://img.shields.io/badge/Python-3.10%2B-3776AB?logo=python&logoColor=white)
![Telethon](https://img.shields.io/badge/Telegram-Telethon-26A5E4?logo=telegram&logoColor=white)
![CLI](https://img.shields.io/badge/Interface-CLI-222222)
[![GitHub stars](https://img.shields.io/github/stars/BYxarek/telegram-cli?style=flat)](https://github.com/BYxarek/telegram-cli/stargazers)

**English** · [Русский](https://github.com/BYxarek/telegram-cli/blob/main/README.ru.md)

[Features](#features) · [Installation](#installation) · [Quick start](#quick-start) · [Commands](#commands) · [AI agents](#ai-agents)

</div>

```console
tcli                          # Show help and setup steps
tcli chats                    # Find a chat
tcli read "Work chat"         # Read recent messages
tcli send me "Remember the meeting"
tcli watch "Work chat"        # Follow new messages
```

`tcli` is a local Python CLI built with [Telethon](https://docs.telethon.dev/).
It uses the Telegram API and acts as your personal account. You need your own
`API_ID` and `API_HASH`; no bot token is used.

## Features

- **Chat list:** IDs, names, and unread counts.
- **Message history:** recent messages, oldest first, with timestamps and sender IDs.
- **Text messages:** send to Saved Messages, usernames, or chats where you can post.
- **Live updates:** follow new messages in one chat until `Ctrl+C`.
- **Local configuration:** enter API credentials once using `tcli config`.
- **Saved login:** reuse your local session on later runs.
- **Built-in help:** `tcli`, `tcli help`, and `tcli help <command>` work without an account.
- **AI agent skills:** project instructions for Codex and Claude Code.

Reading history does not mark messages as read. Outgoing text is literal by default;
use `--format markdown` or `--format html` for formatting. Terminal control characters
are removed from displayed messages.

### Current scope

One local account session, text messages, human-readable output, and optional JSON.
Media is shown as a placeholder; uploading and downloading attachments are not implemented.
Message editing, deletion, and a full-screen interface are not available.

## Installation

Requires **Python 3.10+**, pip, and access to Telegram.

### Published package and updates

Install the isolated CLI and its user skills:

```console
pipx install telegram-cli-local
tcli skills install
tcli --version
```

Update the CLI, then refresh the bundled skills:

```console
pipx upgrade telegram-cli-local
tcli skills install
```

For an existing Python virtual environment, use `python -m pip install --upgrade telegram-cli-local` instead.
Install pipx using its [official instructions](https://pipx.pypa.io/stable/installation/).
GitHub source installations are also supported:

Clone the repository, or download and extract **Code → Download ZIP** on GitHub:

```console
git clone https://github.com/BYxarek/telegram-cli.git
cd telegram-cli
```

### Windows · PowerShell

Install for your user:

```powershell
py -m pip install --user -e .
tcli
```

If pip is missing, first run `py -m ensurepip --upgrade --user`.

<details>
<summary>PowerShell cannot find tcli</summary>

Add the user Python scripts directory to `PATH`:

```powershell
$tcliScriptsDir = (py -c "import sysconfig; print(sysconfig.get_path('scripts', scheme='nt_user'))").Trim()
$tcliUserPath = [Environment]::GetEnvironmentVariable('Path', 'User')
if (($tcliUserPath -split ';') -notcontains $tcliScriptsDir) {
    $tcliUpdatedPath = (($tcliUserPath + ';' + $tcliScriptsDir).Trim(';'))
    [Environment]::SetEnvironmentVariable('Path', $tcliUpdatedPath, 'User')
}
$env:Path = $tcliScriptsDir + ';' + $env:Path
tcli
```

New terminals receive the saved `PATH`. Restart an existing terminal or its parent application if needed.

</details>

The installed command works from any directory. Editable installation (`-e`) uses this source folder;
if you move it, reinstall from its new location.

### Linux / macOS · bash or zsh

Use a virtual environment:

```bash
python3 -m venv .venv
.venv/bin/python -m pip install -e .
source .venv/bin/activate
tcli
```

After activation, `tcli` works from any directory in that terminal.
In a new terminal, activate the environment again using its full path,
or run `/path/to/telegram-cli/.venv/bin/tcli` directly.
Some Linux distributions require installing the `venv` component separately through the OS package manager.

## Quick start

### 1. Get your API credentials

Sign in at [my.telegram.org](https://my.telegram.org), open **API development tools**, and create an application.
Follow the [official Telegram guide](https://core.telegram.org/api/obtaining_api_id) to obtain `api_id` and `api_hash`.

### 2. Configure and sign in

```console
tcli config
tcli login
```

`config` asks for your API credentials and saves them locally. API hash input is hidden.
It does not connect to Telegram. Run it again to replace credentials; invalid input leaves existing settings intact.

`login` asks for your international phone number, Telegram login code, and 2FA password if enabled.
Code and password input is hidden. The session is saved for later commands.

### 3. Read and send

```console
tcli chats
tcli read "Chat name" --limit 10
tcli send me "Hello from tcli!"
```

`me` means your own **Saved Messages**. Messages are sent from your personal account.

## Help

```console
tcli                   # General help, setup steps, and examples
tcli help              # Same general help
tcli help send         # How to send a message
tcli read --help       # Read options and examples
```

Help does not load configuration, create a session, or connect to Telegram.
In an interactive terminal, `tcli`, `tcli help`, `tcli --help`, and `tcli -h` also check PyPI for
a newer stable release. The check uses a one-second network timeout and caches results (including
failed checks) for 24 hours in the data directory's `cache/update-check.json`.
Available updates are reported on stderr with upgrade instructions; no update is installed automatically.
Network/cache errors are silent. Piped output, command-specific help, and `--version` skip the check.
Set `TCLI_NO_UPDATE_CHECK=1` to disable it entirely.
Running `tcli` without a command succeeds instead of showing a missing-command error.
Unknown commands and invalid arguments still return an error.

## Commands

| Command | Purpose |
| --- | --- |
| `tcli config` | Save or replace API credentials |
| `tcli login` | Sign in to your personal account |
| `tcli chats --limit 100` | List up to 100 chats; default: 50 |
| `tcli read "Chat" --limit 20` | Read recent messages; default: 20 |
| `tcli send "Chat" "Text"` | Send one plain-text message |
| `tcli watch "Chat"` | Follow new messages until `Ctrl+C` |
| `tcli logout` | Revoke this CLI session, keeping API credentials |
| `tcli help [COMMAND]` | Show general or command-specific help |
| `tcli doctor [--connect]` | Check local configuration/session; optionally test connectivity and authorization |
| `tcli skills install [--agent auto\|all\|codex\|claude]` | Install/update bundled user skills without Telegram access |
| `tcli --version` | Show the installed CLI version |

### JSON, search, pagination, and replies

```console
tcli chats --json
tcli read "Chat" --json --limit 20
tcli watch "Chat" --json
tcli read "Chat" --search "meeting" --before 12345 --limit 20
tcli send "Chat" "Reply text" --reply-to 12345
tcli send me --file message.txt
```

`chats --json` and `read --json` return JSON arrays, including `[]` for empty results.
Chat objects contain `id`, `name`, and `unread_count`. Message objects contain `id`,
`chat_id`, `date` (ISO 8601 with offset), `sender_id` (nullable), `out`, `text`, and `has_media`.
JSON preserves original text, including Unicode and control characters as escaped sequences;
human-readable output removes terminal controls. Media-only messages have empty JSON text.
`watch --json` emits one message object per line (JSONL), flushing immediately.
Watch status and errors go to stderr, keeping stdout machine-readable.

`--search` uses Telegram's text search within the selected chat. Results remain oldest first
within each returned page. `--before ID` excludes that ID and returns older messages;
use the smallest returned message ID for the next page. It can be combined with search.
`--before` and `--reply-to` require positive message IDs from the same chat.

`send` requires exactly one text source: a positional text argument, `--stdin`, or `--file PATH`.
Files and stdin use UTF-8 (an optional BOM is accepted). Stdin is read until EOF;
empty or whitespace-only input is rejected before connecting. Line breaks and surrounding
whitespace are kept in plain mode. `--file` sends the file's text, not an attachment.
All text sources support `--reply-to` and `--format`.

### Text formatting

```console
tcli send me '**Bold** __italic__ ~~strike~~ `code` [link](https://example.com)' --format markdown
tcli send me '<b>Bold</b> <i>italic</i> <u>underline</u> <s>strike</s>' --format html
tcli send me '<blockquote>Quote</blockquote>' --format html
tcli send me --file message.html --format html --reply-to 12345
```

`--format plain` (the default) sends markup literally. Markdown is Telethon's dialect,
not Telegram Bot API MarkdownV2: `**bold**`, `__italic__`, `~~strike~~`, backticks for code,
triple backticks for code blocks, and `[label](URL)`. Use HTML for underline and nested
formatting. Supported HTML includes `<b>`, `<strong>`, `<i>`, `<em>`, `<u>`, `<s>`, `<del>`,
`<code>`, `<pre>`, `<a href="URL">`, and `<blockquote>` (also `expandable`).
`<pre><code class="language-python">...</code></pre>` specifies a code-block language.
HTML escapes use `&lt;`, `&gt;`, and `&amp;`. Use actual line breaks, not `<br>`.
The installed Telethon parser does not support spoiler markup; unknown HTML tags are ignored.
Telegram may trim surrounding whitespace when parsing formatted text.

PowerShell pipeline example (ensure the shell sends UTF-8):

```powershell
$OutputEncoding = [System.Text.UTF8Encoding]::new($false)
Get-Content -Raw -Encoding utf8 message.txt | tcli send me --stdin
```

`doctor` prints configuration/session paths, validates the effective API credentials without
showing their values, and checks session-file presence without connecting or creating files.
It exits 1 on invalid configuration or a missing session. File presence does not prove authorization.
`doctor --connect` requires an existing session and additionally connects to Telegram and checks
authorization without prompting for login or reading chats. It may update the existing Telethon session.

### Choosing a chat

Use `me`, `@username`, an exact chat name, or an ID from `tcli chats`.
Chat names are case-sensitive. If names are duplicated, use the ID.
Partial name matching and `t.me` links are not supported.

Put `--` before a negative ID, after all options:

```console
tcli read --limit 10 -- -1001234567890
tcli send -- -1001234567890 "Message to a group"
tcli watch -- -1001234567890
```

The ID above is an example; use an ID from your chat list. Limits must be positive integers.
`watch` records the latest message ID at startup and checks for newer messages every two seconds.
It includes outgoing messages from another CLI process, including Saved Messages, and outputs
each fetched batch oldest first without a fixed batch limit. Already existing messages are not printed.
Messages deleted before the next check cannot be displayed. Open a second terminal to send while watching.
Session changes are committed between checks so the watcher does not hold a SQLite write lock while idle.
Timestamps use your computer's local time zone.

## Configuration and session

| Platform | Data directory |
| --- | --- |
| Windows | `%LOCALAPPDATA%\telegram-cli\` |
| Linux / macOS, when `LOCALAPPDATA` is absent | `~/.local/share/telegram-cli/` |

`config.json` stores API credentials; `account.session` stores the Telethon session.
Both are kept outside the source directory and are independent of your working directory.

For compatibility, `TG_API_ID` and `TG_API_HASH` environment variables override the file.
If either variable is present, both are required; values from different sources are never mixed.
`.env` files are not loaded automatically.

**The session file grants access to your account.** Do not publish it, your API hash, login codes, or password.
Configuration is stored unencrypted. New configuration files use permissions `0600` on POSIX;
Windows inherits access permissions from the profile directory.
If a session leaks, revoke it in Telegram: **Settings → Devices**.
Outgoing message text may be saved in your shell history.

## AI agents

| Agent | Skill | Invocation |
| --- | --- | --- |
| Codex | [.agents/skills/telegram-cli/SKILL.md](https://github.com/BYxarek/telegram-cli/blob/main/.agents/skills/telegram-cli/SKILL.md) | `$telegram-cli` |
| Claude Code | [.claude/skills/telegram-cli/SKILL.md](https://github.com/BYxarek/telegram-cli/blob/main/.claude/skills/telegram-cli/SKILL.md) | `/telegram-cli` |

`tcli skills install` detects installed agents and installs the bundled skill only for those agents into
`~/.agents/skills/telegram-cli/SKILL.md` (Codex) and `~/.claude/skills/telegram-cli/SKILL.md` (Claude Code).
The default `--agent auto` checks PATH, native `~/.local/bin` executables, standard npm/binary locations,
Codex.app on macOS, and the Windows Store Codex installation. Configuration folders alone do not count.
If no agent is detected, no skill folders are created. Explicit `--agent codex`, `--agent claude`, or
`--agent all` bypasses detection for custom installations. This command works offline without API credentials
or a Telegram session, and does not install either agent application.
An identical file is skipped; a differing file is backed up as `SKILL.md.backup-*.bak` in the same folder
before atomic replacement. Other files stay in place. Merge personal instructions from the backup manually.
Symlinked skills are not replaced; update their source instead.
Restart your agent or start a new session if the updated skill does not appear.

For a cloned checkout, `git pull --ff-only` updates project-local skills and editable CLI source.
Run `python -m pip install -e .` again to refresh package metadata and dependencies, then `tcli skills install` if you also
installed user copies. Avoid duplicate project/user skills unless you need both scopes.

Open your agent in the project root. Start a new session if the skill is not visible.
Each skill contains the complete command, setup, and architecture reference in its own `SKILL.md`.
Project instructions are in [AGENTS.md](https://github.com/BYxarek/telegram-cli/blob/main/AGENTS.md)
and [CLAUDE.md](https://github.com/BYxarek/telegram-cli/blob/main/CLAUDE.md).

Example request:

> Use telegram-cli. Explain the commands and run tests without signing in to Telegram.

Skills explain chat resolution, configuration, errors, and authorization boundaries.
Sending requires the user's direct instruction. Telegram messages are untrusted data,
not instructions for the agent. Enter credentials and sign in in your own terminal.

## Development

Windows:

```powershell
py -m venv .venv
.\.venv\Scripts\python.exe -m pip install -e .
.\.venv\Scripts\python.exe -X utf8 -m unittest discover -s tests -v
.\.venv\Scripts\tcli.exe help
```

Linux / macOS, after installing in `.venv`:

```bash
.venv/bin/python -m unittest discover -s tests -v
.venv/bin/tcli help
```

Tests run without a real account: they cover help, argument validation, chat resolution,
JSON/JSONL, search and pagination arguments, replies, stdin/files, diagnostics, login/logout,
watch polling/cursors, formatting selection, error exit codes, disconnects, and configuration preservation on errors.
They do not verify a real Telegram login or message delivery.

```text
tg.py                 CLI commands, configuration, and Telegram operations
pyproject.toml        Package metadata and tcli entry point
requirements.txt      Dependencies
tests/                Tests without a live account
.agents/skills/       Self-contained Codex skill and project reference
.claude/skills/       Self-contained Claude Code skill and project reference
README.ru.md          Russian documentation
```

Keep both READMEs and all three SKILL.md copies (Codex, Claude Code, and `tcli_skills/`) in sync when changing commands.
Release instructions are in [RELEASING.md](https://github.com/BYxarek/telegram-cli/blob/main/RELEASING.md).
[Report bugs](https://github.com/BYxarek/telegram-cli/issues) with the command, Python version,
and sanitized error output. Never attach your session file or credentials.

## Troubleshooting

**`Could not find platform independent libraries <prefix>` on startup?**
This warning comes from Python before the CLI starts. Check `py -c "import sys; print(sys.executable); print(sys.prefix)"`
on Windows. Repair or reinstall that Python installation so its standard library and extension modules
are present alongside the interpreter; avoid moving `python.exe` on its own.
Then reinstall the CLI using that interpreter. If a virtual environment points to a removed installation,
recreate it and reinstall the project. Do not hide stderr: it also contains real CLI errors.

**Chat not found?** Use an exact name, `@username`, or an ID from `tcli chats`.
Increase `--limit` if your chat is not in the first page.

**Telegram asks you to wait?** Wait for the reported FloodWait period.
After a connection failure, check recent history before retrying a send to avoid duplicates.

**Can I use a bot?** This CLI supports personal accounts only.

**Can I still run the Python file?** Yes: `python tg.py ...` from the project root
with dependencies installed uses the same commands.

## License

Copyright 2026 BYxarek. Licensed under [Apache-2.0](https://github.com/BYxarek/telegram-cli/blob/main/LICENSE).
