Skip to main content

Bot Modules

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-cli package 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:

  • category must be "bot_module"
  • platforms declares which chat platforms this module supports
  • triggers defines when handlers fire (commands, keywords, patterns, events, timers)
  • targets is 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

WrapperTriggerExecutionReturn
command(name, handler)Chat prefix (!name)Sync (500ms deadline)\{ reply?: string \}
keyword(word, handler)Substring matchAsync (fire-and-forget)\{ reply?: string \} or null
pattern(regex, handler)Regex matchAsync (fire-and-forget)\{ reply?: string \} or null
event(type, handler)Platform eventAsync (fire-and-forget)\{ reply?: string \} or null
timer(name, handler)Interval clockAsync (self-triggered)\{ reply?: string \} or null
moderate(handler)Every messageSync (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

  1. A chat message arrives at the platform bot (Twitch, YouTube, etc.)
  2. The bot runs built-in modules first (link protection, word filter, spam protection)
  3. The bot matches the message against installed extension triggers (commands, keywords, patterns)
  4. On match, the bot dispatches to the Bot Module Worker via HTTP (sync) or Redis (async)
  5. The Worker executes your handler in a V8 isolate
  6. The handler response (reply, moderation action) is sent back to the bot
  7. The bot delivers the response to chat

Next steps