README#
SideQuest Guild bot#
Game Master, the Discord bot for SideQuest, an Alliance guild on World of Warcraft: Forever. It posts guild events and takes sign-ups in Discord, hands out roles based on the website, awards chat levels and badges, and keeps the server tidy.
The bot never opens the database. It talks to the API in SideQuest-Guild/website with a shared key, and anything it remembers lives there.
What members see#
Events. Every guild event has a Discord event and a thread in the events forum. The thread has Going, Maybe and Can’t buttons. For a raid or dungeon the bot asks for your character, class and role the first time, then reuses them. Sign-ups made here and on the website are the same sign-up.
Roles from the website. Sign in on the website and you get Signed the Ledger. Link Battle.net and you get Battle-Tagged. When a Quest Master confirms you are in the guild in game, you get New Arrival and the guild channels open. Until you sign in you hold At the Gate and see only the sign-in channel.
A welcome DM when you first sign in, and a pinned Start here button in
#guest-chatthat shows it again.Chat levels. Each message earns 15 to 25 XP, at most once a minute. Level roles from Lv 5 · Wayfarer to Lv 50 · Legend come on their own.
Badges. Earn one on the Hall of Heroes and the bot gives you its role and says so in chat.
Away on a Quest. Mark away dates on the website and you hold this role for those days.
The weekly board. Every Monday at 10:00 Central the bot posts the week’s events in one message. A week with no events gets no message.
WoW: Forever news. Every five minutes the bot checks Blizzard’s own forum posts about WoW: Forever and Wowhead’s WoW: Forever news, and posts each new one in the feed channel with a link to the full post.
Class halls. Pick a class in
#choose-your-classand you join that class’s post in#class-halls.Commands for everyone:
/rank [member]shows a level and/leaderboardshows the top of the server.
Commands for officers#
Discord hides each command from anyone without the permission listed. Server admins can change who sees what under Server Settings, Integrations. Settings are saved in the API and apply at once.
Command |
Needs |
What it does |
|---|---|---|
|
Manage Server |
Picks the forum for event threads. |
|
Manage Server |
Picks the weekly board’s channel, or shows you this week’s board. |
|
Manage Server |
Picks where badges are announced, or checks for new badges now. |
|
Manage Server |
Picks where announcements from the game and the website are posted. |
|
Manage Server |
Picks where WoW: Forever news from Blizzard and Wowhead is posted. A new channel gets the latest three first. |
|
Manage Server |
Picks where new sign-ins are posted, each with an Approve button for Quest Masters. |
|
Manage Server |
Posts and pins the Start here button. |
|
Manage Server |
Picks the four roles that come from the website. |
|
Manage Server |
Picks the away role. |
|
Manage Server |
The welcome message in |
|
Manage Server |
Where edits, deletes, joins, leaves, role changes and voice moves are logged. |
|
Manage Server |
Level rewards, XP range, cooldown, level-up messages, and channels or roles that earn no XP. |
|
Manage Roles |
Button panels that let members pick their own roles. |
|
Timeout Members |
Each one DMs the member, opens a numbered case and logs it. |
|
Kick Members |
As above. |
|
Ban Members |
As above. |
|
Timeout Members |
Look up or explain past cases. |
|
Manage Server |
Deletes invite links, and times people out for mention spam or floods. |
Nobody can moderate the server owner, the bot, themselves, or someone whose top role is at or above their own.
The bot only hands out a role if it sits below the bot’s own role, has no moderator or admin powers, and isn’t managed by another app. It checks this before every grant, so a role that later gains powers stops being handed out. Whoever sets up a role needs Manage Roles and a higher role than the one they pick.
Run it on your computer#
You need uv, a bot token from the Discord Developer Portal (Game Master, then Bot), and the website’s API running on your computer (see the website README).
In the Developer Portal, turn on the Server Members and Message Content intents. In the server, give the bot Manage Events, and for the events forum also Manage Channels, Send Messages in Threads and Create Posts.
Put these in a .env file or in your shell:
DISCORD_TOKEN=... # from the Developer Portal
API_KEY=... # the same value as the website's API_KEY
API_URL=http://localhost:8000
WEB_BASE_URL=http://localhost:8000 # used in links the bot posts
DISCORD_GUILD_ID=... # optional: your test server, so commands show up at once
Then:
make install
make bot
Before you push#
make ci runs every check GitHub runs: formatting, lint, type checks and the tests. make fmt fixes formatting. The
tests start the real website API inside the test run, so they catch a change in what the API sends back. Type checks
fail only on new errors. Known ones are listed in pyrefly-baseline.json, and make type-baseline updates it after
you fix some.
Each feature is one file in src/sidequest_bot/plugins/. The role icons are in src/sidequest_bot/assets/role_icons/.
When the website changes#
The bot gets the API’s request and reply shapes from the website’s sidequest-common package. It isn’t on PyPI, so
pyproject.toml pins it to one commit of the website repo:
[tool.uv.sources]
sidequest-common = { git = "https://github.com/SideQuest-Guild/website", rev = "<sha>", subdirectory = "packages/sidequest-common" }
sidequest-api = { git = "https://github.com/SideQuest-Guild/website", rev = "<sha>", subdirectory = "api" }
To move to a newer website commit, put its SHA in both rev fields, run uv lock, then make ci.
Deploy the website first when the bot needs a new route. A bot that calls a route the live API doesn’t have yet gets “not found” until the website catches up.
Deploying#
Push to main. Cabotage builds the Dockerfile and runs the one process in the Procfile, worker: sidequest-bot.
It serves no web traffic.
Run exactly one worker. Two bots on the same token would both answer every button and post everything twice.
Live settings: DISCORD_TOKEN, API_KEY, API_URL=https://sidequest-guild.com,
WEB_BASE_URL=https://sidequest-guild.com, and DISCORD_GUILD_ID if you want commands to update at once.