--- sidebar_position: 12 --- # Slash Commands API The Commands API lets plugins register `/` slash commands. When a user types `/` in the chat composer, Toju shows a Discord-style autocomplete menu of available commands. Selecting a command (click, `Enter`, or `Tab`) runs it — either immediately when it declares no options, or after the user types the requested arguments. ## Required Capabilities | Method | Capability | | --------------------------------- | ------------- | | `commands.register(id, command)` | `ui.commands` | | `commands.list()` | `ui.commands` | Every registration returns a disposable. Push it into `context.subscriptions` so the command is removed when the plugin unloads. ## Command Scope A command's `scope` controls where it appears: | Scope | Available in | | ------------------- | --------------------------------------------- | | `global` (default) | Chat servers **and** direct messages | | `server` | Only while a chat server is the active surface | Use `global` for commands that work without a server context (e.g. `/help`, `/shrug`). Use `server` for commands that act on the current server, channel, or members. ## Options and Argument Parsing Declare `options` to describe the arguments a command accepts. Toju parses what the user typed after the command name and passes the result to `run` as `context.args`, keyed by option name. ```ts interface PluginApiSlashCommandOption { description?: string; name: string; required?: boolean; // 'rest' captures all remaining text; otherwise a single whitespace-delimited token type?: 'string' | 'number' | 'boolean' | 'rest'; } ``` - Positional options are filled left-to-right from whitespace-delimited tokens. - A `rest` option captures all remaining text verbatim (use it last, for free-form text). - Missing positional values are passed as empty strings. - The autocomplete menu shows required options as `` and optional ones as `[name]`. Values arrive as strings; convert `number`/`boolean` types yourself inside `run`. ## Command Context `run` receives a context that extends the standard action context (`source: 'slashCommand'`) with the invocation details: ```ts interface PluginApiSlashCommandContext extends PluginApiActionContext { args: Record; // parsed values keyed by option name command: string; // invoked name without the leading slash rawArgs: string; // raw text typed after the command name // inherited: server, textChannel, voiceChannel, user, source } ``` ## Register a Command ```js export function activate(context) { const api = context.api; // Server-scoped command with a free-form message argument. context.subscriptions.push( api.commands.register('announce', { name: 'announce', description: 'Post an announcement to the current channel', icon: '📢', scope: 'server', options: [{ name: 'message', type: 'rest', required: true }], run: (slash) => { api.messages.send(`📢 ${slash.args.message}`, slash.textChannel?.id); } }) ); // Global command that works in servers and DMs. context.subscriptions.push( api.commands.register('shrug', { name: 'shrug', description: 'Append the shrug emoticon', scope: 'global', run: () => api.messages.send('¯\\_(ツ)_/¯') }) ); } ``` `api.messages.send` requires the `messages.send` capability, so the example above declares both `ui.commands` and `messages.send` in its manifest. ## List Registered Commands ```js const allCommands = context.api.commands.list(); ``` Returns every slash command currently registered across all active plugins, including their scope and options. ## Built-in Commands Toju ships first-party commands that are always available without any plugin, such as `/lenny` (posts `( ͡° ͜ʖ ͡°)`). They appear in the same autocomplete menu tagged as **Built-in**. Plugin commands are listed alongside them; if a plugin registers a command with the same name as a built-in, both appear and the user can pick either. ## How Input Is Handled - Typing `/` opens the menu; typing more characters filters by command name (prefix matches rank first). - Picking a command **without options** runs it immediately and clears the composer. - Picking a command **with options** fills `/name ` so the user can type arguments, then `Enter` runs it. - Slash input is intercepted and never posted as a chat message. Text that starts with `/` but matches no registered command falls through and is sent as a normal message.