Hot Reload & Plugins
The commands framework can watch your command files for changes and reload them automatically. Plugins let you package reusable middleware, hooks, and commands into a single installable unit.
File watching
Section titled “File watching”When watch is enabled (the default), calling commands:load() also starts watching the loaded directory. Saving a command file triggers an automatic reload - no restart required.
local commandsManager = commands.new(bot) -- watch: true by default
bot.onAllShardsReady:listenOnce(function() commandsManager:load("src/commands") -- loads and watchesend)Disable watching if you don’t need it (e.g. in production):
local commandsManager = commands.new(bot, { watch = false })Manual watching
Section titled “Manual watching”Call commands:watch() separately to watch a directory without loading from it, or to watch additional directories after the initial load.
local stopWatching = commandsManager:watch("src/extra-commands")
stopWatching()Stopping all watchers
Section titled “Stopping all watchers”commands:destroy() stops every active watcher registered through commands:watch() or auto-started by commands:load().
commandsManager:destroy()How hot reload works
Section titled “How hot reload works”When a file changes, the loader writes the new file content to a temporary file with a randomised name, require()s that file to bypass the module cache, then deletes the temporary file. The new CommandDefinition replaces the old one in the registry. In-flight interactions using the previous definition complete normally.
Plugins
Section titled “Plugins”A plugin is a table with a name and a setup function. setup receives the Commands instance so it can register middleware, after hooks, commands, or anything else. It can optionally return a teardown function.
local commands = require("../../luau_packages/commands")
local loggingPlugin = { name = "logging",
setup = function(commandsManager: commands.Commands) commandsManager:use(function(interaction: any, next: () -> ()) local anyInteraction = interaction :: any local name = anyInteraction.data and anyInteraction.data.name or "interaction"
print(`[log] {name}`) next() end)
-- return a teardown function (optional) return function() print("[log] plugin unloaded") end end,}Install a plugin with commands:usePlugin():
commandsManager:usePlugin(loggingPlugin)Installing the same plugin twice is a no-op - the framework warns and skips.
Unloading a plugin
Section titled “Unloading a plugin”commandsManager:unloadPlugin("logging")This calls the teardown function returned by setup, if one was provided.
Context
Section titled “Context”The context option lets you pass a shared value (config, database handle, etc.) into every command factory function and into plugins.
Command files can receive it by exporting a factory function instead of a plain table:
-- src/commands/example.luaulocal classes = require("../../luau_packages/classes")
return function(context) return { command = ...,
execute = function(interaction: classes.TypesCommand) -- context.db, context.config, etc. end, }endPass the context when creating the Commands instance:
local commandsManager = commands.new(bot, { context = { db = myDatabase, config = myConfig, },})References
Section titled “References”- Getting Started -
commands.newoptions includingwatchandcontext - Middleware & After Hooks - what plugins commonly register