tele
_ _
| |_ ___ | | ___
| __| / _ \ | | / _ \
| |_ | __/ | | | __/
\__| \___| |_| \___|
A terminal-native Telegram client built for keyboard-driven workflows.
Features • Installation • Why tele? • vs other TUI clients • Keybindings • Roadmap • Docs
Status: Active development - already usable for daily messaging (private chats, groups, replies, reactions, forwarding, drafts). Some Telegram features are still in progress.
Why tele?
Telegram Desktop, the web client, and mobile apps are designed around mouse-first interaction.
If you live in the terminal - using tools like Neovim, yazi, k9s, or tmux - switching to a GUI messenger breaks your flow.
tele keeps you in the terminal.
It is built for:
- keyboard-driven navigation
- fast chat switching
- SSH / remote workflows
- distraction-free messaging
tele will too.
It also runs lean - typically ~50MB RSS at idle vs several hundred MB for desktop clients.
Compared to other terminal clients
Nearly every terminal Telegram client is built on TDLib, Telegram's C++ library -
either linked directly or through a Python runtime. tele speaks MTProto itself
via gotd/td and builds without cgo, so there is no
C++ library to download or compile, no interpreter to keep on your machine, and
no chain of optional helper programs to install before the app is fully usable.
| | tele | tgt | tg · tuigram |
| ---------------- | ---------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| Language | Go | Rust | Python |
| Telegram backend | gotd/td - MTProto in pure Go | TDLib | TDLib via python-telegram |
| What you install | one static binary | cargo install plus TDLib downloaded or built; CMake to get voice notes; a system chafa to get inline images | a Python 3.9+/3.10+ runtime plus TDLib; ffmpeg, terminal-notifier, urlview, ranger/fzf for the full feature set |
| Packaging | brew, apt, dnf, zypper, apk, nix, scoop, winget, signed deb/rpm | crates.io, AUR, nix, Docker | PyPI, AUR, Docker |
| Inline photos | Kitty graphics protocol at full quality, ANSI block-art fallback | chafa block art, behind an optional build feature | handed to an external viewer via mailcap |
| Windows | binary, Scoop, winget | supported | not practical |
| Release cadence | weekly stable releases plus a separate beta channel | latest release is v1.0.0-rc1; most recent commits are dependency bumps | tg ships in bursts months apart; tuigram is a fork of a fork |
Beyond packaging, tele covers parts of modern Telegram that none of the three
list as supported: reactions, chat folders, grouped album sending,
and inline previews for video, round notes (кружки) and GIFs. Voice notes
play inside the app with a waveform and a moving playhead - no external
player, and no CMake step to build an Opus decoder. Chats open instantly from a
local SQLite history, themes come as eight built-in palettes that switch between
a dark and a light one as your terminal background changes (with
--theme-check to validate contrast), and every key is rebindable per context,
chords included.
Where they are ahead, honestly: tg and tuigram can record voice messages
(via ffmpeg) and support secret chats - the first is out of scope for
tele (why), the second is on the
backlog. Full-text
message search is also still ahead on the roadmap.
Fully abandoned projects are left out of the table: TelegramTUI (marked
deprecated, last touched in 2022), arigram (archived), tg-tui (2018),
Telegram-TUI, tg9 and ithil (early prototypes).
Features
- Keyboard-first UX - vim-inspired navigation (
gg/G, insert mode), plus a
j/k) that steps bubble-by-bubble and is the
target for the context menu and per-message actions. Mouse support is
optional: click a chat or a pane, scroll with the wheel.
- Full Telegram support - private chats, groups, channels, replies,
- Photos inline - full quality via the Kitty graphics protocol in kitty,
o opens the image
in an in-app viewer.
- Voice messages - waveform with duration and in-app playback (
p) with a
- Video, round notes (кружки) and GIFs - inline thumbnails, with the
- Sending media - attach a file with
u; press it again to stage more and
- Proxies, as in the official clients - an MTProto proxy (server, port and
tg://proxy link carries, fake-TLS included) or a SOCKS5 one,
set in the config for tele alone rather than for your whole shell, and used
by every connection, downloads included:
docs/configuration.md
- Terminal-native design - built for terminal workflows, not adapted from a
- Simple configuration - one YAML file with sensible defaults, and a
, that edits the same file, comments and all.
Recording is out of scope. tele can _send_ a pre-recorded audio or video
file, but it cannot record voice messages or round videos (кружки), and it
does not do voice or video calls: as a terminal-native, cgo-free client it has
no microphone or camera capture stack. This is an architectural boundary, not
a missing feature on the roadmap.
Details on every media type, in-app playback and the optional ffmpeg
dependency: docs/media.md
Installation
Any Unix (macOS · Linux · FreeBSD · OpenBSD · NetBSD) - one-liner
curl -sL https://raw.githubusercontent.com/sorokin-vladimir/tele/main/scripts/install.sh | sh
The script detects your OS and architecture and installs the matching binary from the latest release. Options:
# Latest beta (prerelease), installed as tele-beta so it coexists with stable:
curl -sL https://raw.githubusercontent.com/sorokin-vladimir/tele/main/scripts/install.sh | sh -s -- --beta
A specific version, or a custom install directory:
curl -sL .../install.sh | sh -s -- --version v1.9.0
curl -sL .../install.sh | PREFIX="$HOME/.local/bin" sh
BSD note: desktop notifications on FreeBSD use the terminal-native path (supported terminals only); audio playback needs a running PulseAudio/PipeWire server. Both degrade gracefully when unavailable.
macOS / Linux - Homebrew
brew install tele # from homebrew/core
Or from tele's own tap:
brew tap sorokin-vladimir/tap
brew trust sorokin-vladimir/tap
brew install sorokin-vladimir/tap/tele
Both formula names are written out in full on purpose. Once the tap is tapped, a
plain brew install tele picks the tap's formula and mentions it only in a
Warning: tele shadows homebrew/core/tele line that is easy to scroll past. The
two differ in one way worth knowing about, described under App key.
macOS / Linux - Homebrew (beta channel)
Want the latest merged changes ahead of the weekly stable release? Install the
beta package from the same tap. It ships as a separate tele-beta binary with
its own config and state (~/.config/tele-beta), so it lives alongside a stable
install:
brew tap sorokin-vladimir/tap
brew trust sorokin-vladimir/tap
brew install tele-beta
brew upgrade tele-beta # pull newer betas as they are cut
Beta builds come from prerelease tags (vX.Y.Z-beta.N) and are published as
GitHub prereleases, so they never show up as the "latest" release. Run it with
tele-beta.
Linux - binary
curl -sL https://github.com/sorokin-vladimir/tele/releases/latest/download/tele-linux-amd64 \
-o ~/.local/bin/tele && chmod +x ~/.local/bin/tele
For arm64: replace amd64 with arm64.
Debian / Ubuntu / Mint - apt
echo 'deb [trusted=yes] https://apt.fury.io/sorokin-vladimir/ /' \
| sudo tee /etc/apt/sources.list.d/tele.list
sudo apt update && sudo apt install tele
Fedora / RHEL / openSUSE - dnf / zypper
sudo tee /etc/yum.repos.d/tele.repo <<'EOF'
[tele]
name=tele
baseurl=https://yum.fury.io/sorokin-vladimir/
enabled=1
gpgcheck=0
EOF
sudo dnf install tele # or: sudo zypper install tele
Alpine - apk
echo 'https://alpine.fury.io/sorokin-vladimir/' | sudo tee -a /etc/apk/repositories
sudo apk add --allow-untrusted tele
Prefer a raw package? Signed.deband.rpmfiles are also attached to
every release.
Coming soon: AUR and Snap packages are planned but not published yet.
Windows - binary
Download the executable with PowerShell (run as your normal user):
$dir = "$Env:LOCALAPPDATA\Programs\tele"
New-Item -ItemType Directory -Force -Path $dir | Out-Null
Invoke-WebRequest
-Uri "https://github.com/sorokin-vladimir/tele/releases/latest/download/tele-windows-amd64.exe"
-OutFile "$dir\tele.exe"
For arm64: replace amd64 with arm64. Add $dir to your PATH (or run
tele.exe by full path) and launch it from any terminal. Photos are ANSI block
art there: inline images need a terminal that draws Kitty images through Unicode
placeholder cells, and no Windows terminal does that yet -
WezTerm has the Kitty graphics protocol but not the
placeholders (wezterm#7924).
Once a terminal gains them, photos.mode: kitty turns inline images on before
auto-detection learns to recognize it.
Prefer a packaged install? A.zipcontainingtele.exe
(tele_windows_amd64.zip) is attached to every release.
Prefer a package manager? Install with
Scoop or winget:
>> scoop install tele > # or > winget install sorokin-vladimir.tele >> scoop bucket add tele https://github.com/sorokin-vladimir/scoop-tele
Nix / NixOS
tele ships a flake. Try it without installing anything:
nix run github:sorokin-vladimir/tele
Or install it into your profile:
nix profile install github:sorokin-vladimir/tele
To pull it in as an input of your own flake (e.g. a NixOS configuration):
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
tele = {
url = "github:sorokin-vladimir/tele";
inputs.nixpkgs.follows = "nixpkgs";
};
};
}
Then, in your configuration:
environment.systemPackages = [
inputs.tele.packages.${pkgs.system}.default
];
A nix develop shell is also available in the repo for local development (go,
golangci-lint, lefthook).
First launch
tele
On first run, tele creates:
~/.config/tele/config.yml
Then prompts for:
- phone number
- SMS code
- optional 2FA password
App key
tele reaches Telegram with an app key: an api_id and api_hash pair that
identifies the application rather than you. There is nothing to do about it -
every build carries one, and the login above works as it stands.
Builds compiled from published source - homebrew-core, the Nix flake, a BSD
port, your own go build - share a single key. Telegram can refuse a key it
considers too widely shared, and then tele says app key blocked by Telegram
rather than claiming your session expired. Two ways past it, take whichever is
less trouble.
Register a key of your own at my.telegram.org and put
it in ~/.config/tele/config.yml. A key you supply always outranks the built-in
one:
telegram:
api_id: 123456
api_hash: "your api hash"
Or install an official build, which carries a key of its own: the Homebrew tap
above, the install script, apt, dnf, apk, Snap, Scoop and winget all ship
binaries built by tele's release pipeline.
More, including which Homebrew formula carries which key: docs/app-key.md
Flags
| Flag | Description |
| ----------------- | ---------------------------------------------------------------------------------------------- |
| --config | Path to config file (default ~/.config/tele/config.yml) |
| -e | Enable debug logging |
| --trace | Log sensitive metadata (peer IDs, message lengths). Never use on shared or synced file systems |
| --version | Print version and exit |
| --theme-check | Print which theme each slot resolved to and where its tokens came from, then exit |
| --theme-dump | Print a slot's theme as a complete theme file, then exit (--theme-dump=light) |
Keybindings
| Key | Action |
| ------------------- | ------------------------------------------------- |
| j / k | Navigate chats or select next / previous message |
| ctrl+j / ctrl+k | Scroll messages |
| i | Compose message |
| r | Reply |
| e / d | Edit / delete message |
| t | React |
| f | Forward message |
| u | Attach a file to send (repeat to send an album) |
| o | Open / view media (photo in viewer, video inline) |
| O | Open video in the external player |
| p | Play voice message in-app |
| s | Download the selected file |
| / | Search chats |
| space | Message context menu |
| 0 / 1 / 2 | Focus panes |
| , | Settings |
| ? | Keyboard shortcuts |
| q | Quit |
Full reference: docs/keybindings.md
Configuration
Everything lives in one YAML file, ~/.config/tele/config.yml, created on first
run.
Press , for the settings overlay: every setting tele has, in the same order
and grouping as the file, with what each one is worth now and when a change takes
hold. Changes go straight into config.yml, keeping your comments and blank
lines, so editing the file by hand and editing it in the overlay are the same
act.
Commonly changed settings:
ui:
history_limit: 50 # messages fetched per chat on open
# theme: # omit for the built-in tele-dark / tele-light
# dark: my-dark # ~/.config/tele/themes/my-dark.yml
# light: my-light
notifications:
desktop: true # hand it to the OS notification service
toast: true # draw it in a corner of tele's own window
preview: true # set false to send the sender's name and no message text
photos:
mode: auto # auto | kitty | blocks - inline image renderer
disk_cache_size: 268435456 # 256 MB of fetched chat media kept between runs
Every other key, and what each one does: docs/configuration.md
Themes
tele holds two themes at once and switches between them as your terminal
background changes: ui.theme.dark and ui.theme.light. Leave ui.theme out
and you get the built-in tele-dark and tele-light.
Eight ready-made themes ship inside the binary - Catppuccin Macchiato, Dracula, Gruvbox Dark, Nord, Tokyo Night (Night, Moon and Day) and Seoul256 Light. There is nothing to install and nothing to copy: name one and it is there.
ui:
theme: tokyonight-night
Your own themes are files in ~/.config/tele/themes/, and a theme sets only the
tokens it cares about and inherits the rest. The bundled sources, fully commented
with the palette each was ported from, are in themes/.
Writing one, every token, and the contrast checks: docs/themes.md
Customizing keybindings
Override default keys in the keybindings: section of the config file. The
generated config already lists every action with its current default keys,
commented out, grouped by context.
The key syntax, chords, how conflicts are handled and the full list of action names: docs/keybindings.md
Roadmap
Planned work lives on the public project board,
grouped into milestones. Milestones track
minor lines (v1.11, v2.0, …); patch releases ship incrementally within a line as fixes land.
| Release | Focus |
| ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| v1.11 _(in work)_ | Settings & people - in-app settings overlay, user profile overlay, avatars, themes shipped inside the binary, plus the distribution and audit gaps left behind |
| v2.0 _(planned)_ | Single owner of the Telegram connection - a resident daemon with attachable TUI and CLI clients, headless scripting, background notifications |
| Backlog | Power-user & platform - search (full-text history, command palette, in-chat grep), voice and round-video messages, scheduled sending, bot commands & inline keyboards, secret chats, polls, extended vim motions, notification click routing |
Work is also categorized by theme (Security & Reliability, Architecture & Performance, Feature Completeness, Power User & Polish) via the board's Theme field.
Build from source
Requires Go 1.26+. The binary this produces carries the shared app key described under App key, so it runs without you registering anything:
git clone https://github.com/sorokin-vladimir/tele
cd tele
go build -o tele ./cmd/tele/
Building with your own app key, the nix develop shell and the flake's
vendorHash: docs/development.md
Documentation
- Configuration - the config file, the settings overlay, notifications, photo and avatar caches
- Keybindings - every key by context, and how to rebind them
- Themes - theme slots, writing your own, every color token
- Media - inline photos, voice playback, video, GIFs, sending files
- App key - what it is, and what to do when Telegram blocks it
- Development - building from source, the Nix flake
- Contributing - how to propose a change
License
GPL-3.0 - free to use and fork; derivative works must remain open-source.
Built with: