A plugin for exteraGram that turns your client into a TUI/CLI environment: a real shell, control over plugins and client settings, tooling for plugin authors, and a mode that renders the whole client as text.
Status: early development.
- A console, opened from the side menu, a chat's overflow menu, or by typing
.cliin any chat. - A POSIX-style shell: pipes, redirection including here-documents,
&&/||, variables and${...}forms,$(...), arithmetic, globbing,if,for,while/until,case, functions, aliases andsource. - Real programs through
/system/bin/shand the toybox applets, with a Python-implemented fallback set (ls,cat,grep,head, …) for devices where the system shell is unavailable. - Client commands:
plugin(list/info/enable/disable/reload/path/config),host(status/paths/doctor/version/class),log. - Colors taken from your Telegram theme, plus an Amoled theme.
| Client | exteraGram 12.9.0 or newer |
| Plugin SDK | 1.4.5.1 or newer |
| Android | 7.0+ (API 24) |
Install ElyxBuilder:
pip install ElyxBuilderFrom the repository root:
elyb build -v -nf # uncompiled
elyb build -c 2 -v -nf # compiled to bytecode (Python 3.11)The archive is written to builds/.
The character-grid renderer is Kotlin, shipped prebuilt as
extcli/dex/terminal.dex, so an ordinary plugin build needs no Java toolchain.
Rebuild it only when kotlin/ changes:
./scripts/kotlin-build.shThe script looks for its toolchain in $EXTCLI_TOOLCHAIN
(default /opt/extcli-toolchain), or in a local Android SDK:
| Tool | Where to get it |
|---|---|
kotlinc |
Kotlin releases → unpack as kotlinc/ |
r8.jar (provides d8) |
Google Maven |
android-all.jar |
Maven Central |
The shell, the output formatting layer and the TUI composer never import Android APIs, so they run off device:
python3 -m pytest tests/exteraGram targets SDK 36, so SELinux forbids executing files from the app's
data directory. extCLI therefore does not assume a bundled proot can run:
it probes the device at startup and picks a backend from what is actually
allowed — /system/bin/sh in a pty, in-process Python builtins, the dynamic
linker, or a Termux bridge. Run Diagnostics on the plugin's settings page
to see the result for your device.