Bot Modules
Lumio's built-in bot modules (Link Protection, Spam Protection, Word Filter, Timed Messages) are system extensions that run through the same V8 execution model as third-party bot modules. All bot modules -- built-in and custom -- use the same SDK handlers (defineCommand, defineModerate, etc.).
Bot modules are extensions that handle chat messages, platform events, and timed actions across Twitch, YouTube, Kick, Trovo, and Discord. They run server-side in a V8 isolate — no browser required.
This guide walks through creating a bot module from scratch, writing handlers, testing locally, and deploying.
Prerequisites
- Node.js 20+
- A Lumio developer account
- The
@zaflun/lumio-clipackage installed globally
npm install -g @zaflun/lumio-cli
lumio login
Create a bot module project
Use lumio init and select the bot_module category:
lumio init my-bot-module
When prompted:
- Category:
bot_module - Platforms: Select one or more:
twitch,youtube,kick,trovo,discord - Server functions: Yes (auto-enabled for bot modules)
This generates the following project structure:
my-bot-module/
├── lumio.config.json
├── server/
│ ├── schema.ts
│ └── functions.ts
├── package.json
└── tsconfig.json
Bot modules have no src/ directory — they are server-only extensions with no browser UI surface.
Configure the manifest
Open lumio.config.json and define your triggers and permissions:
{
"$schema": "https://lumio.vision/schemas/lumio.config.schema.json",
"extension_id": "your-uuid-here",
"name": "My Bot Module",
"category": "bot_module",
"version": "1.0.0",
"platforms": ["twitch", "youtube"],
"server": true,
"permissions": ["chat:send", "chat:read"],
"triggers": {
"commands": [
{
"name": "hello",
"description": "Greet the user",
"cooldown_global": 5,
"cooldown_user": 10,
"min_role": "everyone"
}
],
"keywords": ["gg"],
"events": ["twitch:subscribe"],
"timers": [
{
"name": "reminder",
"interval": 300,
"handler": "periodicReminder"
}
]
},
"config_schema": [
{
"key": "greeting",
"type": "string",
"label": "Greeting message",
"default_value": "Hello",
"required": true
}
]
}
Key differences from widget/overlay extensions:
categorymust be"bot_module"platformsdeclares which chat platforms this module supportstriggersdefines when handlers fire (commands, keywords, patterns, events, timers)targetsis not used — bot modules have no visual surfaces
Define the database schema
If your module needs persistent storage, define tables in server/schema.ts:
// server/schema.ts
import { defineSchema, defineTable, column } from "@zaflun/lumio-sdk/server";
export default defineSchema({
greetings: defineTable({
user_id: column.string(),
count: column.number(),
last_greeted: column.number(),
}),
});
Write handlers
Bot modules use handler wrappers from @zaflun/lumio-sdk/server. Each wrapper corresponds to a trigger type:
// server/functions.ts
import { command, keyword, event, timer } from "@zaflun/lumio-sdk/server";
// Command handler — fires when a user types !hello
export const hello = command("hello", async (ctx, args) => {
const greeting = ctx.config.greeting ?? "Hello";
return { reply: `${greeting}, ${ctx.user.name}!` };
});
// Keyword handler — fires when "gg" appears in chat
export const hypeDetector = keyword("gg", async (ctx, message) => {
await ctx.cache.increment("hype_count", 1);
return null; // no reply
});
// Event handler — fires on Twitch subscriptions
export const welcomeSub = event("twitch:subscribe", async (ctx, evt) => {
return {
reply: `Welcome ${evt.user_name}! Thanks for subscribing!`,
};
});
// Timer handler — fires every 300 seconds
export const periodicReminder = timer("reminder", async (ctx) => {
return { reply: "Remember to follow the channel!" };
});
Every handler receives a ctx object with access to the database, cache, secrets, config, and more. See the Bot Module Context reference for the full API.
Handler types
| Wrapper | Trigger | Execution | Return |
|---|---|---|---|
command(name, handler) | Chat prefix (!name) | Sync (500ms deadline) | \{ reply?: string \} |
keyword(word, handler) | Substring match | Async (fire-and-forget) | \{ reply?: string \} or null |
pattern(regex, handler) | Regex match | Async (fire-and-forget) | \{ reply?: string \} or null |
event(type, handler) | Platform event | Async (fire-and-forget) | \{ reply?: string \} or null |
timer(name, handler) | Interval clock | Async (self-triggered) | \{ reply?: string \} or null |
moderate(handler) | Every message | Sync (500ms deadline) | \{ block: boolean \} |
Test locally
Start the bot module dev server:
lumio dev --bot-module
This launches a chat simulator where you can type messages and see handler responses in real time. See Local Development for details.
You can also test individual handlers:
lumio run command:hello --args "" --user "testuser"
Deploy
Build and deploy like any other extension:
lumio deploy
After deployment, the bot module appears in the Lumio Store under the Bot Module category. Users install it from the Store and configure triggers, cooldowns, and settings in their dashboard.
What happens at runtime
- A chat message arrives at the platform bot (Twitch, YouTube, etc.)
- The bot runs built-in modules first (link protection, word filter, spam protection)
- The bot matches the message against installed extension triggers (commands, keywords, patterns)
- On match, the bot dispatches to the Bot Module Worker via HTTP (sync) or Redis (async)
- The Worker executes your handler in a V8 isolate
- The handler response (reply, moderation action) is sent back to the bot
- The bot delivers the response to chat
Next steps
- Local Development — chat simulator, hot-reload, mock users
- Bot Module Context — full
ctxAPI reference - Triggers — trigger configuration reference
- Security — rate limits, permissions, audit log
- Cache & Background Jobs —
ctx.cacheandctx.defer()usage - Examples — complete bot module examples