# Codegen

Type your commands, emojis, and plugins by running seedcord codegen. Covers why a separate step exists, what it writes, how it loads your bot, catching a stale file in CI, and the commands it skips or rejects as duplicates.

Here's a command that declares one option.

```ts title="src/commands/Search.ts"
import {
    BuilderComponent,
    RegisterCommand
} from '@seedcord/gateway';

@RegisterCommand('global')
export class SearchCommand extends BuilderComponent<'command'> {
    constructor() {
        super('command');

        this.instance
            .setName('search')
            .setDescription('Look something up')
            .addStringOption((o) =>
                o
                    .setName('query')
                    .setDescription('The term')
                    .setRequired(true)
            );
    }
}
```

An option's name and its required flag are arguments to method calls. Those calls run when something constructs the class. TypeScript reads the source of that chain without running it, so the name `query` only exists once the chain has run.

`seedcord codegen` records those names for you. It imports every `.ts` and `.js` file under your commands folder, constructs each decorated class it finds, reads the JSON that class's builder produced, and writes what it found to `seedcord-gen.d.ts`.

```sh
pnpm run codegen
```

Run it after you add a command, change its options, attach a plugin, or edit your emoji block.

Your handler then reads its options through `this.options`. `getString('query')` comes back as `string`, because you marked that option required. A typo in the name stops the build. [Command options](/commands/options) covers what each kind returns.

You rerun it whenever a command changes, and the file sits stale until you do. `seedcord dev` offers to run codegen whenever it re-registers your commands, so most of the time you answer `y` and never think about it.

> **Note**
>
> Codegen writes the file into the `root` folder set in your `seedcord.config.ts`. A scaffolded project sets `root: './src'`, which puts it at `src/seedcord-gen.d.ts`.

## What it writes

Every run rewrites the whole file from scratch.

{/* prettier-ignore-start */}

| what it types                                                                                                | filled from                                                                          |
| ------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------ |
| [`SlashRegistry`](https://docs.seedcord.org/packages/core/latest/slash-registry)                             | every command class in your `commands` folder                                        |
| [`UserContextMenuRegistry`](https://docs.seedcord.org/packages/core/latest/user-context-menu-registry)       | the same folder, for right-click commands on a user                                  |
| [`MessageContextMenuRegistry`](https://docs.seedcord.org/packages/core/latest/message-context-menu-registry) | the same folder, for right-click commands on a message                               |
| [`EmojiMap`](https://docs.seedcord.org/packages/types/latest/emoji-map)                                      | the `bot.emojis` block on your config, which [Components](/components) shows in full |
| [`Core`](https://docs.seedcord.org/packages/gateway/latest/core)                                             | the key you gave each attached plugin                                                |

{/* prettier-ignore-end */}

`Core` only appears once you attach a plugin. It [types `this.core.db`](/plugins/typing), for example.

Codegen records only the keys you attached. TypeScript resolves each plugin's type from the bot you built, since your `attach()` call already names the plugin class. Your handler still reads `this.core.db` with every method that plugin declares.

> **Gateway and http differ**
>
> The rows codegen adds are the same either way. The interface it adds them to differs, since gateway's [`Core`](https://docs.seedcord.org/packages/gateway/latest/core) carries a `bot` member holding the discord.js client and its token. http's [`Core`](https://docs.seedcord.org/packages/http/latest/core) does not hold a connection.

## Codegen constructs your bot

To read your commands folder and your emoji block, codegen imports the module your `instance` setting points at. Constructing your bot runs every `attach()` call and every plugin constructor.

Even so, your bot never starts. Nothing calls `start()`, so no plugin connects, no task runs, and nothing you've written reaches Discord.

A command constructor that throws fails the whole run, since codegen has to construct the class to read its options. `CliCodegenCommandConstructorThrew` names the class, the file, and what your constructor threw. Keep anything that can fail out of a command constructor.

## Catching a stale file in CI

Some drift breaks the build for you. If you add a command without rerunning codegen, the handler naming its route fails to compile. Your editor flags it immediately.

Other drift compiles perfectly. If you delete a command, its entry stays in `SlashRegistry`, still typing a route your bot stopped answering. Passing `--check` renders the file in memory and compares it to the copy on disk, which catches the kind that still compiles.

```sh
pnpm exec seedcord codegen --check
```

When the two match, the command prints nothing and exits `0`. A difference prints the path it compared and exits `1`.

```txt output
Augmentations are out of date. Run `seedcord codegen` and commit /home/you/my-bot/src/seedcord-gen.d.ts.
```

`--check` only reports, so you fix the drift by running plain `seedcord codegen`. The scaffold does not wire a script for it, so put it wherever your pipeline runs its checks.

If codegen can't read your commands folder, it throws `CliCodegenCommandsDirUnreadable`, because a run that found no commands would pass `--check` against a file that's already stale.

## Commands codegen passes over

Codegen records a command class once it carries [`@RegisterCommand`](https://docs.seedcord.org/packages/core/latest/register-command). If a class has no decorator, codegen skips that export entirely, so your route never appears in `SlashRegistry`. You get the same compile failure as a missed codegen run.

Your commands folder can hold helpers and constants too. Codegen imports each of those files as well, keeps the exports that are decorated command classes, and ignores everything else.

## Two commands, one name

Discord scopes command names per kind. seedcord enforces the same rule. Two commands resolving to one slash route throw `CliCodegenDuplicateRoute`. Two context menus of one kind sharing a name throw `CliCodegenDuplicateContextMenu`. Both errors print the two file paths, so you know which one to rename.
