> ## Documentation Index
> Fetch the complete documentation index at: https://developers.duelsplus.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Commands

> Register custom chat commands for your plugin

# Commands

Plugins register custom chat commands that the player can run with `/commandname`. The proxy routes these to your plugin's `execute` function.

## Registering a command

```ts theme={null}
ctx.commands.register({
  name: 'myplugin',
  description: 'Does something useful',
  usage: '/myplugin [on|off]',
  aliases: ['mp'],
  execute: (args, sender) => {
    const sub = args[0]?.toLowerCase();
    if (sub === 'on') {
      ctx.storage.set('enabled', true);
      ctx.client.sendChat('§aEnabled');
    } else if (sub === 'off') {
      ctx.storage.set('enabled', false);
      ctx.client.sendChat('§cDisabled');
    } else {
      ctx.client.sendChat(`§7Usage: /myplugin on|off`);
    }
  },
});
```

* **name** - The main command name (e.g. `myplugin` → `/myplugin`). Use lowercase.
* **description** - Shown in help (e.g. `/dhelp`).
* **usage** - Optional; shown in help.
* **aliases** - Optional; e.g. `['mp']` allows `/mp` as well.
* **execute** - `(args: string[], sender: { username: string; uuid: string }) => void | Promise<void>`. `args` is everything after the command (e.g. `/myplugin on` → `args = ['on']`).

## Unregistering

If you need to remove a command at runtime:

```ts theme={null}
ctx.commands.unregister('myplugin');
```

Aliases are unregistered automatically when the plugin unloads. You don't need to unregister for normal shutdown - the proxy cleans up all plugin commands when a plugin is unloaded.

## Example (from auto-glhf)

The auto-glhf example registers `/glhf` with subcommands:

```ts theme={null}
ctx.commands.register({
  name: 'glhf',
  description: 'Configure auto-glhf',
  usage: '/glhf [on|off|set <message>|delay <ms>]',
  execute: (args) => {
    const sub = args[0]?.toLowerCase();
    if (sub === 'on') {
      ctx.storage.set('enabled', true);
      ctx.client.sendChat('§7[GLHF] §aEnabled');
    } else if (sub === 'set') {
      const msg = args.slice(1).join(' ');
      if (msg) ctx.storage.set('message', msg);
    }
    // ...
  },
});
```

Commands run in the same context as the rest of your plugin; you can use `ctx.client`, `ctx.storage`, `ctx.gameState`, etc., inside `execute`.
