Skip to content
Bots

Discord bot (TypeScript)

discord.js v14 rules and an add-a-slash-command skill for building a Discord bot that registers commands properly and never leaks its token.

Verified install Not agent-tested v1.1.0 MIT updated discordnodejstypescript
Equips
  • 2 2 Rules
  • 1 1 Skills
  • – 0 MCP

Discord bots are a classic first agent project and a classic way to leak a token to GitHub. This loadout sets up a clean discord.js v14 structure (one file per slash command, a loader, a deploy script), teaches the agent the three-second interaction rule and the intents model, and gives it a skill for adding new commands end to end.

What's in it

  • One-file-per-command structure with a separate command deploy script
  • The three-second rule: defer, then edit the reply
  • Minimal intents; no privileged Message Content intent unless you really need it
  • Skill that adds, registers and documents a new slash command

You'll need

  • Tools: node
  • Environment variables: DISCORD_TOKEN, DISCORD_CLIENT_ID, DISCORD_GUILD_ID
Level 1 · automated

Verification

Verified install

Checked at commit ad36e85 · 9 passed, 0 failed, 1 not applicable

CheckResultWhat we found
Listinglisting.yaml matches the schema and declares every file in the folder. Pass
Schema valid; 5 files declared, none missing or extra
  • tested.status: untested (agent tests are separate from Level 1)
Files parseJSON parses; SKILL.md and .mdc front matter is valid YAML with the fields each agent needs; code fences are closed. Pass All 5 files parse; front matter valid
AdaptersCLAUDE.md imports @AGENTS.md, GEMINI.md imports @./AGENTS.md, and both match the generator. Pass
CLAUDE.md and GEMINI.md import AGENTS.md and are up to date
  • CLAUDE.md: matches the generator
  • GEMINI.md: matches the generator
Install pathsEvery file lands where each agent documents it, with no collisions, and the laid-out project is re-discovered correctly. Pass
Correct paths for all 5 agents; layouts re-discovered
  • Claude Code: 3 files, 1 skill in .claude/skills/
  • Codex CLI: 2 files, 1 skill in .agents/skills/
  • Cursor: 3 files, 1 skill in .agents/skills/, 1 rule
  • Gemini CLI: 3 files, 1 skill in .agents/skills/
  • GitHub Copilot: 2 files, 1 skill in .agents/skills/
MCP configmcp.json is structurally valid, converts to each agent's format, declares no literal secrets, and referenced packages exist on npm/PyPI. Not applicable No MCP servers in this loadout
Safety scanThe intake scanner finds no credentials, risky shell, hidden Unicode or prompt-injection wording, and the listing's network flag is honest. Pass
Clean: no credentials, risky shell or hidden text
  • Scanner intake-precheck/1: verdict clean; network no (listing says yes)
ReferencesLinks and file paths between the loadout's files resolve, including for each agent's installed layout. Pass No cross-file references to check
Size limitsFile count and sizes are within the submission limits; SKILL.md bodies stay under 500 lines. Pass
5 files, 7.0 KB total; largest AGENTS.md 3.5 KB
  • Limits: 30 files, 32 KB per file, 128 KB total, 500 lines per skill or rule
LicenceA recognised SPDX licence, with the licence text available. Pass MIT, by Agent Loadout; text in the repository LICENSE
Starter buildA minimal fixture project with the loadout applied installs and builds or type-checks, and the loadout's own code examples compile. Pass
discord.js v14 bot in the loadout's layout type-checks (tsc strict) and the loadout's example command builds a valid slash command
  • Applied 6 loadout files at every agent's paths
  • Example from AGENTS.md:17 (ts) → src/commands/roll.ts
  • Example from .cursor/rules/discord-commands.mdc:9 (ts) → src/commands/roll-cursor-rule.ts
  • ✓ install: npm ci --no-audit --no-fund
  • ✓ type-check and build (tsc): npm run build
  • ✓ commands serialise for Discord: node dist/check-commands.js
  • Covers: src/commands/<name>.ts exports data + execute, loaded by src/index.ts (as AGENTS.md describes)
  • Covers: Example commands from AGENTS.md and the Cursor rule compile and pass discord.js's builder validation (name/description limits)
  • Covers: Does not log in or call Discord: no token needed

