Skip to main content
Yato uses the gcommands framework to handle commands. Commands are automatically loaded from the src/commands/ directory and work as both slash commands and mention-based commands.

Command module structure

All commands follow a standard module.exports pattern. There are two ways to define commands:
The most common pattern used in Yato:
src/commands/utilities/ping.js
const { MessageEmbed } = require('discord.js');
const colors = require('../../config/colors.json');

module.exports = {
  name: 'ping',
  slash: true,
  description: 'Checks the bot ping!',
  run: ({ client, respond }) => {
    const choices = [
      'Is this really my ping?', 
      'Is this okay? i can\'t look!', 
      'I hope it isn\'t bad!'
    ];
    const response = choices[Math.floor(Math.random() * choices.length)];

    const embed = new MessageEmbed()
      .setTitle(`:ping_pong: ${response}`)
      .setColor(colors.default)
      .addField('API Latency', `**${Math.round(client.ws.ping)}ms**`);

    respond(embed);
  }
};

Creating a new command

1

Choose a category

Determine which category your command belongs to:
  • games/ - Game integrations
  • images/ - Image generation and reactions
  • information/ - Server and user information
  • memes/ - Entertainment and memes
  • misc/ - Miscellaneous features
  • moderation/ - Moderation tools
  • utilities/ - Bot utilities
  • weeb/ - Anime and manga features
2

Create the command file

Create a new .js file in the appropriate category directory:
touch src/commands/utilities/mycommand.js
3

Define the command structure

Use the standard module.exports pattern with required properties:
module.exports = {
  name: 'mycommand',
  slash: true,
  description: 'What this command does',
  run: ({ client, respond }) => {
    // Your command logic
  }
};
4

Restart the bot

Commands are loaded on startup, so restart the bot to register your new command:
npm run dev

Command properties

All available properties you can use in command definitions:

Required properties

PropertyTypeDescription
namestringCommand name (lowercase, no spaces)
descriptionstringWhat the command does
runfunctionCommand execution logic

Optional properties

PropertyTypeDescription
slashbooleanEnable as slash command (default: false)
cooldownnumberCooldown in seconds
guildOnlystringRestrict to specific guild ID
userRequiredPermissionsstringRequired user permissions
clientRequiredPermissionsstringRequired bot permissions
minArgsnumberMinimum argument count
expectedArgsstring|arrayArgument definitions
Set slash: true to enable the command as a slash command. Without this, the command only works with the mention prefix.

Defining arguments

There are two ways to define command arguments:
Simple string format used in the ban command at src/commands/moderation/ban.js:13:
module.exports = {
  name: 'ban',
  minArgs: 1,
  expectedArgs: '<user:6:Select the User> [reason:3:Reason for banning?]',
  run: async ({ guild, respond }, arrayArgs, args) => {
    const banMember = guild.members.cache.get(args.user);
    const reason = args.reason || 'No reason provided';
    // ...
  }
};
Format: <name:type:description> or [name:type:description]
  • <> = required argument
  • [] = optional argument
  • Type codes: 3=string, 6=user, 7=channel, etc.

Argument types

Common Discord slash command option types:
TypeCodeDescription
String3Text input
Integer4Whole number
Boolean5True/false
User6User mention
Channel7Channel mention
Role8Role mention

Run function parameters

The run function receives destructured parameters:
run: async ({ client, guild, channel, member, respond, edit }, arrayArgs, args) => {
  // client - Discord.js client instance
  // guild - The guild where command was used
  // channel - The channel where command was used
  // member - The member who used the command
  // respond - Function to send response
  // edit - Function to edit response
  // arrayArgs - Arguments as array
  // args - Arguments as object
}

Responding to commands

Use the respond() function to send messages:
const embed = new MessageEmbed()
  .setColor(colors.default)
  .setDescription('Hello!');
  
respond(embed);

Permission checks

Add permission requirements to your command:
src/commands/moderation/ban.js
module.exports = {
  name: 'ban',
  userRequiredPermissions: 'BAN_MEMBERS',
  clientRequiredPermissions: 'BAN_MEMBERS',
  run: async ({ guild, member, respond }, arrayArgs, args) => {
    // gcommands automatically checks permissions
    // This code only runs if both user and bot have BAN_MEMBERS
  }
};
Common permissions:
  • ADMINISTRATOR
  • MANAGE_GUILD
  • MANAGE_CHANNELS
  • KICK_MEMBERS
  • BAN_MEMBERS
  • MANAGE_MESSAGES
  • CREATE_INSTANT_INVITE

Using shared utilities

Import shared utilities from the structures folder:
const utils = require('../../structures/utils');
const colors = require('../../config/colors.json');
const emojis = require('../../config/emojis.json');

module.exports = {
  run: async ({ client, channel, respond }) => {
    // Use utility functions
    const embeds = await utils.animeMangaSearch('anime', query, channel);
    
    // Use config values
    const TickYes = client.emojis.cache.get(emojis.TickYes);
    
    const embed = new MessageEmbed()
      .setColor(colors.green)
      .setDescription(`${TickYes} Success!`);
  }
};

Interactive components

Create commands with buttons and collectors:
src/commands/weeb/anime.js
const { MessageButton, MessageActionRow } = require('gcommands');

module.exports = {
  run: async ({ member, respond, edit }) => {
    // Create buttons
    const nextPage = new MessageButton()
      .setStyle('gray')
      .setLabel('Next')
      .setID('next')
      .toJSON();
    
    const buttonRow = new MessageActionRow()
      .addComponent(nextPage);
    
    const msg = await respond({
      content: embed,
      components: buttonRow
    });
    
    // Create collector
    const filter = (button) => button.clicker.user.id === member.user.id;
    const collector = msg.createButtonCollector(filter, { 
      time: 60000 
    });
    
    collector.on('collect', (button) => {
      button.edit({ content: newEmbed });
    });
  }
};

Example: Complete command

Here’s a complete example combining multiple features:
src/commands/utilities/serverinfo.js
const { MessageEmbed } = require('discord.js');
const moment = require('moment');
const colors = require('../../config/colors.json');

module.exports = {
  name: 'serverinfo',
  slash: true,
  description: 'Display information about the server',
  cooldown: 5,
  run: ({ guild, respond }) => {
    const embed = new MessageEmbed()
      .setTitle(guild.name)
      .setColor(colors.default)
      .setThumbnail(guild.iconURL({ dynamic: true }))
      .addField('Owner', `<@${guild.ownerID}>`, true)
      .addField('Members', guild.memberCount.toString(), true)
      .addField('Created', moment(guild.createdAt).format('MMM DD, YYYY'), true)
      .addField('Channels', guild.channels.cache.size.toString(), true)
      .addField('Roles', guild.roles.cache.size.toString(), true)
      .setFooter(`ID: ${guild.id}`);
    
    respond(embed);
  }
};
Check existing commands in src/commands/ for more examples and patterns used throughout Yato.

Build docs developers (and LLMs) love