5.4 KiB
telegram-tui
A minimal Telegram terminal client built with ncurses and TDLib.
Features
- interactive login flow inside the TUI
- chat list in the left pane
- message view in the right pane
- keyboard-first text compose, reply, edit, forward, and delete flows
- attachment browser and inline media preview
- clipboard image sending with
>paste/>clip - saved GIF picker backed by Telegram saved animations
- scroll chats and message history with the keyboard
Requirements
- CMake 3.21+
- a C++17 compiler
ncurses- TDLib build dependencies (
gperf,openssl,zlib,git)
The project vendors TDLib automatically by default. If you already have TDLib installed with CMake package metadata, configure with -DTELEGRAM_TUI_USE_SYSTEM_TDLIB=ON.
If you have a prebuilt TDLib bundle with include/ and lib/, configure with
-DTELEGRAM_TUI_TDLIB_ROOT=/path/to/tdlib.
Build
cmake -S . -B build
cmake --build build -j
During configure, CMake also checks the app config at
$XDG_DATA_HOME/telegram-tui/config.json or ~/.local/share/telegram-tui/config.json.
If that file contains api_id and api_hash, they are embedded into the build.
For CI or release builds, prefer setting TELEGRAM_TUI_BUILD_API_ID and
TELEGRAM_TUI_BUILD_API_HASH in the environment so credentials come from secrets instead of
local config.
Run
Create a Telegram application at https://my.telegram.org/apps, then either rely on the embedded credentials from the app config above, or export credentials:
export TELEGRAM_API_ID=123456
export TELEGRAM_API_HASH=0123456789abcdef0123456789abcdef
./build/telegram-tui
Or start the app without env vars and enter them interactively when prompted.
When entered in the TUI, the app now stores api_id and api_hash in
~/.local/share/telegram-tui/config.json and reuses them on later launches.
Clipboard image sending via >paste or >clip supports:
- raw clipboard images via
wl-clipboardon Wayland or KDE Plasma Wayland - raw clipboard images via
xclipon X11 - KDE Klipper clipboard entries that point to a local image file via
qdbus/qdbus6
Klipper by itself is still not a raw image backend for this feature.
To use Telegram test servers instead of production:
export TELEGRAM_USE_TEST_DC=1
./build/telegram-tui
The client stores TDLib state in ~/.local/share/telegram-tui/tdlib for production and ~/.local/share/telegram-tui/test/tdlib for test mode.
Gitea Actions
The repository includes .gitea/workflows/build-tdlib.yaml,
which builds the latest upstream TDLib tag on Gitea Actions and publishes a bundled TDLib
archive plus checksum to the Gitea Generic Package Registry under the tdlib package.
It also refreshes a latest/tdlib-latest.json manifest with the newest published version.
The repository also includes .gitea/workflows/release-app.yaml,
which downloads a prebuilt TDLib bundle from the shinoa-tdlib repository using a pinned
version tag such as v1.8.63, builds a
versioned app release tag such as v0.1.1, and publishes an archive containing usr/bin/shinoa plus the
bundled usr/lib/libtdjson.so*. The root PKGBUILD installs that prebuilt release as
shinoa-bin. The package disables debug splitting with options=(!debug). That workflow expects Gitea secrets named TELEGRAM_API_ID and
TELEGRAM_API_HASH. Release builds are configured to fail if those secrets are missing.
To prepare the TDLib bundle on your own machine:
cmake -S td -B td-build -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX="$PWD/td-install"
cmake --build td-build -j"$(nproc)"
cmake --install td-build
./scripts/package-tdlib.sh td-install tdlib-linux-x86_64.tar.gz
Publish tdlib-linux-x86_64.tar.gz to the shinoa-tdlib repository under a versioned tag such
as v1.8.63. Then update TDLIB_RELEASE_TAG in
.gitea/workflows/release-app.yaml and run the
Release App workflow.
Keys
Up/Down: move selectionTab: switch focus between chats and messagesEnter: open the selected chati: start composing a messagea: prepare a reply to the latest messageg: open the saved GIF picker for the current accountm: open the attachments browser for the current chato: open the selected attachment from the message panePgUp/PgDn: scroll the current message viewr: reload chats or historyEsc: cancel current inputq: quit
Compose Commands
While composing, these commands are available:
>r <msg> [text]: prepare a reply to a message reference>e <msg> <text>: edit one of your messages>f <msg...>: forward one or more messages>d <msg...>: delete one or more of your messages>paste [caption]or>clip [caption]: send an image from the clipboard
Message references can be a visible message number such as 12, a raw Telegram message id,
or a range/list such as 3,5,8-10 where supported.
Saved GIF Picker
Press g in an open chat to fetch saved animations from the account and open the picker.
Use Up / Down to move, r to refresh, and Enter to send the selected GIF.
If the GIF file is already cached locally, the picker renders a static preview frame using the
same preview backend as other media. For image previews, install one of chafa, kitten, or
img2sixel; for video/GIF thumbnail extraction, install ffmpegthumbnailer or ffmpeg.