Skip to main content

Triggers

The triggers field in lumio.config.json defines when your bot module handlers fire. Triggers are only allowed when category is "bot_module" — other extension categories with a triggers field are rejected at validation.

Overview

{
"category": "bot_module",
"triggers": {
"commands": [...],
"keywords": [...],
"patterns": [...],
"events": [...],
"timers": [...]
}
}

Each trigger type has different matching behavior and execution characteristics:

TriggerWhere matchedExecutionLatency
CommandBot (prefix match)Sync HTTP (500ms deadline)~50-200ms
KeywordBot (substring)Async (fire-and-forget)Fire-and-forget
PatternBot (compiled regex)Async (fire-and-forget)Fire-and-forget
EventWorker (event subscription)AsyncFire-and-forget
TimerWorker (internal clock)Async (self-triggered)N/A

Commands

Chat commands triggered by a prefix (e.g., !points).

{
"triggers": {
"commands": [
{
"name": "points",
"description": "Show your current points balance",
"cooldown_global": 5,
"cooldown_user": 10,
"min_role": "everyone"
}
]
}
}

Command fields

FieldTypeRequiredDescription
namestringYesCommand name (without ! prefix). Alphanumeric + underscore, 1-32 characters.
descriptionstringYesShort description shown in the dashboard and Discord slash command registration.
cooldown_globalintegerNoGlobal cooldown in seconds (0 = no cooldown). Applies to all users.
cooldown_userintegerNoPer-user cooldown in seconds (0 = no cooldown). Applies individually.
min_rolestringNoMinimum role required to use the command. Default: "everyone".
discord_optionsarrayNoDiscord slash command options. Ignored on other platforms. See Discord Slash Commands.

Command validation rules

RuleConstraint
Name format^[a-zA-Z0-9_]+$, 1-32 characters
Max commands per extension20
Cooldown valuesInteger >= 0

min_role values

ValueWho can use
"everyone"All viewers
"follower"Followers and above
"subscriber"Subscribers and above
"vip"VIPs and above
"moderator"Moderators and above
"broadcaster"Broadcaster only

Users can raise (but not lower) the minimum role in their dashboard override settings.

Keywords

Substring matches against chat messages. When a keyword appears anywhere in a message, the associated handler fires.

{
"triggers": {
"keywords": ["gg", "nice shot", "pog"]
}
}

Keyword validation rules

RuleConstraint
Minimum length3 characters
Max keywords per extension50

Keywords are matched as case-insensitive substrings. A keyword of "gg" matches "gg wp", "lol gg", and "gg".

Patterns

Regex patterns matched against chat messages. When a pattern matches, the handler receives the matched string.

{
"triggers": {
"patterns": ["https?://clips\\.twitch\\.tv/\\S+"]
}
}

Pattern validation rules

RuleConstraint
Max length200 characters
Max patterns per extension10
Regex engineRust regex crate (linear-time, no backreferences)
ReDoS safetyGuaranteed by construction (Rust regex crate)

Pattern matching runs in Rust on the bot side. JavaScript RegExp is never used for trigger matching. The matched substring is passed to the handler as the matched parameter:

import { pattern } from "@zaflun/lumio-sdk/server";

export const clipLogger = pattern(
"https?://clips\\.twitch\\.tv/\\S+",
async (ctx, message, matched) => {
// matched = "https://clips.twitch.tv/FunnyClip123"
return { reply: `Clip from ${ctx.user.name}: ${matched}` };
}
);

Events

Platform events that trigger handlers when they occur.

{
"triggers": {
"events": ["twitch:subscribe", "twitch:raid", "youtube:superchat"]
}
}

Each event type must be a valid Lumio event type. The handler receives the event payload:

import { event } from "@zaflun/lumio-sdk/server";

export const welcomeSub = event("twitch:subscribe", async (ctx, evt) => {
return { reply: `Welcome ${evt.user_name}!` };
});

Available event types

Twitch: twitch:follower, twitch:subscribe, twitch:gift_sub, twitch:resub, twitch:cheer, twitch:raid, twitch:reward, twitch:hype_train, twitch:hype_train_end, twitch:poll, twitch:poll_end, twitch:prediction, twitch:prediction_lock, twitch:prediction_end, twitch:goal, twitch:goal_end, twitch:ad_break, twitch:ban, twitch:unban, twitch:stream_online, twitch:stream_offline, twitch:stream_update

YouTube: youtube:subscribe, youtube:member, youtube:superchat, youtube:supersticker, youtube:gift_membership, youtube:gift_membership_received, youtube:poll

Kick: kick:follower, kick:subscribe, kick:gift, kick:stream_online, kick:stream_offline

Trovo: trovo:subscribe, trovo:spell

Spotify: spotify:track, spotify:play, spotify:pause, spotify:skip, spotify:volume, spotify:queue_add, spotify:device, spotify:playlist_add, spotify:playlist_remove, spotify:playlist_create, spotify:playlist_edit, spotify:playlist_delete

StreamElements: streamelements:tip

Chat: twitch:chat, youtube:chat, kick:chat, trovo:chat, chat:message

Timers

Recurring handlers that fire at a fixed interval.

{
"triggers": {
"timers": [
{
"name": "reminder",
"interval": 300,
"handler": "periodicReminder"
},
{
"name": "adDisclaimer",
"interval": 1800,
"handler": "adMessage"
}
]
}
}

Timer fields

FieldTypeRequiredDescription
namestringYesUnique identifier for this timer
intervalintegerYesFiring interval in seconds (minimum: 60)
handlerstringYesName of the exported server function to call

Timer validation rules

RuleConstraint
Minimum interval60 seconds
HandlerMust match an exported server function name

Timer behavior

  • Timers are per-install, not per-account. Two accounts installing the same extension have independent timers.
  • Timer messages are sent to all declared platforms that the account has active bot connections for.
  • If a platform bot is offline, the timer action for that platform is silently dropped. There is no retry — timers are best-effort.
  • Users can override the interval and enable/disable individual timers in their dashboard.

Moderation

The moderate() handler does not need a trigger declaration — it runs on every message that passes built-in module checks. Declare it only in your handler code:

import { moderate } from "@zaflun/lumio-sdk/server";

export const linkFilter = moderate(async (ctx, message) => {
if (message.text.includes("banned-site.com")) {
return { block: true, action: "timeout", duration: 60, reason: "Banned link" };
}
return { block: false };
});

Moderation handlers use the sync execution path (500ms deadline). They require the chat:ban or chat:delete permission, which triggers enhanced manual review during store approval.