BSGO Admin Bot

๐Ÿ“– Help

Every bot module documented in one place. Each entry has the overview, setup steps, slash commands, and tips. Tap any card to expand. Per-guild settings live on each module's dashboard page โ€” sign in and pick a server to manage them.

Anti-nuke

Wick-equivalent: trip wires for bulk channel/role deletes + magic-link unfreeze.

Listens for bulk admin actions (channel deletes, role deletes, mass bans). If an actor exceeds the threshold within the time window, the bot strips their dangerous roles, freezes the guild's admin tier, takes a snapshot, and DMs the owner a single-use **magic link** to unfreeze. Fastest practical kill-switch for hostile-takeover scenarios.

Setup

  1. Visit Anti-nuke โ†’ Config. Verify thresholds (defaults are conservative).
  2. Make sure the bot's role is above the roles it needs to strip.
  3. Confirm `SNAPSHOT_KEY` is set in the .env (snapshot blobs are AES-GCM encrypted).

Workflows

What happens during a freeze

Bot strips Manage-* perms from the actor โ†’ freezes the guild (blocks new admin actions for the freeze duration) โ†’ takes a snapshot โ†’ DMs the owner with the magic link. Owner clicks link, confirms, freeze lifts.

Manual freeze

Anti-nuke โ†’ Config โ†’ Freeze. Same effect as the auto-trigger but driven by you.

Slash commands

CommandWhat it does
/antinuke status Show current state + freeze status.
/antinuke freeze Manually freeze the guild.
/antinuke unfreeze Manually clear a freeze (also via magic link).

Tips

  • Take periodic snapshots (Backups โ†’ Take). They're the rollback for a real nuke.
  • Add a few trusted admins above the bot's role so they bypass the trip wires.

Troubleshooting

Auto-freeze didn't fire on a real attack
Check audit-log lookup window (default 5s). Actions outside it can't be attributed to an actor; we fail open. Tune via the config.
Lost the magic link DM
Owner can also `/antinuke unfreeze` directly in Discord. Or trigger another DM from the dashboard's Anti-nuke page.

Anti-raid

Account-age + no-pfp gates, panic mode, join-rate spike auto-trigger.

Each `on_member_join` runs through gates in order: account age < min_days โ†’ kick; no profile picture (if required) โ†’ kick; panic mode active โ†’ kick. Join-rate spike (configurable) auto-activates panic mode.

Setup

  1. Anti-raid โ†’ Config form. Sane defaults: 7-day min age, 10 joins/60s spike threshold.

Slash commands

CommandWhat it does
/antiraid status Current state + active panic.
/antiraid panic on duration_min:30 Manual panic mode.
/antiraid config Slash-form alternative to dashboard.

Automod

Regex / spam-rate / invite / link / badword / toxicity rule chains with heat scoring.

Per-message scan against enabled rules. Each rule has a chain of actions (delete + warn points + mute seconds). A per-user **heat score** (Redis ZSET, decays linearly) tracks repeat offenders and lets you scale severity adaptively.

Setup

  1. Automod โ†’ + New rule. Pick a type and pattern.
  2. (Optional, toxicity only) Automod โ†’ OpenAI key โ€” paste an `sk-...` key to enable AI moderation.
  3. Add rules incrementally. The heat-score per-user surfaces in the Top heat scores table.

Workflows

Block invite links

+ New rule โ†’ type: `invite`, pattern: empty, action chain: delete + warn 1pt. Done. Built-in regex matches discord.gg / discord.com/invite.

Block specific bad words

Type: `badword`, pattern: comma-separated list (e.g. `slur1,slur2,scamword`). Match is case-insensitive substring.

Spam rate

Type: `spam_rate`, pattern: `{"count":5,"window_s":4}`. 5 messages in 4 seconds โ†’ action chain fires.

Toxicity (BYO OpenAI key)

Type: `toxicity`. Pattern empty = match anything OpenAI flags. Optional: `{"categories":["harassment"],"threshold":0.8}` to filter to one category.

Slash commands

CommandWhat it does
/automod rule-add Quick add via slash.
/automod rule-list Inline list.
/automod heat @user Show their current decayed score.
/automod openai-key Set/clear the per-guild key for the toxicity rule.

Tips

  • Start with a few rules; expand as patterns emerge in mod-log.
  • Heat-score adaptive escalation: build rules that trigger only above a heat threshold.

Troubleshooting

Toxicity rule never matches
Check OpenAI key is configured (Automod page shows a green pill if so) and that you have an OpenAI account in good standing.
Spam rate over-triggers
Tune count/window_s upward, or use exempt_roles to skip moderators.

Backups

Snapshot + restore the guild's channel/role structure.

