Przejdź do treści
mosaic

Dokumentacja

Napisz swój moduł

Wszystko, czego potrzebujesz, by moduł trafił do Mosaic: struktura, manifest, przykład kodu i zasady pull requestów.

01

Jak to działa

Każdy moduł to osobny folder w katalogu modules/ repozytorium bota. Bot ładuje moduły przy starcie, a strona czyta manifest i sama buduje stronę modułu oraz formularz ustawień.

Moduły są odizolowane: każdy ma własne komendy, zdarzenia, ustawienia i tłumaczenia. Moduł nie może czytać danych innych modułów bezpośrednio — tylko przez publiczne API bota.

02

Szybki start

Potrzebujesz Pythona 3.12+, uv i testowego serwera na Discordzie.

  1. Zrób fork repozytorium mosaicbot-dev1/mosaic-bot-core i sklonuj je.
  2. Zainstaluj zależności: uv sync.
  3. Wygeneruj szkielet modułu: uv run mosaic create birthdays.
  4. Uruchom bota lokalnie na testowym serwerze: uv run mosaic dev.
terminal
git clone https://github.com/<you>/mosaic-bot-core.git
cd mosaic-bot-core
uv sync
uv run mosaic create birthdays
uv run mosaic dev --guild 123456789012345678

03

Struktura modułu

Minimalny moduł to manifest i punkt wejścia. Reszta — według potrzeb.

modules/birthdays/
├── module.toml
├── __init__.py
├── commands.py
├── events.py
├── locales/
│   ├── uk.json
│   ├── en.json
│   └── pl.json
└── README.md
module.toml
manifest: id, wersja, autor, uprawnienia i schemat ustawień
__init__.py
punkt wejścia: pakiet Pythona, który rejestruje komendy, zdarzenia i hooki
commands.py
komendy slash i grupy komend
events.py
obsługa zdarzeń Discorda i zadań cyklicznych
locales/
tłumaczenia modułu, co najmniej uk i en
README.md
opis i lista komend do katalogu

04

Manifest

Strona buduje formularz ustawień bezpośrednio z settings. Pola grupuje się przez section; dostępne typy: boolean, number, text, select, color, channel i channels, role i roles oraz pairs — reguły „liczba → wartość”, np. „poziom 10 → rola”.

modules/birthdays/module.toml
[module]
id = "birthdays"
name = "Birthdays"
version = "1.2.0"
category = "community"
author = "olha-codes"
permissions = ["ManageRoles", "SendMessages"]
network = []

[[settings]]
section = "general"
key = "announceChannel"
type = "channel"
channel_type = "text"

[[settings]]
section = "general"
key = "birthdayRole"
type = "role"

[[settings]]
section = "general"
key = "timezone"
type = "select"
options = ["Europe/Kyiv", "Europe/Warsaw", "UTC"]
default = "Europe/Kyiv"

[[settings]]
section = "messages"
key = "birthdayMessage"
type = "text"
default = "Happy birthday, {user}!"
max_length = 300

05

Przykład kodu

Moduł to pakiet Pythona z obiektem Module, który czyta manifest. Ustawienia są typowane ze schematu manifestu, a tłumaczenia dostępne przez ctx.t.

modules/birthdays/__init__.py
from mosaic import Context, Module

module = Module.from_manifest(__file__)


@module.on_enable
async def on_enable(ctx: Context) -> None:
    ctx.log.info("birthdays enabled on %s", ctx.guild.name)


# Importing the files registers their commands and events on `module`
from . import commands, events  # noqa: E402,F401

Komendy to funkcje async z dekoratorem @birthday.command. Dane zapisuj wyłącznie przez ctx.store: tak bot izoluje moduły i czyści dane po usunięciu.

modules/birthdays/commands.py
from datetime import date

from discord import app_commands

from mosaic import CommandContext

from . import module

birthday = module.group("birthday", description="Birthdays")


@birthday.command("set", description="Set your birthday")
@app_commands.describe(day="Day of the month", month="Month, 1-12")
async def set_birthday(
    ctx: CommandContext,
    day: app_commands.Range[int, 1, 31],
    month: app_commands.Range[int, 1, 12],
) -> None:
    try:
        when = date(2000, month, day)  # a leap year, so 29 February is valid
    except ValueError:
        await ctx.reply(ctx.t("errors.invalidDate"), ephemeral=True)
        return

    # ctx.settings comes from the dashboard, ctx.store keeps this module's data
    await ctx.store.user(ctx.user.id).set("birthday", when.strftime("%m-%d"))
    await ctx.reply(ctx.t("set.success", date=when.strftime("%d.%m")), ephemeral=True)

06

Sprawdzanie lokalnie

Przed PR uruchom te same testy co CI: ruff, pytest i mosaic validate, który sprawdza manifest, uprawnienia i tłumaczenia.

terminal
uv run ruff check modules/birthdays
uv run pytest
uv run mosaic validate birthdays

07

Zasady pull requestów

PR zostaje przyjęty, jeśli moduł spełnia te zasady:

  • Jeden moduł — jeden PR. Tytuł w formacie feat(module): birthdays.
  • ruff, pytest i mosaic validate przechodzą bez błędów, a publiczne funkcje mają adnotacje typów.
  • Moduł prosi tylko o te uprawnienia Discorda, których naprawdę używa, i wyjaśnia je w README.
  • Żadnych zewnętrznych zapytań bez pola network w manifeście. Dane osobowe — tylko niezbędne.
  • Tłumaczenia co najmniej po ukraińsku i angielsku.
  • README z opisem, listą komend i zrzutem ekranu ustawień.
  • Kod na licencji MIT, bez zapożyczonego kodu na niezgodnej licencji.

08

Review i wydanie

Opiekunowie przeglądają PR w ciągu siedmiu dni. Automatyczne testy startują od razu: build, testy, analiza bezpieczeństwa i walidacja manifestu.

Po scaleniu moduł pojawia się w katalogu z oznaczeniem „Społeczność” w najbliższym wydaniu, a Ty — na liście kontrybutorów.