Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/onesoft-sudo/sudobot/llms.txt

Use this file to discover all available pages before exploring further.

SudoBot extensions let you add custom commands, event listeners, and services to your bot instance without modifying the core source. This guide walks you through creating a TypeScript extension from scratch — from directory setup through to running your first custom command.

Prerequisites

  • SudoBot built and running (see Quickstart)
  • Node.js v21+ or Bun v1.1.12+
  • Basic TypeScript knowledge

Project structure

Each extension lives in a subdirectory of your extensions root. The final layout looks like this:
installed_extensions/
└── hello/
    ├── src/
    │   ├── commands/
    │   │   └── HelloCommand.ts
    │   ├── events/
    │   │   └── MessageCreateEventListener.ts
    │   └── index.ts
    ├── extension.json
    ├── package.json
    └── tsconfig.node.json

Step-by-step setup

1

Configure the extensions directory

Add EXTENSIONS_DIRECTORY to your .env file and create the directory:
.env
EXTENSIONS_DIRECTORY=/path/to/sudobot/installed_extensions
mkdir installed_extensions
mkdir -p installed_extensions/hello/src/commands
mkdir -p installed_extensions/hello/src/events
2

Create extension.json

Inside installed_extensions/hello/, create extension.json:
extension.json
{
    "id": "org.example.sudobot.extension.hello",
    "main": "index.js",
    "src_main": "index.ts",
    "commands": "commands",
    "events": "events",
    "language": "typescript",
    "main_directory": "./build",
    "src_directory": "./src",
    "build_command": "npm run build"
}
3

Initialize npm and install dependencies

From inside installed_extensions/hello/, run:
npm init -y
npm install --save ../..
npm install -D typescript
The ../.. path links to the SudoBot project root so your extension can import core utilities.
4

Create tsconfig.node.json

tsconfig.node.json
{
    "compilerOptions": {
        "target": "ESNext",
        "module": "CommonJS",
        "moduleResolution": "node",
        "rootDir": "./src",
        "baseUrl": "./",
        "paths": {
            "@sudobot/*": ["node_modules/sudobot/build/out/main/typescript/*"],
            "@framework/*": ["node_modules/sudobot/build/out/framework/typescript/*"]
        },
        "resolveJsonModule": true,
        "outDir": "./build",
        "allowSyntheticDefaultImports": true,
        "esModuleInterop": true,
        "strict": true,
        "skipLibCheck": true
    },
    "exclude": ["./tests", "./build"]
}
Then create a symlink so TypeScript picks it up:
ln -s ./tsconfig.node.json ./tsconfig.json
5

Update package.json

Add module aliases and a build script to package.json:
package.json
{
  "_moduleAliases": {
    "@framework": "node_modules/sudobot/build/out/framework/typescript",
    "@sudobot": "node_modules/sudobot/build/out/main/typescript"
  },
  "scripts": {
    "build": "tsc"
  }
}
6

Create the entry point

Create src/index.ts:
src/index.ts
import "module-alias/register";
import { Extension } from "@sudobot/core/Extension";

class HelloExtension extends Extension {
    // Initialization logic goes here if needed
}

export default HelloExtension;
7

Add a custom command

Create src/commands/HelloCommand.ts:
src/commands/HelloCommand.ts
import { Command, type CommandMessage } from "@framework/commands/Command";
import type Context from "@framework/commands/Context";

class HelloCommand extends Command {
    public override readonly name = "hello";
    public override readonly description = "A simple hello-world command.";

    public override async execute(context: Context<CommandMessage>) {
        await context.reply("Hello world, from the hello extension!");
    }
}

export default HelloCommand;
8

Add an event listener

Create src/events/MessageCreateEventListener.ts:
src/events/MessageCreateEventListener.ts
import EventListener from "@framework/events/EventListener";
import { Events } from "@framework/types/ClientEvents";
import type { Message } from "discord.js";

class MessageCreateEventListener extends EventListener<Events.MessageCreate> {
    public override readonly name = Events.MessageCreate;

    public override async execute(message: Message<boolean>): Promise<void> {
        if (message.author.bot) return;

        if (message.content === "ping") {
            await message.reply("Pong, from the hello extension!");
        }
    }
}

export default MessageCreateEventListener;
9

Build and run

Build your extension, then start the bot:
npm run build
Then from the SudoBot project root:
./blazew run
SudoBot will automatically discover and load your extension on startup. The /hello command will be available on any server.
Make sure you build SudoBot itself before building your extension. The TypeScript path aliases point to SudoBot’s build/ directory.

Next steps

Extensions Overview

Learn about the official bundled extensions and how to install prebuilt ones.

Configuration

Configure EXTENSIONS_DIRECTORY and other environment settings.

Build docs developers (and LLMs) love