Take periodic snapshots (zstd JSON + AES-GCM if SNAPSHOT_KEY set). Restore wizard diffs the snapshot against the live guild and applies create/update ops. Default safe (no auto-deletes).

Setup

  1. Backups โ†’ Take snapshot. Recommended: take one before risky restructures.

Slash commands

CommandWhat it does
/backup take / list / info / export / delete Slash equivalents.

Branding

Per-guild bot nickname + dashboard accent color.

Discord allows per-guild nickname (and only nickname โ€” not avatar or status). Dashboard accent color repaints the chrome on this guild's pages.

Setup

  1. Branding โ†’ set nickname + theme color.

Slash commands

CommandWhat it does
/branding nickname/theme/show/clear Slash equivalents.

Custom commands

User-defined commands rendered via TagScript. Carl-bot-equivalent.

Members type `<prefix><name>` (default `!cmdname`) and the bot replies with the rendered template. Useful for FAQs, quick references, or running gags. TagScript is sandboxed โ€” 50ms render cap, 4KB output cap, no I/O.

Setup

  1. Custom commands โ†’ tweak the prefix if `!` clashes with another bot.
  2. + New command โ†’ name + body. Live preview validates as you type.

Workflows

Create a simple FAQ command

+ New command โ†’ name: `rules`, body: `Read <#channel-id>! Be excellent.` Save. Now `!rules` in any channel renders that text.

Use TagScript variables

Body: `Hello {user.mention}, you're #{member_count} in {guild.name}!`. Renders dynamically per caller.

Slash commands

CommandWhat it does
/cmd add name:_ body:_ Slash equivalent of the dashboard New form.
/cmd run name:_ Trigger by name when the prefix is unclear.
/cmd list List all commands.
/cmd prefix prefix:_ Change the prefix.

Tips

  • 200-command cap per guild. Plenty for FAQs.
  • Permissions editor (role/channel restrict) is slash-only for now: `/cmd permissions`.

Troubleshooting

Commands don't trigger from chat
1) Confirm Message Content Intent is on. 2) Confirm the prefix is what you think it is (Custom commands โ†’ Prefix field shows current value).
Command output is empty
TagScript errored โ€” switch the command to a simpler body and re-build up. Live preview catches most errors.

Embed builder

Saved embed library with dual-pane editor + send-to-channel.

Build embeds with a form (title/desc/color/image/fields), see a live Discord-shaped preview, save by name, send to any channel.

Setup

  1. Embeds โ†’ + New embed. Live preview updates 200ms after each keystroke.

Slash commands

CommandWhat it does
/embed save / send / list / view Slash equivalents.

Giveaways

Timed prize draws with a persistent Enter button.

Create a giveaway โ†’ bot posts an embed with an Enter button โ†’ at deadline, picks N random winners + edits embed + DMs winners.

Setup

  1. Giveaways โ†’ Start a giveaway. Pick prize + duration + winners + channel.

Slash commands

CommandWhat it does
/giveaway start prize:_ duration:_ winners:_ Inline create.
/giveaway end <id> End now.
/giveaway reroll <id> Pick new winners from same entries.

Leveling

Mee6-compatible XP per message + role rewards on level-up.

Every non-bot message earns 15-25 XP (configurable) once the user clears the 60s anti-spam cooldown. Level curve is the standard Mee6 shape: 5Lยฒ+50L+100 per level. Hitting a configured **reward** level grants the matching role automatically via roles.service.grant_role.

Setup

  1. Leveling โ†’ Config. Toggle Enabled, optionally tweak XP min/max + cooldown.
  2. Pick an announce channel (empty = post in the user's own channel).
  3. Add level rewards in the Rewards table (level + role picker).

Workflows

Tune XP rate

Leveling โ†’ Config โ†’ XP min / max. 15-25 is the Mee6 default and works for most communities. Lower for very chatty servers.

Reset a user's XP

Leveling โ†’ Leaderboard โ†’ Reset row. Deletes their XP row; they start at level 0.

Hide certain channels from XP

Leveling โ†’ Config โ†’ Ignore channels. Members chatting there earn nothing.

Slash commands

CommandWhat it does
/level get [@user] Show level + XP + progress bar.
/level top Top 10 leaderboard.
/level opt-out / opt-in Member-side toggle to stop earning XP.

Tips

  • Level rewards should be additive โ€” don't remove lower-level roles automatically.
  • Combine with Roles โ†’ Autoroles for a 'verified at level 5' badge.

Troubleshooting

Members aren't earning XP
1) Confirm Enabled. 2) Confirm Message Content Intent is on in the Dev Portal. 3) Check the channel isn't in the ignore list. 4) Check the user isn't opted out.

Logging

80+ event types routed to per-category log channels with live tail + search.

