Skip to content
/docs/adding-a-command

Developers

Add a command

The real module contract the loader expects, and how the pieces behave.

A command is one CommonJS file in src/commands/ (or src/commands/group/ for group ones). The loader at src/handlers/command.handler.js scans the directory on boot — drop a file in, restart, done. Packaged builds load the same files through a manifest, so nothing else to touch.

The module contract

src/commands/flip.cjs
// A real example in the spirit of src/commands/rand.cjsconst { tr } = require("../utils/i18n.cjs");const { sendBotMessage } = require("../utils/sendBotMessage.cjs"); module.exports = {  name: "flip",  aliases: ["coin"],                 // optional, conflicts are reported and skipped  description: { en: "Flips a coin.", ar: "يرمي قطعة." },  usage: { en: "flip", ar: "flip" },  chat: "all",                       // "all" | "group" | "private"   async execute(sock, msg, args, body, groupMetadata) {    const heads = Math.random() < 0.5;    await sendBotMessage(sock, msg.key.remoteJid,      { text: heads ? "Heads" : "Tails" },      { replyTo: msg });  },};
FieldNotes
nameRequired, unique — it becomes !name.
aliasesOptional. Conflicts with an existing name are logged and ignored, not overwritten.
description / usageA plain string or { en, ar } — the help menus, the panel's Command Catalog and the dashboard all read these. Arabic falls back to English for a string.
chat"all", "group" or "private" — where the dispatcher allows the command at all.
userAdminRequired / botAdminRequiredOptional gates: the sender must be a WhatsApp group admin, and/or the bot must be one.
execute(sock, msg, args, body, groupMetadata, ctx)args is the split argument list; body is the raw message text (needed for multiline input); groupMetadata is preloaded for group chats.

Permissions come from src/config/defaults.cjs's command_permissions table — a new command not listed there starts as MEMBERS (anyone in the chat), and the operator can raise or lower it from the panel at any time without touching code (an override is stored in the database and layered over the defaults).

Useful helpers used across the codebase: tr(en, ar) for bilingual strings, sendBotMessage(sock, jid, content, { replyTo }) for replies, createStatus from utils/statusMessage.cjs for a live status line you can update or remove, and runtimeConfig.getPrefix() for the current prefix inside execute. Media commands follow the sticker stack's pattern: src/stickers/errors.cjs for typed failures and an errorText helper in utils/stickerBot.cjs that renders them.