ItsMyBot Docs

First plugin

Build a small slash command plugin with typed configuration.

This page builds a welcome-helper plugin. It exposes one /greet slash command and one configurable greeting.

Create files

Start with this layout:

welcome-helper/
  package.json
  src/
    index.ts
    metadata.ts
    config.ts
    commands/
      greet.ts
  README.md

Install the SDK:

pnpm add itsmybot

package.json

Add scripts for local author workflow:

{
  "name": "welcome-helper",
  "private": true,
  "type": "module",
  "scripts": {
    "bundle": "itsmybot bundle .",
    "publish": "itsmybot publish ."
  },
  "dependencies": {
    "itsmybot": "latest"
  },
  "devDependencies": {
    "typescript": "latest"
  }
}

metadata.ts

Keep metadata separate from behavior. Reviewers should be able to inspect plugin identity without reading command logic.

import { PluginCapability, PluginCategory } from "itsmybot";

export const metadata = {
  id: "welcome-helper",
  version: "0.1.0",
  name: "Welcome Helper",
  summary: "Send configurable welcome messages.",
  category: PluginCategory.Engagements,
  compatibilityDate: "2026-04-20",
  capabilities: [PluginCapability.DiscordInteractionReply] as const,
};

Use a stable id. Changing it creates a different plugin.

config.ts

defineConfig() keeps defaults typed and lets bundle generate the config schema.

import {  } from "itsmybot";

export interface Config extends <string, unknown> {
  /**
   * @title Greeting
   * @description Text used in slash command replies.
   * @minLength 1
   * @maxLength 80
   */
  : string;

  /**
   * @title Public replies
   * @description When enabled, command replies are visible to everyone.
   */
  : boolean;
}

export const  = <Config>({
  : "Welcome",
  : false,
});

.greeting;

commands/greet.ts

Command files should define options and command class together. That keeps context types tied to the actual option object.

import {
  ,
  type ,
  ,
  ,
} from "itsmybot";

import type { Config } from "../config";

const  = ({
  : ({
    : "Who should receive the greeting",
    // Discord validates slash command string option limits during publish too.
    : true,
    : 1,
    : 32,
  }),
});

export class  extends <Config, typeof > {
  readonly  = "greet";
  readonly  = "Send a configured greeting";
  readonly  = ;

  (: <Config, typeof >) {
    ...target;
target: string | undefined
return .( `${..}, ${...}`, { : !.. }, ); } }

index.ts

The entrypoint composes metadata, config, and handlers.

import {  } from "itsmybot";

import {  } from "./commands/greet";
import type { Config } from "./config";
export {  } from "./config";
import {  } from "./metadata";

class  extends <Config> {
  readonly  = .;
  readonly  = .;
  readonly  = .;
  readonly  = .;
  readonly  = .;
  readonly  = .;
  readonly  = .;
  readonly  = [new ()];
}

export default new ();

Bundle

Generate the artifact:

pnpm bundle

Expected output:

.itsmybot/
  manifest.json
  runtime.js

Do not edit generated files. Change source code, then bundle again.

On this page