Documentation

Mallard is a Discord moderation bot with a built-in scripting engine: everything the bot does, from slash commands to event reactions to scheduled jobs, is a script you write and edit yourself in JavaScript, from the dashboard's own code editor. This page walks through how it works; the sections below hold the full API reference.

Overview

Out of the box, Mallard ships with moderation commands: warn, kick, ban (including temp bans), timeout, slowmode, unban, and per-user notes. Each one posts to a mod-log channel and keeps an audit trail. Beyond that, every piece of guild behavior (slash commands, reactions to Discord events, and scheduled/timed jobs) is authored as a "GuildScript": a snippet of JavaScript stored per guild and run through an embedded JS engine, rather than hardcoded per-guild logic in the bot itself.

Scripts are written and managed entirely from the dashboard, using a full code editor with autocomplete against the same API reference documented on this site. No hosting, no deploy step: saving a script takes effect immediately.

How it works

One process holds the Discord gateway connection and decides what should run; a pool of interchangeable runners does the running:

  1. A Discord gateway event (a message, a member joining, a reaction, …) or a slash command arrives at the bot.
  2. The bot looks up enabled scripts matching the guild and the trigger type, applies that script's filters, and checks the guild's hourly budgets. Anything admitted is written to a job queue. Because that decision is made once, by the single process that sees every event, the budget counting stays honest no matter which runner picks the job up.
  3. A runner claims the job, usually within milliseconds. Runners are anonymous and no guild belongs to any of them, but each guild has a small cap on how many of its own jobs may be in flight across the whole pool at once (it scales with tier), and jobs are claimed oldest-first within that cap. Two scripts in one server still can't race on the key-value store even when they do overlap: whichever reaches a key first holds it until it's done. Different guilds run concurrently.
  4. The script runs end-to-end through an embedded JavaScript engine (Jint). Every Discord action it calls (sending a message, banning a user, adding a role, …) and every key-value write happens live, in call order, the moment the script calls it. There's no all-or-nothing rollback: a script that errors partway keeps whatever actions and writes it already made.
  5. Once the script finishes (or errors, or times out), an execution record is saved with its status, duration, how long it waited to be claimed, and any error, viewable on the guild's Logs page.
Because there's no rollback, scripts that need to do something later (a temp ban's unban, a reminder, …) log that intent to the key-value store and pick it up from a Scheduled script that sweeps for it periodically, rather than "waiting." Every setKV call lands in the database the instant it's called, so writes already made survive a later error in the same run. See the KV store section .
A failed Discord action normally ends the script. The exception is a target that simply isn't reachable: a user who doesn't accept DMs, a member who already left, a message already deleted. Those aren't something your script can control, so sendDm, kick, timeout, unban and deleteMessage return false and your script keeps going. Everything else still stops it; full detail on Subsystems & limits .

Ready to try it?

Add Mallard to your server, then manage its commands and scripts from the dashboard.

Go to Dashboard
An unhandled error has occurred. Reload 🗙