Fast and extensible Telegram userbot written in Rust
Runs directly over MTProto, targets Linux, and provides first-class declarative NixOS integration.
Lavis is a personal Telegram userbot built in Rust on top of grammers.
It works through your Telegram account, handles commands from your own messages, edits the original command message with the result, and supports both built-in commands and external modules.
,ping
,stats
,fastfetch
,help
The default prefix is ,, but it can be changed at runtime.
| Feature | Description |
|---|---|
| β‘ Native Rust core | Async Telegram access directly over MTProto |
| π Local authorization | Telegram session and API credentials stay local with restrictive permissions |
| βοΈ Message editing | Command output replaces the original outgoing message |
| π§© External modules | Language-agnostic modules over a JSON Lines protocol |
π¦ .lmod packages |
Reviewed module installation through Saved Messages |
| π Module API v6 | Capability-based events, Telegram RPC adapters and bounded raw MTProto access |
| π§ NixOS integration | Flake, package, dev shell and ready-to-use NixOS module |
| π§ Prefixes and aliases | Persistent aliases and configurable command prefix |
| π€ Companion bot | Optional BotFather-backed companion/workspace setup |
| π₯οΈ Fastfetch | Fastfetch passthrough with user arguments |
| π English / Russian UI | Persistent interface language and onboarding |
Create an application at my.telegram.org/apps and obtain:
API ID;API hash.
nix run 'git+https://tangled.org/zumuvik.tngl.sh/lavis'On first interactive launch Lavis stores the API credentials locally and asks for the Telegram phone number, login code and, when enabled, the two-factor password.
Authorization can also be started explicitly:
nix run 'git+https://tangled.org/zumuvik.tngl.sh/lavis' -- authAfter authorization, start the Telegram introduction from Saved Messages:
,start
Choose the interface language explicitly if needed:
,start en
,start ru
Important
Never publish your API hash, credentials.json, Telegram session database, companion token, XDG state directories, or authorization logs containing secrets.
| Command | Purpose |
|---|---|
start |
Start or continue onboarding |
language |
Show or change the interface language |
help |
Command, alias and module help |
modules |
Built-in and active external modules |
ping |
Live Telegram RPC latency |
stats |
Uptime, latency, process and host statistics |
prefix |
Show, set or reset the command prefix |
alias |
Manage persistent command aliases |
fastfetch |
Runs the system fastfetch with passed arguments |
setup |
Companion bot/workspace setup and repair |
lm |
Install and control external .lmod modules |
reboot |
Restart the Lavis process |
Command examples
,help
,help fastfetch
,modules
,ping
,stats
,prefix .
.alias add sys fastfetch --logo arch
.sys
.lm list
An external Lavis module is a separate executable communicating with the core through JSON Lines over stdin and stdout.
Modules can be written in Rust, Go, Python, or any other suitable language. The current Module API v6 supports capability-gated Telegram operations, message events and a bounded raw MTProto escape hatch.
The repository ships a reference external module, Cleaner (modules/cleaner): scheduled deferred cleanup of your own messages, per-group management, and an opsec scan that surfaces ghost chats still holding your messages β ,cleaner [list|add <n>|remove <n>|status|log|run|opsec [add <n>]].
Local module operations:
lavis modules validate ./my-module/module.json
lavis modules enable my-module
lavis modules disable my-module
lavis modules status-
Attach a
.lmodarchive to a new self-authored message in Saved Messages. -
Send:
,lm install -
Review the installation plan.
-
Confirm the one-time approval ID:
,lm confirm XXXX-XXXX-XXXX-XXXX -
Enable the module and restart Lavis:
,lm enable <module-id> ,reboot
Useful commands include ,lm list, ,lm info <id>, ,lm logs <id> and ,lm doctor [id].
Warning
External modules are not placed in a system sandbox and run with the Lavis user's OS permissions. Capability checks constrain core-mediated operations, not arbitrary OS access. Install only code you trust.
See External modules, .lmod packaging, and Module API v6.
Lavis locks the local Telegram session and distinguishes recoverable authorization problems from deterministic session corruption.
Useful CLI commands:
lavis credentials
lavis credentials reset
lavis auth doctor
lavis auth reset --backup
lavis logoutauth doctor inspects the local session. auth reset --backup replaces a broken session while preserving a backup. logout removes only the local session and does not revoke Telegram sessions remotely.
Add Lavis to your flake inputs:
{
inputs.lavis.url = "git+https://tangled.org/zumuvik.tngl.sh/lavis";
}Lavis publishes Nix build outputs to Cachix. Add the cache declaratively so Nix can download prebuilt Lavis packages instead of compiling them locally:
{
nix.settings = {
extra-substituters = [ "https://lavis.cachix.org" ];
extra-trusted-public-keys = [
"lavis.cachix.org-1:EXJoSAQxNZb8j/p/2DrBBLmOXHP0VemCUZ5FdifeHbg="
];
};
}Then rebuild your NixOS configuration normally. Future Lavis outputs that are available in the cache will be substituted from lavis.cachix.org instead of being built locally.
Import the module and enable the service:
{
imports = [ inputs.lavis.nixosModules.default ];
services.lavis = {
enable = true;
autoStart = false;
credentialsEnvironmentFile = "/run/secrets/lavis.env";
};
}By default the module creates the dedicated lavis system user with home /var/lib/lavis. After applying the configuration, authorize through the supplied helper and start the service:
sudo lavis-auth
sudo systemctl start lavis.serviceAfter successful authorization, autoStart can be enabled.
Declarative external modules are also supported:
services.lavis.extensions = [
{
id = "gaf";
package = inputs.lavis.packages.${pkgs.system}.lavis-extension-gaf;
}
];See NixOS module for service, recovery and declarative extension details.
The same flake ships x86_64-linux and aarch64-linux outputs, so Lavis runs on
any Linux distribution with Nix and flakes enabled β no NixOS required. The binary
package is fully self-contained in the Nix store; fastfetch is already wired into
the wrapper's PATH.
Add the binary cache to ~/.config/nix/nix.conf so future updates are substituted
instead of compiled locally (aarch64 outputs are usually not cached yet):
extra-substituters = https://lavis.cachix.org
extra-trusted-public-keys = lavis.cachix.org-1:EXJoSAQxNZb8j/p/2DrBBLmOXHP0VemCUZ5FdifeHbg=Install and authorize once interactively:
nix profile install 'git+https://tangled.org/zumuvik.tngl.sh/lavis'
lavis authRun it as a systemd user service in ~/.config/systemd/user/lavis.service:
[Unit]
Description=Lavis Telegram userbot
After=network-online.target
Wants=network-online.target
[Service]
ExecStart=%h/.nix-profile/bin/lavis run
WorkingDirectory=%h
Environment=LAVIS_SERVICE=1
Restart=on-failure
# Status 78 means interactive reauthorization is required; retrying cannot fix it.
RestartPreventExitStatus=78
RestartSec=5s
[Install]
WantedBy=default.targetsystemctl --user daemon-reload
systemctl --user enable --now lavis.service
loginctl enable-linger "$USER"Update with nix profile upgrade '.*' followed by
systemctl --user restart lavis.service; rollback is nix profile rollback.
State lives in the XDG directories below and survives updates.
Lavis keeps mutable data outside the Nix store under XDG paths:
$XDG_CONFIG_HOME/lavis/ # credentials, companion token
$XDG_STATE_HOME/lavis/ # MTProto session, settings, aliases and runtime state
$XDG_DATA_HOME/lavis/ # installed modules and staging data
Without explicit XDG variables these resolve under ~/.config, ~/.local/state and ~/.local/share.
git clone https://tangled.org/zumuvik.tngl.sh/lavis
cd lavis
nix develop
cargo runProject checks:
cargo fmt --check
cargo check --all-targets --all-features
cargo clippy --all-targets --all-features -- -D warnings
cargo test --all-targets --all-features
nix flake check --print-build-logs
nix build --print-build-logs| Document | Scope |
|---|---|
| Companion bot setup | BotFather flow, workspace resources and recovery |
| External modules | External module lifecycle and runtime model |
.lmod packaging |
Packaging and validation rules |
| Module API v1 | Early module metadata/API |
| Module API v2 / v3 | Manifest and event protocol evolution |
| Module API v4 | Message edits and reaction sets |
| Module API v5 | Telegram account-status gateway |
| Module API v6 | Capability-based Telegram RPC and raw MTProto boundary |
| NixOS module | Declarative service configuration |
| CONTRIBUTING.md | Development and contribution guide |
Lavis has access to the authenticated Telegram session.
- do not run untrusted Lavis builds;
- do not install unknown external modules;
- do not publish API credentials or session files;
- do not share Lavis XDG directories;
- prefer
RUST_LOG=lavis=debugover globally enabling dependency debug logs; - remember that Fastfetch may expose host information.
Lavis is under active development and is currently alpha software. Module APIs, .lmod format, persistence schema, commands and Nix interfaces may change incompatibly.
Lavis is an unofficial Telegram client. Userbot usage may lead to account restrictions or loss. You are responsible for your Telegram account, installed modules, credentials and compliance with Telegram rules and applicable law.
Copyright Β© 2026 zumuvik.
Lavis is licensed under GNU GPL-3.0-only.