What this means: a script checked the files themselves: they parse, they install where each agent looks, any MCP config is sound, the safety scan is clean, references between files resolve, and, where a free and repeatable fixture exists, a small starter project builds with the loadout applied. No AI agent was run. Per-agent results ("tested with agent") are separate and stay untested until an agent actually runs.

Install

Choose your agent. Run the commands from your project root, or download a zip already laid out in the right folders.

Claude Code reads CLAUDE.md (imports AGENTS.md with @AGENTS.md) and skills from .claude/skills/.

Download zip
curl -fsSL --create-dirs -o AGENTS.md https://loadout.jnw-it.com/raw/discord-bot-ts/1.1.0/AGENTS.md
curl -fsSL --create-dirs -o CLAUDE.md https://loadout.jnw-it.com/raw/discord-bot-ts/1.1.0/CLAUDE.md
curl -fsSL --create-dirs -o .claude/skills/add-slash-command/SKILL.md https://loadout.jnw-it.com/raw/discord-bot-ts/1.1.0/skills/add-slash-command/SKILL.md
FileGoes to
AGENTS.mdAGENTS.md
CLAUDE.mdCLAUDE.md
skills/add-slash-command/SKILL.md.claude/skills/add-slash-command/SKILL.md

Already have an AGENTS.md or CLAUDE.md? The commands above overwrite it — download the file instead and merge the sections you want.

Files

Rules AGENTS.md Discord bot project rules. 63 lines
Download Raw
# AGENTS.md: Discord bot (TypeScript, discord.js v14)

## Layout
```
src/
  index.ts            creates the Client, loads commands and events, logs in
  deploy-commands.ts  registers slash commands with Discord (run by hand, not on every start)
  commands/<name>.ts  one slash command per file: exports `data` (SlashCommandBuilder) and `execute(interaction)`
  events/<name>.ts    one gateway event per file: exports `name`, `once?`, `execute(...)`
  lib/                shared helpers (embeds, db, permissions)
```
Run with `npm run dev` (tsx watch) locally. `npm run deploy` runs `deploy-commands.ts`.

## Command file shape
Each file in `src/commands/` exports `data` and `execute`, nothing else:

```ts
import { SlashCommandBuilder, type ChatInputCommandInteraction } from "discord.js";

export const data = new SlashCommandBuilder()
  .setName("roll")                       // lowercase, 1–32 chars, no spaces
  .setDescription("Roll a dice")         // required, 1–100 chars
  .addIntegerOption((o) => o.setName("sides").setDescription("Number of sides").setMinValue(2).setMaxValue(1000));

export async function execute(interaction: ChatInputCommandInteraction) {
  const sides = interaction.options.getInteger("sides") ?? 6;
  const result = 1 + Math.floor(Math.random() * sides);
  await interaction.reply({ content: `🎲 ${result} (d${sides})` });
}
```

## Token and secrets
- `DISCORD_TOKEN`, `DISCORD_CLIENT_ID`, `DISCORD_GUILD_ID` come from `.env` (git-ignored). `.env.example` lists them with dummy values.
- Never print the token, commit it, or paste it into an embed or error message. If it leaks, the human must reset it in the
  Developer Portal → Bot → Reset Token. Discord also auto-revokes tokens it finds in public repos.

## Intents
- Request the minimum: `GatewayIntentBits.Guilds` covers slash commands.
- `GuildMembers`, `GuildPresences` and `MessageContent` are **privileged**: they must be switched on in the Developer
  Portal and are reviewed once a bot is in 100+ servers. Prefer slash commands over reading message content.

## Interactions
- Discord gives you **3 seconds** to respond. If work might take longer (API calls, database, AI), call
  `await interaction.deferReply()` first, then `await interaction.editReply(...)`.
