Skip to content

About

AI-based Discord moderation bot

Resources

Stars

2 stars

Watchers

0 watching

Forks

Repository files navigation

Discord Moderation Bot

A Bun + TypeScript bot for Discord that uses AI to automatically moderate messages and remove spam or scam content from your server. It is built with Effect 4 (release candidate, pinned exactly): configuration, the moderation model and logging are services, model responses are schema-decoded rather than cast, and the moderation decision logic is a pure module (src/moderation.ts) covered by tests.

Features

  • Automatically monitors Discord channels for spam and scam messages
  • Scores every message with Cloudflare Workers AI's Clef model and extracts typed evidence (links, invites, handles, promised amounts) from flagged messages with Clairic
  • Considers previous channel messages for context when moderating
  • Can be configured to monitor specific channels or the entire server
  • Allows excluding users with specific roles from moderation
  • Automatically times out users who post spam/scam content (configurable duration)
  • Sends detailed notifications to a designated channel for moderation actions
  • Provides detailed logging of moderation activities
  • Runs as a systemd service on Ubuntu for 24/7 operation

Requirements

  • Bun 1.2 or higher
  • Discord Bot Token (with appropriate permissions)
  • Cloudflare account ID and an API token allowed to run Workers AI models
  • Ubuntu server (for systemd service setup)

Installation

  1. Clone this repository:

    git clone https://github.com/EkuboProtocol/discord-mod-bot.git
    cd discord-mod-bot
  2. Install dependencies:

    bun install
  3. Create a .env file based on the example:

    cp .env.example .env
    nano .env  # Edit with your actual credentials
  4. Configure your environment variables in the .env file:

    DISCORD_TOKEN=your_discord_bot_token
    DISCORD_SERVER_ID=your_server_id
    CLOUDFLARE_ACCOUNT_ID=your_cloudflare_account_id
    CLOUDFLARE_API_TOKEN=your_workers_ai_token
    # Add more configuration as needed
    

Usage

Running Manually

Start the bot directly with Bun:

bun run src/index.ts

TypeScript is executed as-is; there is no build step. To run the checks the way CI does:

bun run format:check
bun run lint
bun run typecheck
bun test

Startup validation

Before connecting to Discord, the bot asks Clef about one benign synthetic message using the configured account and token and the normal request. Startup requires a response that decodes within 30 seconds and scores the message as clean (p(spam) < 0.5). An API error, timeout, success: false, a response that does not decode, or a benign message scored as spam fails startup with exit code 1. This check never posts a Discord message or takes a moderation action. It incurs one normal API request per startup. Errors processing real messages still fail open.

After Discord emits clientReady, startup fetches the server's roles, channels, active threads, and the bot member to check effective permissions (including channel overwrites). It verifies bans, timeouts when enabled, moderation notices and context, report embeds, and the report button's purge access across regular text channels. Invalid configured channels or missing permissions fail startup with an actionable error before moderation handlers are enabled. This check is read-only.

Role hierarchy limitations are logged for non-excluded roles at or above the bot. The server owner and administrators retain Discord's moderation protections; startup cannot guarantee actions against every member. Channel/role changes after startup and threads inaccessible to the bot still require operational attention.

Command Line Arguments

The bot supports the following command line arguments:

Options:
  -t, --token                Discord bot token                      [string]
  -s, --server               Discord server ID                      [string]
  -c, --channels             Comma-separated list of moderated channel IDs
                             (default: all)                         [string]
  -e, --excluded-roles       Comma-separated list of role IDs to exclude from
                             moderation                             [string]
  -x, --excluded-channels    Comma-separated list of channel IDs to exclude from
                             moderation                             [string]
  -w, --welcome-channel      Channel ID of the welcome channel to exclude from
                             moderation                             [string]
  -n, --notification-channel Channel ID to send notifications to    [string]
  --context-messages         Number of previous messages for context
                                                     [string] [default: "5"]
  -l, --log-level            Log level (error, warn, info, debug)
                                                    [string] [default: "info"]
  --cloudflare-account-id    Cloudflare account ID that runs the Workers AI
                             moderation models                      [string]
  --cloudflare-api-token     Cloudflare API token allowed to run Workers AI
                             models                                 [string]
  -h, --help                 Show help                             [boolean]

