Dokumentation / Developers / Referenz / Decorators and lifecycle
GeneratedSDK 0.10.116 members

Decorators and lifecycle

Every @plugin decorator and lifecycle hook, with its signature and when it fires.

Create one Plugin instance in your entry module and decorate handlers with it. Handlers receive ctx and the event dict. plugin.run() at the bottom of the file hands control to the platform.

@plugin.on_ready(fn: Callable) -> Callable
Register a function called once when the plugin boots successfully. Single-tenant mode: fires once per worker boot, in a background thread. Pool mode: fires once per (worker, server) on the first event for each tenant, synchronously before the event handler runs — so per-tenant init (schema bootstrap, KV defaults) completes before SQL/KV calls. The function receives one argument: ctx (Context). In pool mode the ctx is scoped to the tenant that triggered the first event.
@plugin.on_event(event_type: str) -> Callable
Register a handler for a Discord event type. The function receives two arguments: ctx (Context) and event (dict). Supported event types: - message_create A message was sent in a channel - message_edit A message was edited - message_delete A message was deleted - member_join A member joined the server - member_leave A member left the server - member_update A member's roles/nick/avatar changed - reaction_add A reaction was added to a message - reaction_remove A reaction was removed from a message - voice_state_update A member's voice state changed - interaction_create A slash command, button, select, or modal was used - channel_create A channel was created - channel_delete A channel was deleted - channel_update A channel was modified - role_create A role was created - role_delete A role was deleted - role_update A role was modified
@plugin.on_ws_message(name: str) -> Callable
Register a handler for inbound frames on the named WebSocket connection. The function receives (ctx, frame) where frame is {"name", "conn_id", "data", "binary"}. For binary=True frames, data is base64-encoded (decode with base64.b64decode). Requires the proxy:websocket capability and a matching ctx.ws.ensure(name, ...).
@plugin.on_ws_open(name: str) -> Callable
Register a handler called each time the named connection (re)connects. Receives (ctx). This is the place to (re)send any auth/subscribe frames — though ctx.ws.ensure(subscribe=[...]) does that automatically.
@plugin.on_ws_close(name: str) -> Callable
Register a handler called when the named connection closes or drops. Receives (ctx, info) where info is {"reason", "will_reconnect"}.
@plugin.on_slash_command(command_name: str) -> Callable
Register a handler for a specific slash command. Convenience wrapper that filters interaction_create events. The function receives two arguments: ctx (Context) and event (dict). Example:: @plugin.on_slash_command("hello") def handle_hello(ctx, event): ctx.interaction.respond(content="Hello!")
@plugin.on_component(custom_id: Optional[str] = None, *, prefix: Optional[str] = None) -> Callable
Register a handler for a component interaction (button click, select, etc.). Pass either custom_id="exact_id" for an exact-string match, or prefix="page:" to match any custom_id starting with that prefix. Use prefix= when your buttons encode dynamic state (e.g. "page:next:5", "vote:yes:42"). Exactly one of custom_id= or prefix= must be provided. Example:: @plugin.on_component("btn_join") def handle_join(ctx, event): ctx.interaction.respond(content="You joined!", ephemeral=True) @plugin.on_component(prefix="page:") def handle_page(ctx, event): # event["custom_id"] e.g. "page:next:5" ...
@plugin.on_modal_submit(custom_id: str) -> Callable
Register a handler for a modal form submission. Convenience wrapper that filters interaction_create events. The function receives two arguments: ctx (Context) and event (dict). event["modal_values"] contains {custom_id: value} for each field. Example:: @plugin.on_modal_submit("signup_form") def handle_signup(ctx, event): name = event["modal_values"].get("char_name", "") ctx.interaction.respond(content=f"Welcome, {name}!")
@plugin.schedule(interval_seconds: int) -> Callable
Register a background task that runs on a fixed interval. The function receives one argument: ctx (Context). Starts after on_ready completes. Stops when the plugin shuts down. Example:: @plugin.schedule(300) # every 5 minutes def cleanup(ctx): ctx.log("Running cleanup...") # do work
In production plugins run in pool mode, which has no background threads, so a @plugin.schedule task never fires there. Declare a cron entry in manifest.json instead. The upload check warns about this.
@plugin.cron(spec: str) -> Callable
Register a background task that runs on a cron schedule (UTC). Spec format: "minute hour day-of-month month day-of-week" — five fields. Each supports *, */N, N, N,M,…, N-M, N-M/S. Day-of-week is 0=Sunday … 6=Saturday. All times are UTC. Examples:: @plugin.cron("0 9 * * 1") # every Monday at 09:00 UTC def weekly_report(ctx): ctx.log("Sending weekly report") @plugin.cron("*/15 * * * *") # every 15 minutes def heartbeat(ctx): ... @plugin.cron("30 0 1 * *") # 00:30 UTC on the 1st of each month def monthly_rollup(ctx): ... Notes: - In single-tenant mode this is a thread-based loop inside the worker process (like @schedule); if the plugin is restarted between firings, the missed tick is **not** replayed. - In pool mode (all marketplace installs) the thread loop never starts. Instead, declare the schedule in manifest.json:: "cron": [{"spec": "0 9 * * *", "name": "weekly_report"}] (name = this function's name). The platform fires it server-side once per enabled server and the SDK routes each firing back to this function with a tenant-scoped ctx. Missed firings are not replayed; delivery is at-most-once per (server, schedule, minute). - Invalid specs raise ValueError immediately at registration — you'll see the error during boot, not silently at the first miss.
@plugin.on_dashboard(method_name: str) -> Callable
Register a dashboard data handler for the manifest-based dashboard. The platform calls these when a user views the plugin's dashboard page. The function receives (ctx, params) and returns a JSON-serializable dict. Widget types and expected return formats: stat_card → {"value": 1234, "change": "+12%"} chart → {"labels": [...], "series": [{"name": "...", "data": [...]}]} table → {"rows": [{...}, ...], "total": 100} form (get) → {"values": {"key": "value", ...}} form (save)→ {"ok": True} Example:: @plugin.on_dashboard("get_stat") def handle_get_stat(ctx, params): total = ctx.kv.get("total_events") or 0 return {"value": int(total)} @plugin.on_dashboard("get_timeseries") def handle_get_timeseries(ctx, params): period = params.get("period", "7d") data = ctx.kv.get(f"timeseries:{period}") or {} return {"labels": data.get("labels", []), "series": data.get("series", [])}
@plugin.on_install(fn: Callable) -> Callable
Called once when the plugin is first installed on a server. Use this to initialize default settings in KV storage. The function receives one argument: ctx (Context).
@plugin.on_enable(fn: Callable) -> Callable
Called when the plugin is enabled (toggled on) for a server. The function receives one argument: ctx (Context).
@plugin.on_disable(fn: Callable) -> Callable
Called when the plugin is disabled (toggled off) for a server. Use this to pause background work or save state. The function receives one argument: ctx (Context).
@plugin.on_uninstall(fn: Callable) -> Callable
Called when the plugin is being uninstalled from a server. Use this to clean up KV data or log a final message. The function receives one argument: ctx (Context).
plugin.run() -> None
Start the plugin. This call blocks forever. Must be the last line of your __main__.py.
YourBot docs Reference tables are generated from the code that is running. Ask in Discord Suggest a correction