CoolPugBot is a modular Aiogram 3 Telegram bot that bundles moderation, entertainment and utility commands with extensive localisation support. The repository now includes environment-based configuration, structured logging and unit tests so it can be shared and maintained as an open-source project.
- Modular architecture with dependency injection and dynamic module discovery.
- Roleplay, entertainment, moderation, filters, auto-delete and statistics modules.
- JSON-based localisation with runtime key generation.
- Structured logging to rotating text and JSON files for easier observability.
- Comprehensive documentation of bot commands.
- Python 3.11+
- A Telegram bot token obtained from @BotFather
Install dependencies with:
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txtCreate a .env file in the project root (or provide variables directly in the
environment) with the following variables:
| Variable | Description |
|---|---|
BOT_TOKEN |
Telegram bot token from BotFather (required). |
LOG_LEVEL |
Optional logging level for console output (default INFO). |
The application loads the .env file automatically on startup and will raise a
RuntimeError if any required variables are missing.
python main.pyLogs are written to logs/ as a timestamped text file, a rolling latest.log
and a JSONL file that is ready for ingestion into log analysis tools.
The project ships with unit tests covering configuration loading, localisation and storage helpers.
pytestBelow is a high-level overview of the commands provided by the bundled modules.
Use /help in chat to access an interactive version of this documentation.
| Command | Description |
|---|---|
/help |
Show the interactive help menu. |
/menu |
Exit the current menu. |
| Command | Description |
|---|---|
/ban |
Ban a user (supports duration and reason). |
/unban |
Remove a ban. |
/mute |
Temporarily or permanently mute a user from sending messages. |
/mediamute |
Remove media permissions while allowing text messages. |
/unmute |
Remove mute restrictions. |
/warn |
Issue a warning. Automatically mutes after three warnings. |
/unwarn |
Remove a warning. |
/kick |
Kick without ban. |
/modlevel |
Assign moderation levels (0–5). |
/restrict |
List members with a specific moderation level. |
/restrictcommand |
Restrict commands to a minimum level. |
/award / /delreward |
Manage custom awards. |
/mods |
List moderators with profile links (use mention=off to show plain names). |
| Command | Description |
|---|---|
/filteradd |
Add a filter (reply to a template message). |
/filterlist |
View filters for a trigger. |
/filterreplace |
Replace an existing filter template. |
/filterremove |
Delete a filter template. |
/filterclear |
Clear all filters for a trigger. |
/filterlistall |
List every stored filter in the chat. |
Supported placeholders inside filter templates:
{randomUser}, {randomMention}, {randomRpUser}, {argument} and {argumentNoQuestion}.
| Command | Description |
|---|---|
/autodelete |
Toggle auto-deleting a command. |
/nodelete |
Explicitly disable auto-delete for a command. |
/autodeletelist |
Show the configured auto-delete commands. |
| Command | Description |
|---|---|
/rpnick / /rpnickclear |
Manage roleplay nicknames. |
/addrp / /delrp |
Manage roleplay actions. |
/listrp |
List available actions. |
/profile |
Show roleplay stats for a user. |
| Command | Description |
|---|---|
/language |
Change the bot language for the current chat or private conversation. |
/top |
Show the top message senders for the current chat. |
| Command | Description |
|---|---|
/ask |
Get a response from the built-in assistant with recent memory context. |
All localisation files live in locales/. New languages can be added by copying
locales/en.json and translating the values. When the bot encounters a missing
key it automatically records the default string, making it easy to keep
translations in sync.
- Fork and clone the repository.
- Create a virtual environment and install dependencies.
- Run
pytestbefore submitting pull requests. - Ensure new strings are wrapped in
gettext()so they can be localised.