- Private replies: `interaction.reply({ content, flags: MessageFlags.Ephemeral })`. (`ephemeral: true` is deprecated.)
- Every `execute` is wrapped by the loader in try/catch. On error: log it, then reply or follow up with a short
  ephemeral "Something went wrong" — never the stack trace.
- Check permissions for moderation commands with `.setDefaultMemberPermissions(...)` on the builder *and* re-check in code.
- Validate options: string lengths, number ranges (`.setMinValue/.setMaxValue`), and never pass user text into shell commands or eval.

## Registering commands
- During development register to one guild (`Routes.applicationGuildCommands(clientId, guildId)`) — updates are instant.
- Global registration (`Routes.applicationCommands(clientId)`) is for release. Do not register on every bot start; there are rate limits.
- After changing a command's `data`, remind the human to run `npm run deploy`.

## Style
- TypeScript strict, ES modules, `async/await`. No `any` on interaction types: use `ChatInputCommandInteraction`.
- Keep command files small; move logic into `lib/` when two commands share it.
- Rate-limit costly commands per user (a simple in-memory cooldown map is fine to start).

## Before you say "done"
`npm run build` (tsc) passes, the new command is in `commands/`, and you have told the human whether to re-run deploy.
Adapter CLAUDE.md Imports AGENTS.md for Claude Code. 10 lines
Download Raw
# CLAUDE.md

@AGENTS.md

## Claude Code notes
- Skills from this loadout live in `.claude/skills/`: `add-slash-command`. Use them when their description matches the task.
- Follow AGENTS.md above; where this file and AGENTS.md disagree, AGENTS.md wins.

<!-- From the Agent Loadout "Discord bot (TypeScript)" v1.1.0 — https://loadout.jnw-it.com/loadouts/discord-bot-ts/ -->
Adapter GEMINI.md Imports AGENTS.md for Gemini CLI. 10 lines
Download Raw
# GEMINI.md

@./AGENTS.md

## Gemini CLI notes
- Skills from this loadout live in `.agents/skills/`: `add-slash-command`. Use them when their description matches the task.
- Follow AGENTS.md above; where this file and AGENTS.md disagree, AGENTS.md wins.

<!-- From the Agent Loadout "Discord bot (TypeScript)" v1.1.0 — https://loadout.jnw-it.com/loadouts/discord-bot-ts/ -->
Cursor rule .cursor/rules/discord-commands.mdc Rule for files in src/commands/. 28 lines
Download Raw
---
description: Shape of a discord.js v14 slash command file
globs: src/commands/**/*.ts
alwaysApply: false
---

Each file exports `data` and `execute`, nothing else:

```ts
import { SlashCommandBuilder, MessageFlags, type ChatInputCommandInteraction } from "discord.js";

export const data = new SlashCommandBuilder()
  .setName("roll")                       // lowercase, 1–32 chars, no spaces
  .setDescription("Roll a dice")         // required, 1–100 chars
  .addIntegerOption((o) => o.setName("sides").setDescription("Number of sides").setMinValue(2).setMaxValue(1000));

export async function execute(interaction: ChatInputCommandInteraction) {
  const sides = interaction.options.getInteger("sides") ?? 6;
  const result = 1 + Math.floor(Math.random() * sides);
  await interaction.reply({ content: `🎲 ${result} (d${sides})` });
}
```

- If `execute` awaits anything slow, `deferReply()` first and `editReply()` after.
- Use `flags: MessageFlags.Ephemeral` for private replies, not `ephemeral: true`.
- Required options must be added before optional ones.
- Do not register commands from here; that is `src/deploy-commands.ts`.
Skill skills/add-slash-command/SKILL.md Adds and registers a new slash command. 24 lines
Download Raw
---
name: add-slash-command
description: Add a new slash command to a discord.js v14 bot, register it and document it. Use when the user asks for a new bot command, e.g. "add a /poll command".
---

# Add a slash command

