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

# Slash commands

> Define commands, option schemas, and subcommands with typed contexts.

## Basic command

```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { command } from '@impulsedev/chameleon'

const echo = command('echo', 'Echo text back')
  .string('text', 'Text to send back', { required: true })
  .execute(async (ctx) => {
    await ctx.reply({
      content: ctx.options.text,
      ephemeral: true
    })
  })
```

## Register it

```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
client.commands.register(echo)
```

For guild-scoped iteration during development, you can register to a single guild:

```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
client.commands.registerGuild(guildId, echo)
```

## Subcommands

```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { command, subcommand } from '@impulsedev/chameleon'

const admin = command('admin', 'Admin tools').subcommand(
  'ban',
  subcommand('Ban a member')
    .user('target', 'User to ban', { required: true })
    .string('reason', 'Reason')
    .execute(async (ctx) => {
      const target = ctx.options.target
      const reason = ctx.options.reason
      await ctx.reply(`Would ban ${target.id} for ${reason ?? 'no reason'}`)
    })
)
```

## Subcommand groups, choices, and richer option types

```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { command, subcommand, subcommandGroup, choice, choices } from '@impulsedev/chameleon'

const toolbox = command('toolbox', 'Command DSL demo')
  .setPermissions('MANAGE_GUILD')
  .group(
    'demo',
    subcommandGroup('Demo subcommands').subcommand(
      'inspect',
      subcommand('Inspect a user or role')
        .string(
          'mode',
          'Inspection mode',
          choices(
            choice('Quick', 'quick'),
            choice('Full', 'full')
          ),
          { required: true }
        )
        .mentionable('target', 'User or role to inspect', { required: true })
        .attachment('file', 'Optional file to include')
        .execute(async (ctx) => {
          await ctx.reply({
            content: `${ctx.options.mode} -> ${ctx.options.target.id}`,
            ephemeral: true
          })
        })
    )
  )
```

Supported chat input option types:

* `string`
* `integer`
* `number`
* `boolean`
* `user`
* `channel`
* `role`
* `mentionable`
* `attachment`

## Permissions

Use `.setPermissions(...)` to set Discord `default_member_permissions` on the command.

Accepted inputs follow the framework bitfield conventions, so these all work:

* permission names like `'MANAGE_GUILD'`
* raw bitfields like `BigInt(...)`
* arrays of permission names
* `PermissionsBitField`

`setDefaultMemberPermissions(...)` also exists as a compatibility alias, but `setPermissions(...)` is the recommended surface.

## Important behavior

Command definitions must provide either:

* `execute`
* or subcommands

That catches one class of invalid command definitions early.

## Deployment note

The command manager deploys registered commands through the application command API. If the client is already ready, deployment happens immediately. Otherwise it is deferred until the ready flow completes.

## Load commands from a directory

If you keep commands in separate files, the command manager can load them from disk:

```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
await client.commands.load('./commands')
```

Each loaded module should default-export a command definition.
