Triggered is a Discord bot that you can configure to take an input action (like a message being sent with certain text, or a member joining a certain voice channel) and perform output actions (like sending a DM with information on what happened). I have tried to make this bot extensible (so it's very easy to add your own input and output actions).
Invite the hosted bot · Author
The invite is just my personal instance (not fully hosted yet). If you actually need this to stay up, self-host it.
Alright, let's get started!
You need:
- Python 3.10+
- MongoDB running locally (please don't use Atlas — this bot talks to the database a lot :D)
- A Discord bot with the privileged intents turned on: Server Members, Message Content, and Presence
- Go to Discord's developer website and create a bot. Official tutorial
- Enable those intents, copy the token.
- Invite the bot with
applications.commandsplus send messages / embed links / add reactions. Manage roles, move members, kick, timeout, and ban are only needed if you actually use those dos. - Clone this repo:
git clone https://github.com/quantumbagel/Triggered.git
cd Triggered
git checkout main
python3 -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e .- Copy
configuration/config.example.jsontoconfiguration/config.jsonand fill in your token, owner ID, and Mongo URI (mongodb://localhost:27017is the default). Don't commit that file, it's gitignored for a reason. - Start MongoDB, then
python bot.py. - In a server the bot can see, send
triggered/syncas the owner. After that,/triggeredshould show up.
Please open an issue if you're having any trouble setting this up.
Everything lives in configuration/config.json. You can also override keys with TRIGGERED_* env vars (that's what Docker does).
| Key | What it is |
|---|---|
bot_secret |
Bot token |
mongodb_uri |
Mongo connection string |
owner_id |
Your Discord user ID (triggered/sync etc) |
max_dos_per_trigger |
Cap on dos per trigger (default 3) |
argument_length_limit |
Max length for names/text (default 128) |
allowed_execution |
leftover, unused |
configuration/requirements.json is not server config. It tells the bot which trigger/do classes to load (contains-text → actions/triggers/contains_text.py unless you set "module").
A trigger is "when X happens". A do is "then do Y". Only the person who made the trigger (or the server owner) can add/delete dos or delete the trigger.
Slash commands don't work in DMs. Autocomplete only shows 25 things at a time — type more to narrow it down.
NB: [] = required, {} = optional
| Command | What it does |
|---|---|
/triggered new [name] [trigger] {description} {trigger_*} |
Make a trigger. Type in trigger to search types. Extra args depend on the type (trigger_text, trigger_role, trigger_member, trigger_emoji, trigger_vc, trigger_channel, …). Durations are 60s / 5m / 1h / 1d (or just seconds). |
/triggered add [trigger_name] [do] [do_name] {description} {do_*} |
Attach a do. Same deal with extra args (do_channel, do_member, do_role, do_emoji, do_text, do_vc, …). |
/triggered delete [to_delete] [trigger_name] {do_name} |
Delete a trigger (and its dos) or one do. |
/triggered view [mode] {query} |
List all, View one by name, or Search by name / author / type. |
/triggered server-configure |
Server permission settings. Needs Discord Administrator. |
/triggered user-configure |
Your personal white/blacklist of other people. |
/triggered about |
About the project. This one works in DMs. |
These only work if your Discord ID matches owner_id.
| Message | What it does |
|---|---|
triggered/sync |
Sync slash commands globally |
triggered/sync this |
Sync to this server |
triggered/sync <guild_id> |
Sync to that server |
triggered/disable |
Stop handling commands without killing the process |
triggered/enable |
Turn them back on |
triggered/toggle |
Flip it |
triggered/emoji-upload |
Upload missing custom emojis from assets/emoji |
| Name | ID | Fires on | Argument |
|---|---|---|---|
| Contains Text | contains-text |
message sent | trigger_text (substring) |
| Contains Word | contains-word |
message sent | trigger_text (whole word) |
| Role Mentioned | role-mentioned |
message sent | trigger_role |
| User Mentioned | user-mentioned |
message sent | trigger_member |
| Sent By | sent-by |
message sent | trigger_member |
| In Channel | in-channel |
message sent | trigger_channel |
| Has Attachment | has-attachment |
message sent | none |
| Everyone Mentioned | everyone-mentioned |
message sent | none (@everyone / @here) |
| Starts With | starts-with |
message sent | trigger_text (prefix) |
| Message Edited | message-edited |
message edited | optional trigger_channel |
| Message Deleted | message-deleted |
message deleted | optional trigger_channel |
| Reaction Added | reaction-added |
reaction added | trigger_emoji |
| Reaction Removed | reaction-removed |
reaction removed | trigger_emoji |
| Joined VC Channel | join-vc |
join voice | trigger_vc |
| Left VC Channel | left-vc |
leave voice | trigger_vc |
| Role Added | role-added |
gained a role | trigger_role |
| Role Removed | role-removed |
lost a role | trigger_role |
| Nickname Changed | nickname-changed |
nick changed | none |
| Member Boosted | member-boosted |
boosted the server | none |
| Member Joined | member-joined |
joined the server | none |
| Member Left | member-left |
left the server | none |
| Scheduled | scheduled |
timer | trigger_text like 5m (min 15s) |
| Name | ID | Argument | What it does |
|---|---|---|---|
| Send Message | send-message |
do_channel |
Posts a "this rule fired" panel in that channel |
| Send DM | send-dm |
do_member |
Same panel, but as a DM |
| Send Text | send-text |
do_channel, do_text |
Posts your text in that channel |
| Reply | reply |
do_text |
Replies to the message (send/edit triggers only) |
| Add Reaction | add-reaction |
do_emoji |
Reacts to the message (send/edit only) |
| Delete Message | delete-message |
none | Deletes the message (send/edit only) |
| Add Role | add-role |
do_role |
Gives that role to whoever fired it |
| Remove Role | remove-role |
do_role |
Takes that role away |
| Move to VC | move-to-vc |
do_vc |
Moves them into that VC (they have to already be in voice) |
| Kick Member | kick-member |
none | Kicks them |
| Timeout Member | timeout-member |
do_text |
Times them out (10m, max 28d) |
| Ban Member | ban-member |
none | Bans them |
Bots never fire triggers. If a do targets someone, their user-configure lists get checked first.
add-role / remove-role need Manage Roles, and the bot's role has to sit above the role you're giving/taking. add-reaction needs Add Reactions. move-to-vc needs Move Members. Kick / timeout / ban need the matching Discord permissions, and they skip the server owner and the bot itself.
Scheduled triggers wait one interval after you create them before they fire the first time. Message-deleted only works if Discord still had the message cached.
If a Required Role is set (/triggered server-configure), you need that role to use commands. If it isn't, your highest role has to sit above the bot's (the server owner can always use it).
Admins can white/blacklist channels and roles for triggers and dos separately. They start as blacklists (everything allowed except listed stuff). Hit Switch Whitelist/Blacklist to flip them.
/triggered user-configure is whether other people can write rules that target you. Those default to whitelist, so nobody can target you until you add them.
The bot loads everything in configuration/requirements.json.
- Subclass
actions.triggers.trigger.Triggeroractions.dos.do.Do. - Implement
dropdown_name(),human(), andis_valid()(triggers) orexecute()(dos). - Drop the file in
actions/triggers/oractions/dos/, named after the ID (contains-text→contains_text.py). - Register it in
configuration/requirements.jsonwith an ID,classname,type(triggers only), andparams.
Trigger type has to be one of: send_msg, vc_join, vc_leave, reaction_add, reaction_remove, member_join, member_leave, message_edit, message_delete, role_add, role_remove, nickname_change, member_boost, scheduled.
Open a pull request if you want it in the public bot. Your contribution is appreciated!
Copy .env.example to .env, put your token and owner ID in it, then:
docker compose up --buildThat starts Mongo and the bot. Env vars from Compose override the example config inside the image.
If you'd rather use a local configuration/config.json, mount it onto /app/configuration/config.json. Env vars still win if they're set.
pip install -e ".[dev]"
pytest