Первый модульYour first module
Модуль — Python-файл с классом, унаследованным от loader.Module. @loader.tds подключает строки перевода, а @loader.command() регистрирует команду. Сохрани пример как hello.py.A module is a Python file containing a class derived from loader.Module. @loader.tds enables translated strings, and @loader.command() registers a command. Save this example as hello.py.
# © Your name, 2026
from .. import loader, utils
@loader.tds
class HelloMod(loader.Module):
"""A small greeting module."""
strings = {"name": "Hello", "hello": "Hello, {}!"}
strings_ru = {"hello": "Привет, {}!"}
@loader.command()
async def hello(self, message):
"""[name] — Send a greeting."""
name = utils.get_args_raw(message) or "world"
await utils.answer(
message,
self.strings["hello"].format(utils.escape_html(name)),
)
Загрузи файл в Telegram, ответь на него .loadmod и вызови .hello Astralix. Команды по умолчанию доступны владельцу.Upload the file to Telegram, reply with .loadmod, then run .hello Astralix. Commands are owner-only by default.
Аргументы и ответыArguments and replies
utils.get_args_raw(message) возвращает строку после команды, utils.get_args(message) — разобранные аргументы. Для ответов используй utils.answer: он учитывает контекст сообщения.utils.get_args_raw(message) returns the text after the command; utils.get_args(message) returns parsed arguments. Use utils.answer for responses: it handles the message context.
@loader.command()
async def echo(self, message):
"""[text] — Repeat text."""
text = utils.get_args_raw(message)
await utils.answer(message, utils.escape_html(text or "…"))Экранируй пользовательские строки через utils.escape_html перед вставкой в HTML. Не выдавай недоверенный текст за разметку.Escape user-supplied strings with utils.escape_html before inserting them into HTML.
Настройки модуляModule configuration
Создай loader.ModuleConfig в __init__. Поля появятся в .config. Валидатор задаёт допустимые значения.Create a loader.ModuleConfig in __init__. Its fields appear in .config. A validator controls the allowed values.
def __init__(self):
self.config = loader.ModuleConfig(
loader.ConfigValue(
"greeting",
"Hello",
"Greeting text",
validator=loader.validators.String(),
),
)
@loader.command()
async def greet(self, message):
"""Send the configured greeting."""
await utils.answer(
message, utils.escape_html(self.config["greeting"])
)Клиент и хранениеClient and storage
client_ready вызывается после подготовки клиента и конфигурации. Храни небольшие JSON-совместимые значения через self.get и self.set. Не складывай секреты в исходники или логи.client_ready runs after the client and configuration are ready. Store small JSON-compatible values using self.get and self.set. Keep secrets out of source code and logs.
async def client_ready(self, client, db):
self.client = client
@loader.command()
async def counter(self, message):
"""Increment a persistent counter."""
count = self.get("count", 0) + 1
self.set("count", count)
await utils.answer(message, str(count))Обработчики событийEvent handlers
Для наблюдения за сообщениями используй @loader.watcher(). Ограничивай обработчик нужными событиями и не отвечай на каждое сообщение: это может создать цикл.Use @loader.watcher() to observe messages. Restrict it to relevant events and avoid replying to every message, which can create a loop.
@loader.watcher()
async def watcher(self, message):
if not getattr(message, "out", False):
return
if getattr(message, "raw_text", "") == "astralix:count":
self.set("matches", self.get("matches", 0) + 1)Rich-сообщения и медиаRich messages and media
Передай HTML в rich_message. Для обычного сообщения используй текст и URL в file. Не путай публичную ссылку с локальным путём.Pass HTML using rich_message. For a regular message, use text and a URL in file. A public URL and a local path are different media sources.
await utils.answer(
message,
rich_message="<h1>Hello</h1><p>Built with astralix.</p>",
)
await utils.answer(
message,
"Hello",
file="https://raw.githubusercontent.com/lowsense-dev/"
"astralix/refs/heads/main/assets/astralix-banner.png",
)astralix-tl и асинхронностьastralix-tl and async code
Импортируй Telegram API из astralixtl. Сетевые операции клиента нужно ожидать через await. Не блокируй цикл событий через time.sleep или синхронные HTTP-запросы.Import the Telegram API from astralixtl. Await client network operations. Do not block the event loop with time.sleep or synchronous HTTP requests.
from astralixtl.tl.types import Message
import asyncio
# Inside an async handler:
await asyncio.sleep(1)Смотри рабочие примеры в модулях ядра и реализацию декораторов в loader.py.See working examples in the core modules and decorator implementations in loader.py.