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)
  • JSON data - generic data_* actions (read / write / increment / lists / leaderboard); paths and filenames are yours (see Data files).

Data files (bot/data/)

Each module gets a folder data/<module-name>/ where <module-name> is sanitized meta.name from the .cod file (or the filename). Inside it you can use any <basename>.json you reference from actions (data_file). Shapes are not fixed: use whatever JSON fits your game (e.g. users.<id>.coins, root array entries, etc.). *.json under data/ is gitignored.

data-store.js exposes readModuleJson / writeModuleJson. The data_* actions below call those for you.

Path templates

Dotted paths support placeholders: {userid} (invoker), {select_value} (menus), {option_user:OPTION_NAME} (slash USER option), {option_string:OPTION_NAME}. Messages also support {mention}, {user}, {random}.

Data action types

  • data_get - data_file, path, optional default, message ({value}). Optional derive object for extra fields from the read number, e.g. "derive": { "level": { "op": "div_floor_add", "by": 100, "add": 1 } } adds {level}.
  • data_set - data_file, path, and value or value_integer_option / value_string_option / value_boolean_option. Optional success_message.
  • data_increment - data_file, path, delta and/or delta_option, optional default_if_missing, clamp_min, clamp_max, message ({value}, {delta}). Optional target_user_option for {target} in the message (slash).
  • data_append / data_append_unique - data_file, path to an array, item template (default {userid}), max_length, optional messages.
  • data_daily_claim - data_file, stamp_path, counter_path, reward, compare_mode utc_date, already_message, success_message ({value} = new counter).
  • data_transfer - slash only: from_path, to_path, amount_option, target_user_option (for {target}), data_file, optional message.
  • data_rank - object_path to an object of records, score_key nested numeric field, order desc|asc, limit, header, score_label, empty_message, optional include_zero.

Examples: bot/modules/economy.cod (wallet + transfer + rank), leveling.cod, giveaway.cod. Web templates economy-demo, leveling-demo, giveaway, gamble (chips).

Module Builder (data blocks)

The web Module Builder includes green data blocks for data_get, data_set, data_increment, list append (data_append / data_append_unique via one block), data_daily_claim, data_transfer, and data_rank. Import a .cod file to edit those fields visually. Slash options are merged automatically from path placeholders ({option_user:…}, {option_string:…}), from data_transfer’s amount_option / target_user_option, from data_increment’s delta_option and optional target_user_option, and from data_set value option fields when filled.

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. Each command and interaction handler gets a moduleName derived from meta.name (for data paths and debugging). 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).