On every meaningful event (message edit/delete, role change, member join, etc.) the bot writes a row to `event_logs` (partitioned monthly) and posts to the configured channel for that category. Message content is encrypted at rest.

Setup

  1. Run `/nabsetup`. Or Logging โ†’ Settings โ†’ set per-category channels.

Slash commands

CommandWhat it does
(no top-level slash) Configured via the dashboard.

Tips

  • Search past events at Logging โ†’ Search. Live tail at Logging โ†’ Live tail.

Moderation

Cases, escalation rules, modlog. The audited path for mod actions.

Every privileged action (warn, mute, kick, ban) creates a numbered **case** with a hash-chained audit row. Cases mirror to the modlog channel as embeds. Each rule in the **escalation** ladder watches a user's infraction points and auto-applies a follow-up action when the threshold is crossed (3 warns โ†’ mute, 5 warns โ†’ tempban, etc).

Setup

  1. Run `/nabsetup` once โ€” wires `#mod-log` automatically.
  2. Or visit Moderation โ†’ Settings, paste a channel ID into Modlog channel, set Mute role.
  3. Add escalation rules under Moderation โ†’ Escalation (optional but powerful).

Workflows

Issue a warning

In Discord: `/warn @user reason:_`. The case lands in #mod-log, the user is DMed, and the audit chain extends. From the dashboard: Moderation โ†’ Cases โ†’ no add-case form yet (slash is the entry point).

Edit a case reason

Cases page โ†’ click a case # โ†’ Edit reason. The audit chain logs the edit; previous text is preserved in the audit `before` field.

Configure escalation

Moderation โ†’ Escalation. Add a rule (action, threshold, mute duration, etc). Subsequent warns count toward each user's points; once a threshold is hit, the auto-action fires immediately as a normal case.

Slash commands

CommandWhat it does
/warn @user reason:_ Add a warning. Increments infraction points.
/mute @user duration:30m reason:_ Native timeout โ‰ค28d, role fallback above.
/kick @user reason:_ Kick + audit + DM.
/ban @user reason:_ Permanent ban.
/tempban @user duration:7d reason:_ Auto-revoke at expiry.
/case <number> Show a case + its audit trail.
/history @user All cases for a member.
/reason <case> new:_ Update a case's reason.

Tips

  • Run `/nabsetup` first โ€” it wires the mod-log channel automatically.
  • Cases are immutable history; edits are tracked, never overwritten.

Troubleshooting

Mute over 28 days didn't work
Discord native timeouts cap at 28d; set a Mute role in settings as the >28d fallback.
User wasn't DMed
They likely have DMs from server members disabled. The case still lands in #mod-log.

Polls

Button or select-menu votes with auto-close at deadline.

โ‰ค5 options renders as buttons; 6+ renders a single select menu. Votes are stored per-user; tally is read-time GROUP BY.

Setup

  1. Polls โ†’ Create a poll. Provide question + comma-separated options.

Slash commands

CommandWhat it does
/poll create question:_ options:_ multi:bool duration:_ Inline create.

Roles

Reaction / button / select / verify panels + autoroles.

Four panel kinds. **Reaction**: members react with an emoji to claim a role. **Button**: click toggles. **Select**: pick from a dropdown. **Verify**: a single click grants a role + any on-event=verify autoroles. Autoroles fire on `join` or `verify`.

Setup

  1. Roles โ†’ + Create panel. Pick kind + channel + title. Then click into the panel to add mappings.

Slash commands

CommandWhat it does
/roles panel-create kind:_ title:_ Slash create.
/roles autorole-add role:@ event:join Auto-grant on join.

Scheduled messages

Recurring messages on a 5-field cron.

One row per schedule. Worker fires due rows every 60s; payload is rendered through TagScript.

Setup

  1. Scheduled msgs โ†’ Add schedule. Cron + channel + payload.

Slash commands

CommandWhat it does
/schedule add cron:_ channel:_ template:_ Inline create.

Tips

  • Daily 9am UTC = `0 9 * * *`. Hourly = `0 * * * *`. Test with a 5-min cron first.

Server stats

Voice-channel vanity counters that auto-update every 30s.

Pick a voice channel โ†’ pick a kind (members, online, boosters, humans, bots) โ†’ write a template like `Members: {count}`. The 30s worker renames the channel.

Setup

  1. Server stats โ†’ Add a counter.

Slash commands

CommandWhat it does
/stats counter add channel:_ kind:_ template:_ Inline create.

Suggestions

Community ideas with status workflow (pending โ†’ approved/declined/implemented).

Members `/suggestion submit` โ†’ bot posts in #suggestions with โฌ†๏ธ/โฌ‡๏ธ + auto-thread. Admins flip status from the dashboard.

