Documentation

C0D loads module files from bot/modules/. Each .cod file lists commands, optional slash options, and either a reply string or an action chain.

Install & run

You need Node.js 18+ and a Discord application (bot token + client ID). The bot code lives in the bot/ folder.

1. Get the project

Clone the repo or copy the bot/ directory to your machine.

2. Install dependencies

cd bot
npm install

3. Configure environment

Copy .env.example to .env and fill in values from the Discord Developer Portal.

DISCORD_TOKEN=your_bot_token
DISCORD_CLIENT_ID=your_application_id
# Optional for instant guild command updates while developing:
# DISCORD_GUILD_ID=your_server_id

Under Bot → Privileged Gateway Intents, enable Server Members Intent for moderation features. Enable Message Content Intent only if you add code that reads message text.

4. Start the bot

npm start

.cod file format

A minimal module with a plain text reply (no action chain) looks like this:

{
  "meta": { "name": "ping", "version": "1.0.0" },
  "commands": [
    {
      "name": "ping",
      "description": "Health check",
      "response": "Pong!",
      "ephemeral": false
    }
  ]
}

Simple replies

If a command has response and no actions array (or an empty one), the bot sends that text once. Use ephemeral: true for replies only visible to the user who ran the command.

Action chains

If actions is a non-empty array, the bot defers the reply, runs each action in order, then sends one combined message (truncated to Discord limits). Mix moderation and channel actions with reply steps as needed.

"actions": [
  { "type": "purge_messages", "count_option": "amount" },
  { "type": "reply", "text": "Cleanup finished." }
]

Action types

  • reply - text (or content)
  • purge_messages - count fixed number, or count_option for a slash integer option name
  • create_channel - name or name_option; optional name_template with {user}, {userid}, {random}; ticket_style: true hides the channel from @everyone and grants access to the user who invoked the action
  • delete_channel - channel_option (slash channel option name)
  • ban_member - user_option, delete_message_days, optional reason_option
  • kick_member - user_option, optional reason_option
  • timeout_member - user_option, minutes or minutes_option
  • lock_channel / unlock_channel - optional channel_option (defaults to current channel)
  • slowmode - seconds or seconds_option, optional channel_option
  • send_message - channel_option (slash channel) or channel_id; content or content_option for slash string
  • send_embed - same channel targeting; embed object (title, description, color, fields, footer); optional components array (see below)

Buttons, dropdowns & ticket panels

A root interactions object maps custom_id strings to action lists. When someone clicks a button or uses a string select menu, those actions run (slash options are not available - use placeholders like {select_value} in reply text).

Inside send_embed, components is an array of rows. Each row has "type": "ACTION_ROW" and components: buttons with type: "BUTTON", custom_id, label, style (PRIMARY, SECONDARY, SUCCESS, DANGER), or type: "STRING_SELECT" with options array (label, value, optional description).

Slash options

Declare options on each command with an options array. Option type values: STRING, INTEGER, BOOLEAN, USER, CHANNEL, ROLE. Use required: false for optional inputs.

Default permissions

Set default_member_permissions to one of: Administrator, BanMembers, KickMembers, ModerateMembers, ManageChannels, ManageMessages - so only members with that permission see the command in the picker.

Discord Developer Portal

Enable Server Members Intent and Message Content Intent (if you extend the bot to read message bodies) under Bot → Privileged Gateway Intents. The bot uses Guilds, GuildMembers, GuildModeration, and GuildMessages.

Invite the bot with scopes bot and applications.commands, and grant permissions for the actions you use (Manage Channels, Moderate Members, Ban Members, Manage Messages, etc.).

How loading works

On startup, index.js parses every *.cod in modules/, merges slash commands, and registers them. Duplicate slash names are overwritten - watch the console.

Set DISCORD_GUILD_ID in .env for instant guild command updates while developing. Omit it for global commands (propagation can take up to an hour).