1. **Clarify in one line** if needed: command name, options (name, type, required?), who can use it, public or private reply.
   Otherwise choose sensible defaults and state them.
2. **Check the name is free:** look in `src/commands/` and in the `data.setName(...)` calls.
3. **Create `src/commands/<name>.ts`** following the command file shape in AGENTS.md:
   - `SlashCommandBuilder` with name, description, typed options with limits.
   - Moderation or admin commands: `.setDefaultMemberPermissions(PermissionFlagsBits.<Perm>)` and `.setContexts(InteractionContextType.Guild)`
     so they cannot run in DMs.
   - `execute`: validate, `deferReply()` if anything is slow, do the work, reply.
   - Handle the expected failures (missing permission, bad input, external API down) with a friendly ephemeral message.
4. **Check the loader** in `src/index.ts` picks up new files automatically. If commands are listed by hand, add it there and in
   `deploy-commands.ts`.
5. **Type-check:** `npm run build` or `npx tsc --noEmit`.
6. **Register:** tell the human to run `npm run deploy` (guild registration is instant). Only run it yourself if they ask and
   `.env` is already set up — it uses the bot token.
7. **Document:** add the command to the commands table in `README.md` (name, options, who can use it).
8. **Report:** the file created, the command signature (`/poll question:<text> duration:<minutes>`), and how to try it.

All files: source zip · Licence MIT · By Agent Loadout · First listed

Installing and testing

How do I install Discord bot (TypeScript) in Claude Code?

From your project root, put AGENTS.md, CLAUDE.md, skills/add-slash-command/SKILL.md at .claude/skills/add-slash-command/SKILL.md. The "Claude Code" tab on this page has the curl commands, or download https://loadout.jnw-it.com/download/discord-bot-ts/claude-code.zip, which is already laid out. Do not overwrite an existing AGENTS.md or CLAUDE.md; merge it.

How do I install Discord bot (TypeScript) in Codex CLI?

From your project root, put AGENTS.md, skills/add-slash-command/SKILL.md at .agents/skills/add-slash-command/SKILL.md. The "Codex CLI" tab on this page has the curl commands, or download https://loadout.jnw-it.com/download/discord-bot-ts/codex.zip, which is already laid out. Do not overwrite an existing AGENTS.md or CLAUDE.md; merge it.

How do I install Discord bot (TypeScript) in Cursor?

From your project root, put AGENTS.md, .cursor/rules/discord-commands.mdc, skills/add-slash-command/SKILL.md at .agents/skills/add-slash-command/SKILL.md. The "Cursor" tab on this page has the curl commands, or download https://loadout.jnw-it.com/download/discord-bot-ts/cursor.zip, which is already laid out. Do not overwrite an existing AGENTS.md or CLAUDE.md; merge it.

How do I install Discord bot (TypeScript) in Gemini CLI?

From your project root, put AGENTS.md, GEMINI.md, skills/add-slash-command/SKILL.md at .agents/skills/add-slash-command/SKILL.md. The "Gemini CLI" tab on this page has the curl commands, or download https://loadout.jnw-it.com/download/discord-bot-ts/gemini-cli.zip, which is already laid out. Do not overwrite an existing AGENTS.md or CLAUDE.md; merge it.

How do I install Discord bot (TypeScript) in GitHub Copilot?

From your project root, put AGENTS.md, skills/add-slash-command/SKILL.md at .agents/skills/add-slash-command/SKILL.md. The "GitHub Copilot" tab on this page has the curl commands, or download https://loadout.jnw-it.com/download/discord-bot-ts/copilot.zip, which is already laid out. Do not overwrite an existing AGENTS.md or CLAUDE.md; merge it.

Has Discord bot (TypeScript) been tested?

It passed the Level 1 automated install checks on 2026-10-16: the files parse, install to each agent's documented paths, and pass the safety scan. No AI agent has run it yet, so no agent pass or fail is claimed.

More for Claude Code, Codex, Cursor, Gemini CLI and GitHub Copilot.