Bot Architecture
This page is hidden behind SLKARDS' spoiler gate. There's a way to unlock it. If you know the way, use it — otherwise, keep exploring the game.
Bot Architecture
This document outlines how SLKARDS is structured within a Discord server — channel organisation, permissions, thread lifecycle, command routing, and backend considerations. The goal is to keep the server clean and organised while the bot performs reliably at scale.
[REDACTED]
Section titled “[REDACTED]”- Python ≥ 3.12 with
discord.py2.4+ (slash-command andapp_commands.GroupAPIs). - MongoDB (via Motor, the async driver) for durable game state.
- redis.asyncio for ephemeral state — battles/spawns, cooldowns, leaderboard sorted sets, session locks.
- APScheduler with a dual jobstore (memory for short-lived jobs, Mongo for persistent ones like wipes).
- pydantic-settings (
config/settings.py) for environment-driven configuration. - structlog for structured JSON logging.
[REDACTED]
Section titled “[REDACTED]”A handful of shared collaborators live under bot/ and are injected through bot.slkards (SlkardsContext). Cogs never instantiate these directly:
bot/bus.py— process-local event bus + modifier resolver. Cogs publish domain events (prestige.completed,kard.captured,market.listing_sold, etc.) and subscribe to them for cross-cog fan-out (e.g.cogs/stats.pyupdatesplayer_statswhen prestige / Almighty / wipe /koins.earnedevents fire).bot/throttle.py— token-bucket rate-limit guardrails: per-channel, per-guild, global DM, and per-user secret-attempt buckets. Allnotifier.pyDMs and high-traffic posts go through this.bot/notifier.py— bounded DM queue (5000-message cap, drop-oldest back-pressure per SEC-012). Retries transient failures with exponential backoff up toMAX_RETRIES=2(3 total tries) and supports an optionalfallback_channelforForbidden/ retry-exhausted cases.bot/scheduler.py— APScheduler wrapper exposing both an in-memory jobstore for short-lived callbacks and a Mongo-backed jobstore for jobs that must survive a restart (wipe warnings, leaderboard refreshes).bot/context.py—SlkardsContextdataclass wiring the Mongo client, Redis client, bus, throttle, notifier, scheduler, and static registry. Bound to the bot asbot.slkards.bot/command_groups.py— the fourapp_commands.Groupsingletons (/slkards,/admin-slkards,/debug-slkards,/alliance-slkards). No other top-level groups are allowed. Cogs attach their commands to one of these four groups.
[REDACTED]
Section titled “[REDACTED]”main.py boots the bot, wires bot.slkards, connects Mongo + Redis, starts APScheduler, then auto-discovers cogs under cogs/ and loads them in topological order from each module’s DEPENDS_ON declaration.
cogs/_bootstrap.py is always loaded first and is non-reloadable. It:
- Applies all Mongo indexes (per
docs/Data Structuring.md). - Loads
StaticRegistryfrom disk (data/static_*.json,data/kardData.json,data/backrooms_almighty.json). - Runs the one-shot
isLocked$unsetmigration onplayer_binders(a 0.3.x cleanup that removed the abandonedisLockedfield from all binder instances).
Every other cog is reloadable via /debug-slkards reloadcog, which is the cornerstone of the no-downtime maintenance model.
[REDACTED]
Section titled “[REDACTED]”Events emitted by the current build (consumed by cogs/stats.py, cogs/wipes.py, and other subscribers):
| Event | Emitted by | Notes |
|---|---|---|
prestige.completed | cogs/prestige.py | Fans out per-series leaderboard updates + player_stats increments. |
almighty.unlocked | cogs/almighty.py | Triggers Almighty stat fan-out. |
wipe.executed | cogs/wipes.py | Drives logs_wipes writes + player_stats.wipes aggregates. |
admin_setup.completed | cogs/admin_setup.py | cogs/wipes.py listens to schedule the first wipe for a freshly configured guild. |
koins.earned / koins.spent | Economy paths (daily, packs, collector, marketplace) | Powers per-source breakdown in /slkards koins and stats fan-out. |
kard.captured | cogs/spawning.py, packs | Increments collection counters; emits logs_discoveries first-find writes. |
kard.traded | cogs/trading.py | Trade leg of player_stats.trades fan-out. |
market.listing_created, market.listing_sold, market.counter_offer_made, market.counter_offer_accepted | cogs/stores/marketplace.py | Marketplace lifecycle hooks; auction events are upcoming with the 0.3.5 auction flow. |
[REDACTED]
Section titled “[REDACTED]”When the bot is first added to a server and the setup wizard is run (/admin-slkards setup), the bot creates a SLKARDS category and places all its channels under it. This keeps SLKARDS content visually separated from the server’s other channels and lets admins manage permissions at the category level.
All SLKARDS channels use the naming convention slkards-{channel-purpose} (e.g., slkards-spawn, slkards-battles). Alliance channels use {alliance_name}-{channel-purpose} and are placed under their own per-alliance category.
[REDACTED]
Section titled “[REDACTED]”These channels are created during the setup wizard and exist for the lifetime of the bot on the server. Each channel description below includes its purpose, who can see and interact with it, which commands work in it, and how the bot uses it.
[REDACTED]
Section titled “[REDACTED]”- Purpose: Server admin messages and official SLKARDS update announcements.
- Permissions: All registered players can read. Only the bot and users with the admin role can send messages.
- Bot behaviour: Posts here when
/admin-slkards announceis used, plus automated system announcements (ranked season resets, major updates). Messages are formatted with embeds for consistency. - Allowed commands: None (read-only for players).
[REDACTED]
Section titled “[REDACTED]”- Purpose: Marketing and information about the Premium Personal Pass (PPP) and Premium Server Upgrade (PSU).
- Permissions: All registered players can read. Only the bot can send messages.
- Bot behaviour: Posts a persistent embed explaining premium features and pricing. The embed is updated if premium offerings change. Serves as a passive information channel, not a sales funnel.
- Allowed commands: None (read-only).
[REDACTED]
Section titled “[REDACTED]”- Purpose: Event lifecycle — start announcements, progress updates, and final results.
- Permissions: All registered players can read. Only the bot can send messages.
- Bot behaviour: When an event starts, posts an embed with the event name, type, description, duration, active modifiers, and reward tiers. For co-op events, a progress-bar embed is posted and edited periodically as the server-wide goal progresses. When the event ends, a final results embed is posted. See Notifications for DM-based player notifications.
- Allowed commands: None (read-only).
[REDACTED]
Section titled “[REDACTED]”- Purpose: Wipe warnings and wipe execution announcements.
- Permissions: All registered players can read. Only the bot can send messages.
- Bot behaviour: Posts three messages at specific intervals: 48 hours before, 24 hours before, and at the moment of the wipe. All three ping the player role. Warnings are bold for visibility. See Notifications for the exact message formats.
- Allowed commands: None (read-only).
[REDACTED]
Section titled “[REDACTED]”- Purpose: At-a-glance leaderboard snapshot showing the top 10 players per category.
- Permissions: All registered players can read. Only the bot can send messages.
- Bot behaviour: On setup, posts a set of compact leaderboard embeds — one per category. Player categories: current season ELO, prestige count, NG+ cycles, total kards collected, total koins received, minigames won. Alliance category: AvA wins. Each embed shows only the top 10 entries as a quick-reference snapshot. Embeds are edited in place on a schedule (ELO recalculated daily for percentile accuracy; all others every 6 hours). Leaderboard data is served from Redis sorted sets for performance. For real-time accuracy, players should use the
/slkards leaderboardcommand. - Allowed commands: None (read-only). Full leaderboards with pagination, filtering, and personal rank lookup are served by
/slkards leaderboardin player chat.
[REDACTED]
Section titled “[REDACTED]”- Purpose: General discussion channel for server admins regarding SLKARDS management.
- Permissions: Only users with the admin role can see and send messages.
- Bot behaviour: The bot does not post here automatically. Free-form discussion space.
- Allowed commands: None enforced — admins can discuss freely. Admin/debug commands should be used in the admin commands channel for audit trails.
[REDACTED]
Section titled “[REDACTED]”- Purpose: Dedicated channel for executing admin and debug commands with full audit trails.
- Permissions: Only users with the admin role can see and send messages.
- Bot behaviour: All admin and debug command outputs are posted here non-ephemerally for transparency and audit logging. Every command execution is logged to
logs_admin. - Allowed commands: all
/admin-slkardsand/debug-slkardscommands.
[REDACTED]
Section titled “[REDACTED]”- Purpose: The channel where kards spawn and minigame queues form.
- Permissions: All registered players can read. Players cannot type — prevents kard spawn messages from being pushed out of view. Interaction is button-only (joining the minigame queue).
- Bot behaviour:
- When the spawn timer fires, posts an embed showing the spawned kard (image, name, series, rarity) with a
Join Minigamebutton and an announcement of which minigame will start in 5 minutes. - Players click to join the queue during the 5-minute window.
- Once the timer ends, participants are split into pools (see Spawning for pool sizes per rarity) and a private thread per pool is created within the spawn channel. Only the pool’s players are added.
- The minigame plays out entirely within the thread. The winner receives the kard and a confirmation message is posted.
- Threads are cleaned up according to the server’s thread cleanup setting (default: auto-deleted after 5 minutes).
- When the spawn timer fires, posts an embed showing the spawned kard (image, name, series, rarity) with a
- Allowed commands: None (interaction via buttons only).
[REDACTED]
Section titled “[REDACTED]”- Purpose: Battle queue and battle execution.
- Permissions: All registered players can read and send messages (for queuing). Battle threads are private to the two participants.
- Bot behaviour:
- Players use
/slkards battleto enter the queue or challenge a specific player. - Ranked matchmaking pairs players by ELO proximity. Casual matches can specify an opponent or match randomly.
- Once a match is found, the bot creates a private thread for the two players. All deck selection, action choices, turn narration, and results are posted within it.
- On battle conclusion, the results summary is posted in the thread, and the thread is cleaned up per the server’s setting (default: auto-deleted after 5 minutes). ELO changes and GP awards are processed in the background.
- Players use
- Allowed commands:
/slkards battle.
[REDACTED]
Section titled “[REDACTED]”- Purpose: Trade discussion and trade execution.
- Permissions: All registered players can read and send messages.
- Bot behaviour:
- Players post trade requests in the channel using the player-driven convention
[Want: #0, #68, #214, ...] [Have: #10, #92, #354, ...]. This is not bot-enforced. - When a player initiates a trade with
/slkards trade, the target receives a trade request. If accepted, a private thread is created for both players. - Within the thread, players select kards to offer, view each other’s offerings, and go through the double-confirmation flow. The trade receipt is posted in the thread before cleanup.
- After the trade, each player receives an ephemeral prompt to leave +rep or -rep for their trade partner.
- Players post trade requests in the channel using the player-driven convention
- Allowed commands:
/slkards trade,/slkards dex(for referencing collections during discussion).
[REDACTED]
Section titled “[REDACTED]”- Purpose: Merchant store interactions (The Collector, Ida, Zeno, Dr. Higginbotham, Grand Central Marketplace).
- Permissions: All registered players can read and use commands. Store threads are private to the player.
- Bot behaviour:
- Players use
/slkards stores(or a direct shortcut —/slkards collector,/slkards ida,/slkards marketplace) to open the merchant hub. The bot creates a private thread for the player to interact with the chosen merchant. - All store interactions (browsing packs, recycling duplicates, marketplace browsing/listing) happen within the thread. Dr. Higginbotham’s artificial-value flow is upcoming with 0.5 and Zeno’s Colosseum with 0.4.
- Threads are cleaned up per the server’s setting (default: auto-deleted 5 minutes after the last interaction).
- Players use
- Allowed commands:
/slkards stores,/slkards collector,/slkards ida,/slkards marketplace.
[REDACTED]
Section titled “[REDACTED]”- Purpose: General chat for players and the primary channel for most player commands.
- Permissions: All registered players can read and send messages.
- Bot behaviour: Responds to commands here. Most responses are ephemeral to avoid clutter, except
/slkards showcase(public by design — renders an owned kard as a canonical embed for others to see) and the upcoming/slkards profile(0.6, public by design for showing off). - Allowed commands (shipped today):
/slkards register,/slkards daily,/slkards koins,/slkards dex,/slkards showcase,/slkards prestige,/slkards almighty,/slkards series,/slkards help,/slkards stats,/slkards rep,/slkards owners,/slkards wishlist,/slkards leaderboard,/slkards secret,/slkards hint. Upcoming:/slkards profile+/editprofile+/achievements(0.6),/slkards gp(0.4),/slkards custom(0.8).
[REDACTED]
Section titled “[REDACTED]”- Purpose: General chat for alliance members and a hub for alliance browsing/creation.
- Permissions: All registered players can read and send messages.
- Bot behaviour: Responds to alliance commands here. Ephemeral responses for most commands. This channel exists even if no alliances have been created yet, serving as the starting point for alliance discovery.
- Allowed commands:
/alliance-slkards list,/alliance-slkards create,/alliance-slkards join,/alliance-slkards profile. Additionally,/slkards dex,/slkards profile,/slkards stats,/slkards achievementsso players don’t need to switch channels mid-conversation.
[REDACTED]
Section titled “[REDACTED]”When an alliance is created, the bot creates a new category named after the alliance (e.g., [Alliance Name]) and populates it with the channels below. When an alliance is deleted, the entire category and all its channels are removed.
[REDACTED]
Section titled “[REDACTED]”- Purpose: Public-facing channel visible to potential new members. Displays the alliance’s description, rules, weekly donation requirements, join mode, type, and other onboarding information.
- Permissions: Visible to all registered players (not just members). Only the bot can post/edit messages. Visibility is intentional so prospective members can read the rules before committing to join.
- Bot behaviour: Posts and maintains a single persistent embed with the alliance’s current settings. Auto-updated whenever a leader or co-leader changes any settings.
[REDACTED]
Section titled “[REDACTED]”- Purpose: Contract negotiation with incoming members.
- Permissions: Only the alliance’s leaders, co-leaders, and players currently in the recruitment process can see this channel.
- Bot behaviour: When a player begins the join process, the bot creates a private thread for the player and the alliance’s leaders/co-leaders to negotiate the contract (sign-on bonus, weekly wages). Thread is archived when the contract is accepted or rejected.
[REDACTED]
Section titled “[REDACTED]”- Purpose: Officer-only discussion and strategic planning.
- Permissions: Only officers, co-leaders, and the leader can see this channel.
- Bot behaviour: Posts shop purchase suggestions from members here (see
/alliance-slkards shop). Also receives automated alerts for pending join requests (invite-only mode), weekly donation shortfalls, and upcoming AvA battle dates. - Allowed commands: Alliance commands available to officers and above.
[REDACTED]
Section titled “[REDACTED]”- Purpose: Main communication channel for all alliance members.
- Permissions: All alliance members can read and send messages.
- Bot behaviour: Posts alliance-wide announcements here (member joins/leaves, level-ups, boon activations, raid availability).
- Allowed commands:
/alliance-slkards donate,/alliance-slkards vault,/alliance-slkards treasury,/alliance-slkards shop,/alliance-slkards roster,/alliance-slkards profile,/alliance-slkards leave.
[REDACTED]
Section titled “[REDACTED]”- Purpose: Donation tracking leaderboard.
- Permissions: All alliance members can read. Only the bot can post.
- Bot behaviour: Maintains a persistent embed showing each member’s weekly donation progress (kards and koins donated vs. requirements). Updated whenever a donation is made. At the end of each week, a summary is posted and the tracker resets.
[REDACTED]
Section titled “[REDACTED]”- Purpose: Archive of raid and AvA results.
- Permissions: All alliance members can read. Only officers and above can pin messages. The bot posts automatically.
- Bot behaviour: After each raid or AvA concludes, posts a detailed results embed (for raids: damage breakdown per member, boss HP remaining, rewards; for AvA: match results table, ELO changes, reward distribution).
[REDACTED]
Section titled “[REDACTED]”- Purpose: Transparent log of all alliance administrative actions.
- Permissions: Leaders and co-leaders can read. Only the bot can post.
- Bot behaviour: Automatically logs every administrative action: member kicks, setting changes, treasury purchases, contract changes, role promotions/demotions, and so on. Creates an auditable history for alliance transparency.
[REDACTED]
Section titled “[REDACTED]”When a raid or AvA begins, the bot creates temporary channels within the alliance’s category:
{alliance_name}-raid-{boss_name}— announcement channel with boss HP tracker, attacks remaining, and a battle channel that splits into per-player threads for each raid attempt.ava-{alliance_name}-vs-{opponent_name}— announcement channel with battle schedule, check-in status, and a battle channel that splits into per-matchup threads. Created in the main SLKARDS category (not the alliance one) since players from both alliances need access.
These channels are automatically deleted 24 hours after the raid or AvA ends.
For multi-alliance events (coalition raids, AvA Colosseum tournaments), special event channels are created and all members from participating alliances are added. Deleted after the event ends.
[REDACTED]
Section titled “[REDACTED]”These permanent channels can be unlocked through the alliance shop:
{alliance_name}-raid-tactics— discussion channel for planning raid strategies. Unlocked via Channel Expansions shop upgrade.{alliance_name}-ava-tactics— discussion channel for planning AvA strategies. Unlocked via Channel Expansions shop upgrade.{alliance_name}-suggestions— suggestion board for members to propose ideas for the alliance. Unlocked via Channel Expansions shop upgrade.
[REDACTED]
Section titled “[REDACTED]”Threads are SLKARDS’ primary tool for keeping channels clean. Instead of filling channels with multi-message interactions (battles, trades, stores, minigames), the bot creates short-lived private threads that only the relevant players can see.
[REDACTED]
Section titled “[REDACTED]”The thread cleanup behaviour is configurable per server by re-running /admin-slkards setup in repair mode (the standalone /admin-slkards threadcleanup command was removed in 0.3.x):
- Auto-delete after 5 minutes (default) — threads are deleted 5 minutes after the interaction concludes. Keeps channels clean. Players should screenshot or note anything they want to remember.
- Auto-archive after 1 hour — threads become read-only and hidden from the channel list after 1 hour. Players can revisit recent interactions by searching. Discord auto-deletes archived threads after 7 days.
- Auto-archive after 24 hours — threads stay accessible for a full day before archiving. Useful for servers where trade disputes are common.
This setting applies to spawn, battle, trade, and store threads. Alliance raid/AvA channels follow their own 24-hour cleanup rule. Recruitment threads follow the contract-negotiation lifecycle.
[REDACTED]
Section titled “[REDACTED]”| Thread type | Channel | Visibility | Lifecycle |
|---|---|---|---|
| Spawn minigame pool | slkards-spawn | Pool participants only | Created on spawn timer end → cleaned up per server setting |
| Battle | slkards-battles | Two combatants only | Created on match found → cleaned up per server setting |
| Trade | slkards-trading | Two traders only | Created on trade accept → cleaned up per server setting |
| Store interaction | slkards-stores | Single player only | Created on /slkards stores (or merchant shortcut) → cleaned up per server setting |
| Recruitment negotiation | {alliance}-recruitment | Applicant + leaders/co-leaders | Created on join process → archived on contract resolution |
| Raid attempt | {alliance}-raid-{boss} | Single attacker | Created on attack start → cleaned up per server setting |
| AvA battle | ava-{alliance_name}-vs-{opponent_name} | Two combatants | Pre-created 24h before → deleted with parent channel |
[REDACTED]
Section titled “[REDACTED]”Not every command works in every channel. This prevents misuse and keeps channels purpose-driven. If a player uses a command in the wrong channel, the bot responds with an ephemeral message pointing them to the correct channel.
| Command group | Allowed channels |
|---|---|
/admin-slkards setup, ban, unban, resetplayer, announce, viewlogs, refresh-leaderboards | slkards-admin-commands |
/admin-slkards eventcreate, eventschedule, eventcancel, eventlist, customapprove [upcoming 0.8] | slkards-admin-commands |
/debug-slkards make, forcespawn, forcewipe, nextspawn, nextwipe, grant, givekards, takekards, equipsuit, resetcooldown, reloadstatic, reloadcog, simulate | slkards-admin-commands |
/slkards battle [upcoming 0.4] | slkards-battles |
/slkards trade | slkards-trading |
/slkards stores, /slkards collector, /slkards ida, /slkards marketplace | slkards-stores |
/slkards register, daily, koins, dex, showcase, prestige, almighty, series, help, stats, rep, owners, wishlist, leaderboard, secret, hint | slkards-player-chat |
/slkards profile, editprofile, achievements [upcoming 0.6]; /slkards gp [upcoming 0.4]; /slkards custom [upcoming 0.8] | slkards-player-chat |
/alliance-slkards list, create, join, profile [all upcoming 0.7] | slkards-alliances-chat |
/alliance-slkards donate, vault, treasury, shop, roster, settings, contract, raid, ava, scout, profile, transfer, delete, leave, invite, kick [all upcoming 0.7] | {alliance_name}-members (some restricted by role) |
[REDACTED]
Section titled “[REDACTED]”[REDACTED]
Section titled “[REDACTED]”The bot must respect Discord’s rate limits to avoid being throttled or temporarily banned. Key limits to design around:
- Thread creation — ~10 per 10 seconds per channel. For high-traffic spawns (50+ players, multiple pools), stagger thread creation over several seconds.
- Message sends — 5 messages per 5 seconds per channel. Battle narration and minigame rounds should batch updates into single embeds rather than rapid-fire messages.
- Message edits — 5 edits per 5 seconds per message. Leaderboard and event progress embeds should throttle update frequency (no more than once per minute for live-updating embeds).
- DM sends — ~5 per second globally. For mass notifications (event completions, wipe warnings via DM), use a queue with rate-limited dispatch. See Notifications for details.
- Channel creation — ~10 per 10 minutes per guild. Alliance creation (7+ channels) should create channels sequentially with short delays. AvA matchup thread pre-creation should be spread across the 24-hour window.
- Bulk deletes — 100 messages max; messages must be less than 14 days old. Thread cleanup should use thread deletion rather than bulk message deletion.
[REDACTED]
Section titled “[REDACTED]”All bot-generated content uses Discord embeds for consistent formatting:
- Persistent embeds (leaderboards, alliance rules, donation trackers) are posted once and edited in place to avoid channel clutter.
- Interaction embeds (battle turns, store menus, trade windows) use ephemeral messages or thread-scoped messages that are cleaned up with the thread.
- Embed colour coding matches the relevant series colour code from
static_series.colorCode. System messages (wipes, announcements) use a consistent bot brand colour.
[REDACTED]
Section titled “[REDACTED]”- Missing channels. If a required channel is missing (manually deleted by an admin), the bot detects this on the next relevant action and sends a DM to the server admin with instructions to re-run
/admin-slkards setup(repair mode auto-recreates only the missing channels). - Missing permissions. If the bot lacks permissions in a channel (e.g., admin revoked send messages), it logs the error and notifies the admin via DM.
- Stale threads. A periodic cleanup job (every 6 hours) scans for orphaned threads (threads whose parent interaction completed but cleanup failed) and deletes them.
- Alliance channel orphans. If an alliance is deleted but channel cleanup fails (e.g., Discord API error), the next bot startup scan detects orphaned alliance categories and cleans them up, logging the action to
logs_admin.
See also: Data Schema · Admin & Debug Commands · Notifications · Roadmap