KaguyaUserBot — an asynchronous, lightweight, modular Telegram client (UserBot) featuring parallel assistant-bot integration, dynamic "hot-loading" of custom modules, and multi-language support.
📦 Official Modules Directory •
📥 Installation •
🛠️ Developer Guide
KaguyaUserBot is an event-driven framework built on top of the kurigram library (a high-performance and actively maintained fork of pyrogram). The main goal of the project is to provide developers and users with a flexible, lightweight environment to run userbots and automate daily tasks without the need to deploy heavy external database management systems (DBMS).
- Microkernel Architecture: The core client
KaguyaClientacts as a lightweight kernel. It is solely responsible for authentication, reading global settings, session maintenance, and event routing. All application logic is offloaded to decoupled, dynamic modules that can be loaded and unloaded on the fly. - Hybrid Operation Mode: Two clients run concurrently within a single Event Loop: the userbot (via MTProto) and the assistant bot (via Telegram Bot API). They interact through a shared database and complement each other, allowing for interactive inline menus and buttons in any chat.
- Shared Local Database: Instead of deploying heavy external database servers, the project utilizes an embedded Key-Value store based on the
diskcachelibrary (running on top of optimized SQLite with an asynchronous wrapper viaasyncio.to_thread). The database supports TTL (Time-To-Live) for automatic expiration and category-based data isolation. - Internationalization (i18n): The userbot is equipped with a fast localization system (ISO 639-1 standard). The active system language is cached in the client's RAM (
client.get_lang()), allowing modules to translate their interface on the fly without any disk-read latency or database overhead. - Media Resource Caching: To conserve network bandwidth and prevent
Flood Waitissues, the project employs theedit_media_cachedmethod. Upon sending an interface media file from disk for the first time, thefile_idreceived from Telegram servers is cached. All subsequent calls to this menu utilize the cachedfile_id, ensuring near-instant rendering.
WARNING: Running userbots violates the official Telegram Terms of Service (Terms of Service), as it automates account actions via the MTProto API.
- The project author is not responsible for any potential blocks or restrictions placed on your account by Telegram's anti-spam algorithms.
- The Kaguya client mimics the official Windows Desktop client to minimize detection risks; however, complete safety cannot be guaranteed.
- Module Security: Installed modules run within the same process as the core client and have full access to your session files (
.session) and environment variables. Only install modules from trusted sources!
To run an MTProto client, you must obtain API keys from Telegram:
- Log in to my.telegram.org.
- Navigate to API Development Tools and create a new application.
- Save your
API_IDandAPI_HASHvalues.
The project features an automated bootstrap script that sets up a Python virtual environment (venv) and installs all dependencies in one click.
- Install Python 3.11 or higher (make sure to check "Add Python to PATH" during installation).
- Download and unpack the KaguyaUserBot repository.
- Run
[Windows]Kaguya_run.bat. - The script will verify your environment, install dependencies, and automatically generate an empty
.envconfiguration file in the project root (a template is also available in.env.example). - Open
.envin Notepad and insert your keys:API_ID=your_api_id API_HASH=your_api_hash
- Save the file and run
[Windows]Kaguya_run.batagain. Enter your phone number and the Telegram confirmation code to establish a session.- Note on compilation: The
tgcryptoencryption acceleration library requires a C++ compiler to build from source on Windows. Our launcher[Windows]Kaguya_run.batautomatically catches compilation errors, skips them, and runs the bot using Python's built-in cryptographic fallbacks seamlessly.
- Note on compilation: The
To run the userbot on smartphones, the Termux terminal emulator is used.
- Install the Termux application (the F-Droid build is highly recommended).
- Launch Termux and execute the command for automated project initialization:
bash [Termux]Kaguya_run.sh
- The script will automatically install
python,git, configure the virtual environment, and install dependencies. - Copy the environment configuration template:
cp .env.example .env
- Open
.envin a built-in terminal editor (e.g.,nano .env), configure yourAPI_IDandAPI_HASH, then run the script again to authenticate.
Step 1. Prepare Server
Connect to your VPS via SSH and install the required system packages:
sudo apt update && sudo apt upgrade -y
sudo apt install python3 python3-venv python3-pip git nano -yStep 2. Clone and Setup Project
git clone https://github.com/cxvimba/KaguyaUserBot.git
cd KaguyaUserBotCreate a virtual environment, activate it, and install dependencies:
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txtCopy the environment configuration template:
cp .env.example .env
nano .envType your API_ID and API_HASH in the opened nano text editor, save changes (Ctrl+O ➔ Enter), and exit via Ctrl+X.
Step 3. Initial Launch and Authorization
Run the script manually once to complete authorization and generate a session file:
python3 main.pyEnter your phone number and the Telegram verification code. Once Kaguya indicates that it has successfully started, stop it by pressing Ctrl + C.
Step 4. Configure 24/7 Autostart via Systemd (Recommended)
To ensure the bot runs persistently in the background and restarts automatically on server reboot, configure a systemd service.
Create the service file:
sudo nano /etc/systemd/system/kaguya.serviceInsert the following template (replace /root/KaguyaUserBot with your actual project directory path, if different):
[Unit]
Description=Kaguya UserBot Service
After=network.target
[Service]
Type=simple
WorkingDirectory=/root/KaguyaUserBot
ExecStart=/root/KaguyaUserBot/.venv/bin/python main.py
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.targetSave the file (Ctrl+O ➔ Enter ➔ Ctrl+X). Activate and start the service:
sudo systemctl daemon-reload
sudo systemctl enable kaguya.service
sudo systemctl start kaguya.serviceThe assistant bot outputs interactive inline keyboards, flag grids, and settings menus.
- Go to the official @BotFather bot in Telegram and create a new bot (
/newbot). - In your bot settings, navigate to
Bot Settings ➔ Inline Modeand enable it. - In the same menu, go to
Inline Feedbackand select100%(required for proper Inline callback operation). - Send the bind command to your running userbot in any chat:
.token <your_BotFather_token> - On-the-fly validation: The userbot will instantly launch the assistant in the background, send a hidden inline query to verify inline mode activity, and bind it to the core.
- If inline mode is disabled in BotFather, the assistant bot will automatically stop, wipe the token from the database, and display a detailed graphic guide on how to fix the issue.
Upon a successful startup, you will receive a confirmation message in your Saved Messages («me») indicating system readiness, along with a quick tip on changing localization via the .lang <code_here> command.
The Kaguya framework supports two module formats in the kaguya/modules/ directory:
- Single-file modules (simple
.pyscripts). - Package modules (complex modules with assets, configs, and submodules), containing an entry-point
__init__.pyfile.
To support multilingual localization and enable proper IDE integration (autocomplete hints in PyCharm Pro), any module should inherit from BaseModule, declare a class-level LANGUAGES dictionary, and use strict type hints.
from pyrogram import Client
from pyrogram.types import Message
from kaguya.types import BaseModule, ModuleInfo, on_command
from typing import TYPE_CHECKING
# Circular import protection and PyCharm Pro autocomplete activation
if TYPE_CHECKING:
from kaguya.client import KaguyaClient
class AutoReply(BaseModule):
meta = ModuleInfo(
name="Auto-Responder",
description="Saves and automatically outputs replies in chat",
version="1.1.0",
author="cxvimba",
commands={
"set_reply | задать_ответ": "Save auto-reply (format: .set_reply word | response)"
}
)
# Localization dictionary.
# The first language in the dict (in this case, "en") automatically becomes
# the default fallback if the user selects a language unsupported by this plugin.
LANGUAGES = {
"en": {
"usage": "❌ **Kaguya:** Format: `.set_reply trigger | reply text`",
"separator": "❌ **Kaguya:** Split trigger and reply using `|`",
"success": "✅ **Kaguya:** Auto-reply for «{trigger}» successfully saved!"
},
"ru": {
"usage": "❌ **Kaguya:** Формат: `.set_reply триггер | текст ответа`",
"separator": "❌ **Kaguya:** Разделяй триггер и ответ символом `|`",
"success": "✅ **Kaguya:** Автоответ на слово «{trigger}» успешно сохранен!"
}
}
@on_command(["set_reply", "задать_ответ"])
async def set_reply_cmd(self, client: "KaguyaClient", message: Message):
"""Parses arguments and saves auto-reply into the local database."""
if len(message.command) < 2:
# Synchronously fetch the localized string via BaseModule's get_text helper
await message.edit_text(self.get_text("usage"))
return
raw_text = message.text.split(maxsplit=1)[1]
if "|" not in raw_text:
await message.edit_text(self.get_text("separator"))
return
trigger, reply_text = map(str.strip, raw_text.split("|", 1))
# Access diskcache-backed SQLite local DB through categories
db = self.client.db.get_category("auto_responses")
await db.set(trigger.lower(), reply_text)
# Display formatted output with automatic translation lookup
await message.edit_text(self.get_text("success").format(trigger=trigger))For Kaguya to recognize a directory as a package module, an __init__.py file must be present inside it. All handlers and command logic can be split into separate files (e.g., commands.py) and then imported and bound as class attributes in __init__.py:
# kaguya/core_modules/system/modules.py
@on_command(['modules', 'модули'])
async def list_modules(self, client: Client, message: Message):
...
# kaguya/core_modules/system/__init__.py
from kaguya.types import BaseModule, ModuleInfo
from .modules import list_modules, install_module
class SystemModule(BaseModule):
meta = ModuleInfo(
name='System',
description='Kaguya core system utilities',
version='1.1.0',
author='cxvimba',
commands={
'modules': 'Module list',
'install': 'Install custom module'
}
)
# Multilingual support at the package-class level
LANGUAGES = {
"en": { "no_modules": "⚠️ No loaded modules found." },
"ru": { "no_modules": "⚠️ Нет загруженных модулей." }
}
# Bind functions imported from external files as class methods
list_modules = list_modules
install_module = install_moduleIf your plugin includes custom images or interactive menu covers, you can load localized images dynamically by running a quick file existence check:
# Fetch system language directly from KaguyaClient's RAM cache
lang = client.get_lang()
# Format path to localized file
local_path = f'assets/Kaguya_modules_{lang}.png'
# Fallback to default asset if localized file is missing
if not os.path.exists(local_path):
local_path = 'assets/Kaguya_modules.png'
# Set unique Telegram cache keys for each localized file to prevent overlapping
cache_key = f'modules_menu_file_id_{lang}'
await client.edit_media_cached(
message=message,
cache_key=cache_key,
local_path=local_path,
caption=text
)@on_command(command_name: str | list[str])— Registers a userbot chat command. Supports alias lists and is case-insensitive. Works via a custom dynamic filter retrieving command prefixes directly from the running client's memory.@on_assistant_command(command_name: str | list[str])— Registers a text command handler for the assistant bot (e.g.,/start).@on_assistant_inline()— Handles incoming inline queries sent to the assistant bot.@on_assistant_callback(pattern: str)— Handles button click callback queries with pre-filtering bycallback_dataprefix.
To prevent unauthorized users from hijacking your assistant buttons in public chats, implement sender verification checks:
# Example from the system translator module
@on_assistant_callback('tr_')
async def translator_callback(self, client: Client, callback_query: CallbackQuery):
settings = client.db.get_category('settings')
owner_id = await settings.get('owner_id')
# Block unauthorized clicks
if callback_query.from_user.id != owner_id:
await callback_query.answer(
text='Kaguya: Hey, this is not your control panel!',
show_alert=True
)
returnWhen dynamically installing plugins via the .install / .установить commands (by replying to a .py, .txt, or .zip file), the core client automatically runs static code analysis checks prior to compilation.
The analyzer scans the incoming code for the following blocked call patterns:
eval(, exec(, __import__, os.system, subprocess, .session, session_path.
If any match is detected, the installation terminates immediately, and temporary files are securely deleted from the disk to prevent any environmental impact.
Q: The [Windows]Kaguya_run.bat script throws a "Failed building wheel for tgcrypto" error. Will the bot start?
A: Yes, it will start and operate normally. This error occurs because pre-compiled wheel packages of tgcrypto are not always available for all Windows environments. You can install a C++ compiler to compile it, but the bot will automatically fall back to Python's built-in cryptographic solutions and run stably without it.
Q: How do I add external dependencies for my custom module?
A: Since the Kaguya core should remain clean and independent, you do not need to add your packages to the root requirements.txt. Instead, use the standard Python import exception handling pattern at the top of your custom module:
try:
import some_library
except ImportError:
raise ImportError("This module requires the 'some_library' package. Install it via terminal: pip install some_library")When installing your module via .install, the framework will catch the ImportError safely and display your installation instructions in the Telegram chat instead of crashing.
Q: My assistant bot does not respond to button clicks or inline queries. What should I do?
A: The most common cause is that inline mode is disabled in BotFather. Please follow the inline setup guide in Section 4.
Q: How do I run Kaguya 24/7 on a remote server?
A: The most reliable way is using a VPS running Linux (Ubuntu/Debian). Follow the complete setup and daemonization guide in the Ubuntu section.
Q: Where are the bot settings and cache stored? How do I reset them completely?
A: All persistent configuration and cached files are stored in data/storage/ as optimized SQLite Key-Value tables managed by diskcache.
- To unbind your helper bot, use the
.token_rmcommand. - To perform a complete factory reset, stop the bot in the terminal and delete the
data/folder. Kaguya will recreate clean databases automatically upon next boot.

