Commands
Commands are declared with createCommand and loaded with ArcClient. This page covers the minimum setup needed to create and register a command.
Create a command
The most common command is a slash command. Its definition lives in build.slash, and its handler lives in run.
import { createCommand } from "arcscord";
export const pingCommand = createCommand({
build: {
slash: {
name: "ping",
description: "Check if the bot is available",
},
},
run: ctx => ctx.reply("Pong!"),
});
Register commands
Load commands after the client is ready:
await client.waitReady();
const [err] = await client.loadCommands([pingCommand]);
if (err) {
client.logger.logError(err);
}
You can also register commands before the ready event by passing your Discord application id to ArcClient.
import { ArcClient } from "arcscord";
const client = new ArcClient(process.env.DISCORD_TOKEN!, {
intents: ["Guilds"],
applicationId: process.env.DISCORD_APPLICATION_ID!,
});
await client.loadCommands([pingCommand]);
await client.login(process.env.DISCORD_TOKEN!);
When applicationId is set, Arcscord can push commands through Discord's REST API before Discord.js hydrates client.application.
Load with handlers
loadHandlers can load commands, components, and events together. If applicationId is configured, command loading does not wait for clientReady.
await client.loadHandlers({
commands: [pingCommand],
components: [confirmButton],
events: [readyEvent],
}, true /* info logs */);
loadHandlers logs and forwards command registration errors through the client logger. Use loadCommands directly when you need to inspect the returned Result.
Command types
Arcscord supports several Discord application command shapes:
- Slash commands — use
createCommandwithbuild.slash - User context menu commands — use
createCommandwithbuild.user - Message context menu commands — use
createCommandwithbuild.message - Subcommands — use
buildCommandWithSubs, notcreateCommand
For subcommands, each subcommand is created with createCommand using a flat build (no slash wrapper), and the group is assembled with buildCommandWithSubs:
import { buildCommandWithSubs, createCommand } from "arcscord";
const banSubCommand = createCommand({
build: {
name: "ban", // no "slash" wrapper for subcommands
description: "Ban a member",
},
run: ctx => ctx.reply("Banned!"),
});
export const modCommand = buildCommandWithSubs({
name: "mod",
description: "Moderation tools",
subCommands: [banSubCommand],
});
Detailed pages
- Slash commands
- Command options
- Autocomplete
- Context menu commands
- Subcommands
- Permissions and contexts
- Registration
Pre-reply
Use preReply when a command may take longer than Discord's initial interaction response window.
export const reportCommand = createCommand({
build: {
slash: {
name: "report",
description: "Generate a report",
},
},
preReply: "ephemeral",
run: async (ctx) => {
const report = await generateReport();
await ctx.editReply(report);
return true;
},
});
preReply: true defers a public response. preReply: "ephemeral" defers a response visible only to the user who ran the command. Because the interaction is already deferred, use ctx.editReply() for the final response.
Use middleware for runtime checks such as bot permissions, member permissions, allowlists, or cooldowns.