← ceesaxp.github.io
✈️

tele-tui

A Telegram client that lives in your terminal. Keyboard-first, vi-shaped, borderless — and the same account exposed to your agents over MCP and REST.

Go TUI MCP REST

🖥️ The Frame

tele-tui — 120×40
 tg  1:all 2:unread 3:work 4:channels 5:archive                                          connected · 1 device21:04 
 / filter chats…                  9/9  # infra-oncallgroup · … buf 1 │ ln 44/44  bot  PINNED                       
# infra-oncall                 2m       09:16     nadia  ↳ you Taking 4412. Backoff c…   Deploy window 14:00–1… ivo 
  nadia: rebased, CI green       [4]                     Yes, jittered. Full ±20%.       Runbook: auth p95 s… nadia 
 @ Nadia Feld                   6m     TODAY ──────────────────────────────────────────                               
   you: pushing the tag now              20:41       ivo  Rollout paused — session hits  MEMBERS · 24                 
 # relay-protocol               14m                       spiked on the auth path.        ivo                  admin 
   ivo: the 429 is upstream       [2]                     @nadia can you look?            nadia                      
 ~ wire notes                   1h                         auth-p95-260…  184 KB · png   sam                        
   draft: saved locally                                   [👀 5] [🔥 2]                   mira                    4h 
 ! ops-alerts muted             2h       20:44       sam  The offending query, for the    jonas                   2d 
   p95 back under 400ms          (31)                     record:                        · +19 more                   
 @ Mira Okonkwo                 4h                         sql ───────────── 4 lines                                
   sounds good — thurs then                               1  SELECT s.* FROM session…  FILES                        
 # design-crit                  yd                        2    JOIN devices d ON d.s…   auth-p95-2608.png     184K 
   you: left comments on 3                                3  - WHERE s.touched > now…   incident-0812.md        6K 
 ! tape/changelog muted         yd                        4  + WHERE s.touched > now…   backoff.patch           2K 
   v0.4.1 — keymap overhaul                               └───────────────────────────┘                               
 @ Jonas Vik                    2d       20:47     nadia  That is the migration                                       
   thanks, that unblocked me                              backfill, not the rollout. It                               
                                                          drains in ~20 min.                                          
                                         20:52       you  Confirmed from the queue                                    
                                                          dashboard. Resuming.  ✓✓                                    
                                       4 NEW ──────────────────────────────────────────                               
                                         20:58       ivo  Resumed. Canary at 5%.                                      
                                         21:01     nadia  ↳ ivo Resumed. Canary at 5%.                                
                                                          Rebased onto main, CI is                                    
                                                          green now. 4412 ready for the                               
                                                          second approval.                                            
                                         21:02       sam  Approved. Merging behind the                                
                                                          flag.                                                       
                                                          [🚀 4]                                                      
                                        21:03       ivo  Good. I will write the                                      
                                                         incident note either way —                                  
                                                         cheap to have, expensive to                                 
                                                         reconstruct.                                                
                                                     ···  nadia is typing…                                            
                                       reply  nadia: Rebased onto main, C… esc to drop                               
                                       NORMAL  i to compose · : for commands        md                               
 j/k move  l open  / filter  [/] folder  u unread  i compose  q quit  ? keymap      idx 12 msgs · 9 buffers · 37 unread 

Not a screenshot — this is the renderer's own output, the same 120×40 golden fixture the test suite asserts against cell for cell, with its real colours. Every row is exactly 120 display cells wide; the suite fails if one is not. Sample data, no real conversations.

📐 A Terminal Tool, Not a Chat GUI in a Box

Most terminal chat clients draw a desktop app with ASCII. This one does not. There are no bubbles, no avatars, no rounded boxes — panels are divided by single-cell rules, messages sit on a fixed time / sender / body grid so the whole conversation aligns to one column, and every row is exactly the width of your terminal.

Graphics are opt-in. Media normally appears as a metadata card; a photo is drawn in the pane only when you open it. Code fences are framed and line-numbered, quotes get a rule, spoilers stay hidden until you press x.