Setup

  1. Run `/nabsetup` for #suggestions. Or Suggestions โ†’ set channel.

Slash commands

CommandWhat it does
/suggestion submit content:_ Submit (members).
/suggestion approve/decline/implement <id> Decision (admins).

Tickets

Modal-driven ticket panels with HTML transcripts on close.

An admin posts a **panel** (an embed with a button) in any channel. When a member clicks it, a modal asks pre-configured questions; answers + a private channel are created. On close, the bot generates a self-contained HTML transcript (avatars, timestamps, attachments) and uploads it to the configured log channel before deleting the channel.

Setup

  1. Run `/nabsetup` once โ€” wires `#ticket-transcripts`.
  2. Tickets โ†’ + Create panel. Pick where the panel posts; the bot creates the message.
  3. Set the transcript channel on the panel (defaults to #ticket-transcripts if you ran /nabsetup).

Workflows

Open a ticket (member)

Click the button on the panel. Fill the modal. A new private channel appears with you, mods, and the bot.

Claim a ticket (mod)

From the ticket channel: `/ticket claim`. Or from the dashboard: Tickets โ†’ row โ†’ Claim.

Close + transcript

Tickets โ†’ row โ†’ Close. Bot generates HTML, uploads to transcript channel, deletes the channel.

Slash commands

CommandWhat it does
/ticket panel-create Create a panel from inside the target channel.
/ticket claim Claim the current ticket channel.
/ticket close Close + transcript.

Tips

  • Set a Tickets category on the panel so new ticket channels get organized.
  • Up to 5 questions per panel โ€” keep them short; the modal has tight character caps.

Troubleshooting

Panel button doesn't work after restart
Persistent views are re-registered on cog_load by message_id. If the panel's DB row exists but the message was deleted, the bot can't find it. Recreate the panel.
Transcript HTML upload failed
Check the bot has Send Files permission in the transcript channel. The channel is still deleted โ€” the transcript is just lost. Increase staff's manual chat-log fallback if this is critical.

Watchlist

Flag user IDs; mods get an embed in #mod-log when they join or leave.

Add a Discord user ID to the watchlist. The bot listens for `on_member_join` and `on_member_remove` and, if the user is on the list, posts an alert embed (avatar, account age, watch note) to the configured `modlog_channel_id`. Useful for ban evaders, repeat offenders from other servers, or just "keep an eye on " cases.

Setup

  1. Run `/nabsetup` (wires the modlog channel) or set Moderation โ†’ Settings โ†’ Modlog channel.
  2. Watchlist โ†’ add user IDs (or `/watchlist add @user note:_`).

Slash commands

CommandWhat it does
/watchlist add @user [note:_] Flag an in-guild user via mention.
/watchlist add-id user_id:_ [note:_] Flag by raw Discord ID โ€” works even if the user is NOT in the guild yet (typical ban-evader case).
/watchlist remove @user Stop watching them via mention.
/watchlist remove-id user_id:_ Stop watching by ID.
/watchlist list Show all watched users.

Tips

  • Enable Developer Mode in Discord โ†’ right-click avatar โ†’ Copy User ID.
  • Add a note explaining *why* you're watching โ€” future-you (or another mod) will appreciate context.
  • Alerts respect the modlog channel's existing permissions, so non-staff never see the embed.

Welcome

Join/leave embeds + DM + autorole, all TagScript-rendered.

Three optional templates: join_msg (posted in the welcome channel), leave_msg (posted in the same channel on leave), dm_msg (DM'd to the joiner). All three support TagScript โ€” `{user.mention}`, `{user.name}`, `{guild.name}`, `{member_count}`. Live preview shows you the rendered output as you type.

Setup

  1. Run `/nabsetup` โ€” wires `#welcome` and enables the module.
  2. Welcome โ†’ fill in templates. Save.
  3. Optional: pick an autorole to grant on join.

Workflows

Edit the join message

Type into the Join message textarea. The preview updates 250ms after you stop typing. Save when happy.

Test a template

From Discord: `/welcome test`. Renders the template against you and posts it.

Slash commands

CommandWhat it does
/welcome config Slash equivalent of the dashboard form.
/welcome test Render the template against the caller.

Tips

  • Image cards (Pillow-rendered) are deferred to v1.1; for now stick with embeds.
  • Combine with Roles โ†’ Autoroles for richer onboarding (verify gate, etc).

Troubleshooting

DM didn't arrive
Discord auto-blocks DMs from members of servers when 'Allow DMs from server members' is off. The join + leave channel posts still work.
TagScript syntax error
Check the live preview โ€” errors show inline as <em>. Common gotchas: missing closing brace, unknown variable name.