An unofficial, terminal-based Telegram user-client suite written in C11. Three binaries share one MTProto 2.0 codebase built from scratch (no TDLib, no HTTP, no JSON library):
| Binary | Mode | Capabilities |
|---|---|---|
tg-cli-ro |
batch, read-only by construction | list dialogs, read history, self/user info, contacts, search, watch updates, download photos |
tg-tui |
interactive REPL | everything tg-cli-ro does plus send, reply, edit, delete, forward, read-markers, file upload |
tg-cli |
batch, read + write | same surface as the TUI from the command line, pipe-friendly (stdin → message body) |
tg-cli-ro can never mutate server state — the write-capable domain
library is simply not linked into that target (ADR-0005).
Status: v1 MVP feature-complete. 2703 unit tests + 427 functional tests green; Valgrind clean. The functional suite drives every user-facing flow (login / 2FA / dialogs / history / send / edit / delete / forward / read-markers / upload / download) through an in-process mock Telegram server with real OpenSSL on both sides.
Disclaimer: This software is provided as-is, without warranty of any kind. The author accepts no responsibility for any damage, data loss, or unintended consequences resulting from the use or malfunction of this program. This is an unofficial client and is not affiliated with Telegram.
- Why MTProto?
- Architecture
- Security
- Dependencies
- Building
- Configuration
- Planned Usage
- Implementation Progress
- Documentation
- Legal
- License
The Telegram Bot API (HTTPS JSON) is easy to use but has a fundamental limitation:
bots cannot fetch chat history. They only receive real-time messages via getUpdates.
tg-cli implements the MTProto 2.0 protocol directly, which is what the official Telegram desktop and mobile clients use. This gives access to:
- Full chat history via
messages.getHistory - Chat/dialog list via
messages.getDialogs - Media download via
upload.getFile - Real-time updates via
updates.getDifference - User account login with phone number + SMS code
All without any third-party library — the entire MTProto stack is implemented in C from the protocol specification.
The project follows a strict layered CLEAN architecture:
Entry points → src/main/{tg_cli,tg_cli_ro,tg_tui}.c (three binaries — ADR-0005)
App → src/app/ (bootstrap, auth flow, DC session, session store)
TUI → src/tui/ (screen, panes, list view, status row, app)
Domain → src/domain/read/ + src/domain/write/ (Telegram service logic)
Infrastructure → src/infrastructure/ (config, cache, transport, RPC, api_call, auth)
Core → src/core/ (logger, fs_util, TL serial/skip/registry,
AES-IGE, MTProto crypto, crypto wrappers)
Platform → src/platform/ (terminal + path + socket, posix + windows)
tg-cli-ro is compile-time read-only: the tg-domain-write library is
not linked into it (ADR-0005), so no mutation RPC is reachable even if
an arg-parse bug were exploited.
┌─────────────────────────────────────────────┐
│ Application — list chats, read messages │
├─────────────────────────────────────────────┤
│ Telegram API (TL RPC) │
│ auth.sendCode, messages.getHistory, etc. │
├─────────────────────────────────────────────┤
│ MTProto session │
│ msg_id, seq_no, salt, session_id, updates │
├─────────────────────────────────────────────┤
│ MTProto encryption │
│ AES-256-IGE, SHA-256, auth_key management │
├─────────────────────────────────────────────┤
│ TL serialization │
│ binary object encoding │
├─────────────────────────────────────────────┤
│ Transport — TCP (Abridged) via POSIX socket │
└─────────────────────────────────────────────┘
- Read-only
tg-cli-roat link time: the binary never linkstg-domain-write, so no mutation RPC is reachable even if an arg-parse bug were exploited. - MTProto 2.0 encryption: AES-256-IGE + SHA-256 for every
client-server frame. MITM hardened via
new_nonce_hash1verification during the DH handshake. - 2FA / SRP:
account.getPassword+auth.checkPasswordwith PBKDF2-HMAC-SHA-512 and the Telegram SRP variant. - Auth key: 2048-bit key generated via DH exchange, persisted
together with DC id and server salt in
~/.config/tg-cli/session.bin(mode 0600).--logoutclears it. - Credentials at rest:
~/.config/tg-cli/config.iniwritten with0600permissions. - Local cache:
~/.cache/tg-cli/with0700directory permissions; downloaded media underdownloads/. - Logs: diagnostics in
~/.cache/tg-cli/logs/session.log. May include API response bodies. - Memory safety: every CI run exercises the full suite under AddressSanitizer and Valgrind — zero leaks or errors.
| Dependency | Purpose |
|---|---|
| C11 compiler (GCC/Clang) | Build |
| POSIX sockets | TCP transport (built into the OS) |
| libssl (OpenSSL) | AES, SHA-256, RSA, DH crypto primitives |
| CMake | Build system |
No third-party Telegram libraries. No TDLib, no Bot API wrappers, no JSON libraries. Everything is implemented from scratch.
./manage.sh deps # Install system dependencies (Ubuntu 24.04 / Rocky 9)
./manage.sh build # Release build — produces bin/tg-cli-ro, bin/tg-tui, bin/tg-cli
./manage.sh test # Unit tests under AddressSanitizer
./manage.sh valgrind # Unit tests under Valgrind
./manage.sh coverage # GCOV/LCOV report (~89% for core + infrastructure)On first run, tg-cli will guide you through setup:
- Phone number — your Telegram account phone number
- Auth code — received via SMS or Telegram app
- 2FA password — if two-factor authentication is enabled
The auth key and configuration are stored at ~/.config/tg-cli/.
To reconfigure:
rm -rf ~/.config/tg-cli/
bin/tg-cliYou need an api_id and api_hash from Telegram (free — one-time setup).
See docs/user/setup-my-telegram-org.md
for the step-by-step guide, or run tg-tui login after building to use
the interactive wizard.
bin/tg-tui
After login you land in a readline-backed prompt. Try help for the
full command list. Highlights:
tg> dialogs 20
tg> history @somechannel 50
tg> send @user "hello there"
tg> reply @user 12345 "nice"
tg> edit @user 12345 "fixed typo"
tg> upload @user ~/docs/report.pdf "final version"
tg> poll
Scriptable, guaranteed non-mutating:
tg-cli-ro --phone +15551234567 --code 12345 me
tg-cli-ro dialogs --limit 20 --json
tg-cli-ro history @peer --limit 50
tg-cli-ro search "hello world" --json
tg-cli-ro download @peer 12345 --out ~/pic.jpg
tg-cli-ro watchtg-cli send @peer "hi there"
echo "msg from stdin" | tg-cli send @peer
tg-cli send @peer --reply 12345 "threaded answer"
tg-cli edit @peer 12345 "corrected"
tg-cli delete @peer 12345 --revoke
tg-cli forward @srcchannel @dstchat 12345
tg-cli send-file @peer report.pdf --caption "final"
tg-cli read @peerPhotos attached to messages in history are exposed via download.
The default output path is
~/.cache/tg-cli/downloads/photo-<photo_id>.jpg; override with --out.
See docs/userstory/US-00-roadmap.md for the authoritative status. Short version:
- CLEAN layered architecture (core → infrastructure → domain → app)
- Three binaries (
tg-cli-ro/tg-tui/tg-cli) from one codebase - RAII memory safety via
__attribute__((cleanup)) - Logger + filesystem helpers + INI config store + cache store
- Platform abstraction (POSIX + MinGW-w64)
- Custom test framework;
./manage.sh test|valgrind|coverage - TL serialization + AES-256-IGE + MTProto encryption
- DH auth key exchange (PQ factorization, RSA_PAD,
new_nonce_hash1) - Session management + persistence +
bad_server_saltretry + service-frame draining - Abridged TCP transport with 3-byte length prefix
- RPC framework;
api_callwrapsinvokeWithLayer+initConnection - Phone + SMS code login with DC migration
- 2FA via SRP (
account.getPassword+auth.checkPassword) - Read: me, dialogs, history (self + peer), search, user-info, contacts, watch, photo download
- Write: send, reply, edit, delete, forward, read-markers, file upload (≤10 MiB documents)
upload.saveBigFilePartfor files > 10 MiB + media-DC migration- Per-variant skippers for Poll / Story / Game / Invoice / Giveaway / WebPage / PaidMedia media
- ReplyMarkup / Reactions / Replies / RestrictionReason / FactCheck trailers on Message objects
- Curses-mode TUI (US-11 v2) with pane-based live redraw
docs/
├── README.md ← index
├── SPECIFICATION.md ← product spec (living)
├── legal-research.md ← licensing, ToS compliance, AI/ML clause
├── userstory/
│ ├── US-00-roadmap.md ← authoritative status / backlog
│ └── US-*.md ← per-feature user stories
├── dev/
│ ├── mtproto-reference.md ← MTProto 2.0 protocol notes
│ ├── telegram-bot-api.md ← Bot API reference (for comparison)
│ ├── logging.md ← log levels, rotation, traffic capture
│ └── testing.md ← unit / functional test layout
├── adr/
│ ├── 0001-clean-architecture.md
│ ├── 0002-raii-memory-safety.md
│ ├── 0003-custom-test-framework.md
│ ├── 0004-dependency-inversion.md
│ └── 0005-three-binary-architecture.md
This is an unofficial Telegram client. See docs/legal-research.md for the full legal research including:
- Telegram API Terms of Service compliance
- Server RSA public key provenance (from TDLib, BSL-1.0)
- api_id registration requirements
- AI/ML clause analysis
- GPL/BSL licensing implications