It is modal, and it says so: the composer carries a NORMAL / INSERT / VI / COMMAND badge, so one glance answers whether the next letter types, navigates, or runs a command.

What's In It

Folders & unread

Telegram's own folder filters as numbered tabs, with pinned/include/exclude semantics. u jumps to the next chat with something in it.

Reactions & pins

+ opens a one-row picker of the twelve defaults and opens on the one you already left, so pressing it again takes it off. p pins.

Forwarding

f opens a searchable destination picker — your chats first, then anything the server matches — and confirms before it sends.

Threads

A channel post with comments says so, and t opens the discussion in the linked group at the post's own copy.

Context rail

Thirty cells beside the thread: pinned messages, members, shared files and links — chosen by chat type, fetched only when you open it.

Composer that behaves

Per-chat drafts, emacs or vi line editing, Ctrl+O to finish the message in $EDITOR, clipboard image paste, optional Markdown.

⌨️ The Keymap Is vi's

Motions are vi's and are not configurable — j/k move by message, Ctrl+E/Ctrl+Y scroll the buffer, and a count prefix works (9k moves nine messages back). The action keys are mnemonics and every one of them can be rebound; a binding that collides with something already claimed is refused and reported at startup rather than silently shadowing it.

KeyDoes
j / kCursor to the next / previous message
h / lMove between panels — they are edges, not a cycle
[ / ]Previous / next folder, from either browsing panel
iOpen the cursored chat and start composing
r / e / dReply, edit, delete — d asks, and says for whom
fForward to another chat
+ / pReact / pin
/ · Ctrl+GSearch this buffer · search every chat
:Command palette
?Context-sensitive help, built from the bindings actually in force

🔌 Three Front Ends, One Account

The same Telegram layer ships as three binaries: tele-tui (the client above), telegram-mcp (an MCP server over stdio) and telegram-api (a JSON REST API, standard library only).

The service front ends are built for being pointed at an agent, which is a threat model rather than a feature list. The REST API is loopback-only and bearer-authenticated by default, and refuses to start unauthenticated unless you say so explicitly. Sending a file is limited to an allowlist of directories you choose — logged at startup — so a message from a stranger cannot talk a model into mailing out your SSH key.

# MCP, over stdio telegram-mcp login telegram-mcp serve # or the REST API, on loopback with a generated token telegram-api serve

📦 Installation

🍺 Homebrew — macOS and Linux, Intel and ARM. Installs all three binaries.

brew install ceesaxp/tap/tele-tui

🐹 Go toolchain — if you already have Go 1.25 or newer.

go install github.com/Ceesaxp/telegram-cli/cmd/teletui@latest # the MCP server and the REST API are their own commands go install github.com/Ceesaxp/telegram-cli/cmd/telegram-mcp@latest go install github.com/Ceesaxp/telegram-cli/cmd/telegram-api@latest

Two things to know about this route. The binary lands in $GOPATH/bin as teletui, not tele-tuigo install names it after its directory, while the release archives and make build both call it tele-tui. And it reports its version as dev, because the version is stamped in at link time by the Makefile and go install does not run it. Neither affects what the program does.

Or build from source. Whichever route you take you need your own api_id / api_hash from my.telegram.org/apps — the client talks to Telegram as your account, not through a bot.

git clone https://github.com/Ceesaxp/telegram-cli.git cd telegram-cli make build ./bin/tele-tui # first run walks you through login

Pure Go, no CGO, no native dependencies. Cross-compiled builds for macOS, Linux, Windows and Android are published on the releases page.

🌱 Where It Came From

This is a fork, not a from-scratch project. It began as imtaqin/telegram-cli — excellent work, and the foundation everything here is built on.

It has since diverged substantially. The interface was rebuilt around a terminal-native design rather than a chat GUI drawn in ASCII, and the client gained update-sequence persistence, chat folders, reactions, pinning, channel discussions, a context rail, per-chat drafts, message forwarding, and a good deal more — along with the MCP and REST front ends. Enough has changed that calling it the same program would be misleading in the other direction.

Upstream is not responsible for anything here. The project stays MIT-licensed, and the original copyright notice travels with it.