Skip to content

Guards & Permissions

Guards are functions that run before execute. If any guard returns false, the command is blocked and the user gets a denial message. The framework ships with built-in guards for common cases, and you can write your own.

Access built-in guards via commands.Guards.

local commands = require("@self/../luau_packages/commands")
local classes = require("@self/../luau_packages/classes")
return {
command = ...,
guards = {
commands.Guards.guildOnly,
},
execute = function(interaction: classes.TypesCommand)
interaction:messageAsync({ content = "You're in a guild!" }):await()
end,
}
GuardPasses when
commands.Guards.guildOnlyInteraction is inside a guild
commands.Guards.dmOnlyInteraction is in a DM
commands.Guards.ownerOnly(ids)Invoking user’s ID is in the provided list

ownerOnly is a factory - call it with a list of owner IDs:

guards = {
commands.Guards.ownerOnly({ "123456789", "987654321" }),
},

A guard is any function that takes the interaction and returns a boolean.

local function premiumOnly(interaction: classes.TypesCommand): boolean
-- check your database, cache, etc.
return isPremiumUser(interaction.user.id)
end
return {
command = ...,
guards = { premiumOnly },
execute = function(interaction: classes.TypesCommand)
interaction:messageAsync({ content = "Premium feature!" }):await()
end,
}

By default, guards in the list are AND - every guard must pass.

guards = {
commands.Guards.guildOnly, -- must be in a guild
premiumOnly, -- AND must be premium
},

Wrap guards in a nested table to express OR - at least one must pass.

guards = {
{ commands.Guards.ownerOnly({ "123" }), isAdminRole },
},

You can mix AND and OR in the same list:

guards = {
commands.Guards.guildOnly, -- must be in a guild
{ isAdmin, isModerator }, -- AND (is admin OR is moderator)
},

Use userPermissions to require the invoking member to hold specific Discord permissions. Use clientPermissions to require the bot itself to have them. These only apply inside guilds.

return {
command = ...,
userPermissions = { "ManageMessages" },
clientPermissions = { "ManageMessages" },
execute = function(interaction: classes.TypesCommand)
interaction:messageAsync({ content = "Message deleted." }):await()
end,
}

If permissions are missing, a default denial message is sent. Override it with onUserPermissionDenied or onClientPermissionDenied:

return {
command = ...,
userPermissions = { "Administrator" },
onUserPermissionDenied = function(interaction: classes.TypesCommand, missing: { string })
interaction:messageAsync({
content = `You're missing: {table.concat(missing, ", ")}`,
flags = 64,
}):await()
end,
execute = function(interaction: classes.TypesCommand) ... end,
}

Override the default “You don’t have permission” message globally via onGuardFailed in Commands.new, or per-command via onGuardFailed on the definition.

-- global
local commandsManager = commands.new(bot, {
onGuardFailed = function(interaction: classes.TypesCommand)
interaction:messageAsync({ content = "Nope.", flags = 64 }):poll()
end,
})
-- per-command
return {
command = ...,
guards = { ... },
onGuardFailed = function(interaction: classes.TypesCommand)
interaction:messageAsync({ content = "Not for you.", flags = 64 }):poll()
end,
execute = function(interaction: classes.TypesCommand) ... end,
}