Kora/developer documentation/Commands

Commands

Add Discord slash commands to Kora's bot from any module.

A command class adds a slash command to Kora's Discord bot. Any module can ship commands. The Discord extension registers and runs them, so it must be turned on with a bot token and server set.

Put commands in src/commands/, one class per file.

modules/example/src/commands/sync.js
import { Commands } from "#kora/modules";

export class SyncCommand extends Commands {
    constructor(kora) {
        super(kora, {
            name: "sync",
            description: "Sync licenses with the store",
            permission: "licenses",
            options: [
                { type: "Subcommand", name: "edit", description: "Sync one product", options: [
                    { type: "String", name: "product", description: "Product", required: true, autocomplete: true }
                ] }
            ]
        });
    }

    async complete(interaction, { bot }) {
        return bot.suggest(interaction.options.getFocused(true));
    }

    async run(interaction, { bot, actor }) {
        const count = await this.kora.modules.handlers.get("example", "sync").product(interaction.options.getString("product", true), actor);
        return bot.embed(bot.accent(), "Sync Complete").setDescription(`Synced **${count}** licenses.`);
    }
}
OptionDefaultWhat it does
nameRequiredThe slash command name.
description""Shown in Discord's command picker.
permission""The permission prefix. See below.
options[]The command's options and subcommands.

Commands are registered in the server set in the Discord config each time the bot starts.

Options

Options use Discord's option fields, with type written as the name of the type:

typeOption
Subcommand, SubcommandGroupA subcommand, with its own options.
String, Integer, Number, BooleanA value.
User, Channel, Role, Mentionable, AttachmentA Discord object.

required, choices, autocomplete, min_value and max_value work as in Discord.

Permissions

With a permission, the bot checks the member's Kora role for <permission>.<subcommand>. In the example, /sync edit needs licenses.edit. Discord accounts are matched to Kora team members by their linked Discord ID. A member without the permission gets the "No permission" message from the Discord lang file.

Leave permission empty for a command anyone in the server can use, then check access yourself:

if (!this.kora.api.allowed(actor, "whitelists.create")) return bot.failure(this.kora.modules.lang.phrase("discord", "messages", "denied"));

Methods

MethodWhen it runsReturns
run(interaction, context)The command is used.The reply.
complete(interaction, context)An autocomplete option is being typed.Up to 25 { name, value } choices.
component(interaction, context)A button or menu from this command is used.The new message.

context holds bot, the Discord handler, and actor, the member running it.

Replies

Every reply is private to the member. Return an EmbedBuilder, or a message payload such as { embeds, components }. Embeds are turned into a Components V2 container in the bot's accent colour. If run throws, the error message is sent in its place.

Buttons and Menus

Give a component a custom ID of <command>:<action>:<args>:

new ButtonBuilder().setCustomId(`sync:retry:${product.id}`).setLabel("Retry")

When it is pressed, component runs with action and args in context. The permission check uses the action, so this one needs licenses.retry. The return value replaces the message. Add ephemeral: true to send a new private reply instead.

Bot Helpers

HelperWhat it does
bot.embed(tone, title)A new embed in the accent colour with a title and timestamp.
bot.accent()The accent colour from the Discord config, or Kora's accent colour.
bot.failure(message)An error reply.
bot.suggest(focused)Autocomplete for options named license, product, customer, status, currency, expires or group.
bot.input(interaction, names)The subcommand's options as an object, with keys renamed by names.
bot.time(value)A readable date, or "Never".
bot.relative(value)A time such as 5m ago.