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, youtube:stream_online, youtube:stream_offline

Kick: kick:follower, kick:subscribe, kick:resub, kick:gift, kick:kicks, kick:reward, kick:reward_status, kick:stream_online, kick:stream_offline, kick:stream_update

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

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.