Example:

bun run src/index.ts --token=your_token --server=your_server_id --channels=channel1,channel2 --excluded-roles=role1,role2

Setting Up as a Systemd Service

  1. Copy the service file to systemd:

    sudo cp discord-mod-bot.service /etc/systemd/system/
  2. Edit the service file to match your environment:

    sudo nano /etc/systemd/system/discord-mod-bot.service
  3. Reload systemd, enable and start the service:

    sudo systemctl daemon-reload
    sudo systemctl enable discord-mod-bot
    sudo systemctl start discord-mod-bot
  4. Check the status:

    sudo systemctl status discord-mod-bot

Deploying to DigitalOcean App Platform

The repository includes a ready-to-use App Platform spec at .do/app.yaml that deploys the bot as a worker service.

  1. Install and authenticate doctl:
    doctl auth init
  2. Review .do/app.yaml and update the GitHub repo/branch or worker sizing if needed.
  3. Create the app:
    doctl apps create --spec .do/app.yaml

The live spec is the source of truth, not this file. deploy_on_push only rebuilds the source; it does not re-read .do/app.yaml. Changing the build or run command here has no effect until you run doctl apps update (below), so the two can silently drift apart. To edit the live spec safely, start from doctl apps spec get <APP_ID> — it round-trips the encrypted secret values, whereas applying this file as-is would clear them.

  1. After the app is created, add the required environment variables (Discord token, server ID, Cloudflare account ID and token, etc.) under Settings → Environment Variables or by updating the spec and running:
    doctl apps update <APP_ID> --spec .do/app.yaml

Environment Variables for App Platform

The spec lists the variables the worker expects:

  • DISCORD_TOKEN (secret) – Discord bot token
  • DISCORD_SERVER_ID – ID of the Discord server to moderate
  • CLOUDFLARE_ACCOUNT_ID – Cloudflare account that runs the Workers AI models
  • CLOUDFLARE_API_TOKEN (secret) – Cloudflare API token allowed to run Workers AI models
  • LOG_LEVEL – Logging verbosity (error, warn, info, debug)
  • CONTEXT_MESSAGE_COUNT – Number of prior messages to send for context
  • TIMEOUT_DURATION – Timeout duration in minutes (set 0 to disable)
  • MODERATED_CHANNELS, EXCLUDED_CHANNELS, EXCLUDED_ROLES, WELCOME_CHANNEL_ID, NOTIFICATION_CHANNEL_ID, IGNORED_PHRASES – Optional fine-tuning values; leave blank to use defaults

Remember to keep secret values (Discord and Cloudflare tokens) stored as Secret scope variables in App Platform so they are not committed to the repository.

Configuration

The bot can be configured using environment variables or command line arguments. A command line argument takes precedence over the matching environment variable, which in turn takes precedence over the built-in default. Every setting has exactly one environment variable name and, where useful, one flag that sets the same thing; --help lists both.

Note: LOG_LEVEL and CONTEXT_MESSAGE_COUNT previously had no effect, because the corresponding flags always carried a default value and so always won. They are honoured now.

If a required setting is missing, the bot names it at startup along with both ways to supply it, rather than reporting a bare stack trace.

