▶ CARTRIDGE
Discord Bot Cartridge
A working discord.js v14 + TypeScript bot your AI agent can extend without breaking it.
$29 · one-time
Plus sales tax or VAT where applicable, calculated at checkout.
- One-time payment. No subscription, no account.
- Secure checkout by Stripe, the merchant of record.
- Your download starts on the next page. Bookmark it to re-download anytime.
- Plain files you can read and edit. Questions before you buy? support@agentcartridge.com
A complete starter Discord bot in discord.js 14.27 + TypeScript (strict), set up for AI-assisted coding: four slash commands that show the main patterns (/ping, /help, /roll with a Roll-again button, /tag with subcommands, autocomplete and SQLite storage), one interaction router with cooldowns and safe error replies, a command registration script with a dry run, 28 tests that run without a Discord token, Cursor, Claude Code and AGENTS.md rules that keep agents on the current discord.js v14 API, and setup and hosting guides. One-time purchase (sales tax or VAT added at checkout where applicable), instant download.
Requirements: Needs Node.js 22.13+ (24 LTS recommended), a Discord account, and a server where you can add bots to run it live. The tests and the registration dry run work without a Discord account. A bot is a long-running process: host it on a VPS or a background-worker service, not on serverless functions.
What's inside
| File | Covers |
|---|---|
src/commands/ | /ping, /help (embed), /roll (dice parser + Roll-again button), /tag (show, list, set, delete; autocomplete; Manage Server check; no pings) |
src/interactions.ts | One router for slash commands, autocomplete and buttons: per-user cooldowns, and an ephemeral error message instead of "The application did not respond" |
src/db/tags.ts | SQLite storage on Node's built-in node:sqlite (nothing to compile), with migrations and per-server limits |
src/register-commands.ts | Registers commands to your test server (instant) or globally, with --dry-run and --clear |
tests/ | 28 vitest tests, including integration tests that run real interactions through discord.js against a local mock Discord API. No token needed |
.cursor/rules/*.mdc | 4 Cursor rules: bot workflow (always on), discord.js 14.27 API (deprecated options to avoid, Discord's limits), commands, data |
CLAUDE.md + AGENTS.md | The same rules for Claude Code, Codex, OpenCode and other agents |
docs/ | SETUP.md (create the Discord app, invite the bot, run it), HOSTING.md (VPS with systemd, worker services, keeping the database), AGENT-PLAYBOOK.md (copy-paste prompts: new command, slow command, database feature, moderation command, welcome message, buttons, pre-launch review) |
README.md + LICENSE.md | Quick start, scripts, and the license: use it for any number of your own bots, free or commercial |
Peek inside
.cursor/rules/10-discordjs-v14.mdc · The first lines of one of the 4 Cursor rules.
---
description: discord.js 14.27 API rules (current options, deprecated ones to avoid, Discord limits)
globs: src/**/*.ts, tests/**/*.ts
alwaysApply: false
---
# discord.js 14.27 API
Pinned: `discord.js@14.27.0`. Check `node_modules/discord.js/typings/index.d.ts` when unsure. Imports come from `"discord.js"` (it re-exports builders, `Routes`, `MessageFlags`, `PermissionFlagsBits`, etc.). Local imports end in `.js` (NodeNext ESM): `import { roll } from "./roll.js"`.
## Use these, not the old forms
- Ready event: `client.once(Events.ClientReady, (c) => …)`. The `"ready"` event name is deprecated in favour of `"clientReady"`.
- Ephemeral replies: `reply({ content, flags: MessageFlags.Ephemeral })`. The `ephemeral: true` option is deprecated.
- Getting the reply back: `reply({ …, withResponse: true })` returns an `InteractionCallbackResponse` (message in `.resource?.message`). `fetchReply: true` is deprecated.
- Where a command works: `.setContexts(InteractionContextType.Guild)` (or `BotDM`, `PrivateChannel`). `setDMPermission()` is deprecated.
- Who can use a command by default: `.setDefaultMemberPermissions(PermissionFlagsBits.ManageGuild)` (whole command). For per-subcommand rules, check `interaction.memberPermissions?.has(...)` in code, like `/tag set`.
- Options: `interaction.options.getString("name", true)` for required options; without `true` it returns `null` when missing.
- Type guards on the union: `interaction.isChatInputCommand()`, `isAutocomplete()`, `isButton()`, `inGuild()`. Don't cast.
…Stripe emails your receipt. Lost your download link? Email us with the receipt and we'll sort it out. Questions: support@agentcartridge.com