Environment Variables

  • DISCORD_TOKEN: Your Discord bot token
  • DISCORD_SERVER_ID: The ID of your Discord server
  • MODERATED_CHANNELS: Comma-separated list of channel IDs to moderate (leave empty to moderate all)
  • EXCLUDED_CHANNELS: Comma-separated list of channel IDs to exclude from moderation
  • WELCOME_CHANNEL_ID: Channel ID of the welcome channel to exclude from moderation (automated messages)
  • EXCLUDED_ROLES: Comma-separated list of role IDs to exclude from moderation
  • TIMEOUT_DURATION: Duration in minutes to timeout users when their message is deleted (default: 5, set to 0 to disable)
  • CLOUDFLARE_ACCOUNT_ID: Cloudflare account that runs the Workers AI models
  • CLOUDFLARE_API_TOKEN: Cloudflare API token allowed to run Workers AI models
  • IGNORED_PHRASES: Comma-separated list of phrases to ignore (never sent to the moderation model)
  • NOTIFICATION_CHANNEL_ID: Channel ID to send detailed moderation notifications
  • CONTEXT_MESSAGE_COUNT: Number of previous messages to include for context (default: 5)
  • LOG_LEVEL: Logging level (error, warn, info, debug)

Logging

Logs are stored in the logs directory:

  • logs/combined.log: Contains all log messages
  • logs/error.log: Contains only error messages

How a message is judged

Each moderated message, with the previous CONTEXT_MESSAGE_COUNT messages for context, goes to Clef with two questions: the probability that it is spam or a scam, and its severity (high, medium, low or none). The thresholds are constants in src/moderation.ts, changed by a release:

  • p(spam) < 0.8: no action.
  • high with p(high) ≥ 0.6: ban (timeout if the ban fails). high below that degrades to medium.
  • medium: delete and time out for TIMEOUT_DURATION.
  • low, or none despite p(spam) ≥ 0.8: delete only.

Only a message that will be acted on is sent to Clairic, which extracts typed evidence: Discord invites, links, off-platform handles, promised amounts, profit cuts, impersonated parties and requests to DM. A field is used only when Clairic returns a value and its confidence clears a floor; invites and links are also found by deterministic checks that undo common obfuscation.

The reason is a template, e.g. High-severity spam/scam (p=0.97): promises $5,000; asks for 20% of profits; directs to Telegram. The public notice never repeats a link, invite code or handle; the moderator report shows the typed evidence and the model's scores.

If Workers AI fails, times out, or returns something that does not decode, the message is treated as clean. If Clairic alone fails, the action still happens, with less evidence.

Moderation Rules

The severity criteria cover:

  1. Messages containing suspicious links or asking users to open tickets
  2. Messages asking users to DM for support instead of using public channels
  3. Generic job-seeking messages that appear to be copy-pasted
  4. Messages asking who to contact for unspecified business/partnerships
  5. Messages promising rewards, giveaways, or airdrops that seem suspicious
  6. Impersonation of staff or team members
  7. Phishing attempts asking for personal information or wallet addresses

Discord Integration Options

There are several ways to integrate this bot with Discord:

1. Standard Bot User (Default)

This is the most common method where you create a bot application in the Discord Developer Portal and add it to your server. This approach:

  • Requires a separate bot user in your server
  • Needs specific permissions to read/delete messages
  • Is easy to set up through the Discord Developer Portal

2. Discord Interactions and Webhooks

For more advanced integrations with fewer permissions, you could modify this code to use:

  • Discord Webhooks: For sending notifications without a full bot
  • Discord Interactions: For slash commands (would require additional development)

3. User Account Token (Not Recommended)

While technically possible to use a user account token instead of a bot token, this approach:

  • Violates Discord's Terms of Service
  • Can result in account termination
  • Is not supported by this code

4. Discord Bot Framework Integration

If you already have a bot for your server, you could integrate this moderation code as a module in your existing bot framework to avoid adding another bot user to your server.

Troubleshooting

  • Bot not starting: Check the logs for error messages
  • Bot not detecting messages: Make sure the bot has the required permissions in Discord
  • Workers AI errors: Verify the account ID and that the token can run Workers AI models
  • Bot not running after system restart: Make sure the systemd service is enabled
  • Context not being considered: Ensure the bot has permissions to read message history

License

MIT

About

AI-based Discord moderation bot

Resources

Stars

2 stars

Watchers

0 watching

Forks

Contributors

Languages