Talk to me · Julian Reder · Resume · GitHub

Strife

Discord Bots · 2026 - Present

A multiplayer game platform for Discord that runs turn-based matches inside message threads, featuring plugin game engines, PostgreSQL persistence, and crash recovery.

2026 - Present View Project ↗
Pythondiscord.pyPostgreSQLasyncpgPydanticDocker
Discord thread slash, components Host lobby, session, routing play() live = replay = CLI Plugin GameContext Move log append-only, resume PostgreSQL 16 matches, players, live integrity
Architecture diagram illustrating how Discord interactions route through the core game host and state storage into individual game plugins.

Built

I developed Strife as a complete rewrite of my earlier Discord bot PlayCord, creating an extensible platform where multiplayer turn-based games run in dedicated message threads. The architecture uses a modular plugin system so that the exact same game logic runs interactively on Discord, replays historical matches, and runs in local command line sessions.

Hard parts

  • Recovering ongoing matches after bot restarts required saving every player action to an append-only database log and replaying moves sequentially to restore game state.
  • Handling user interface interactions across Discord threads required encoding signed message identifiers and managing automated timeouts for inactive lobbies.
  • Preventing unresponsive game code from blocking Discord's asynchronous event loop required isolating player turns inside bounded background execution pools.
  • Designing relational database migrations to track active match states and foreign key relationships across players, guilds, and historical move logs.

Learned

Building a reliable online gaming bot requires treating state persistence as the central priority, using deterministic game rules and an append-only move log so that crashes never corrupt active games.

Also

  • Seven built-in games including Chess, Coup, Mafia, Connect Four, Spyfall, and Liar's Dice, alongside support for third-party plugins.
  • Robust PostgreSQL database layer that stores full move histories and enforces match integrity constraints.
  • Unified game loop interface shared across interactive Discord sessions, historical match replays, and command line testing.
  • Self-contained Docker Compose configuration for easy hosting and deployment.

From single-purpose bots to a game platform

My earlier Discord gaming bots like Piranha and PlayCord were fun experiments, but each bot was tightly coupled to a single game and handled user interaction through hardcoded commands and temporary memory dictionaries. Whenever the bot restarted or encountered an unexpected network disconnect, ongoing games vanished and player progress was lost. Strife was designed from scratch to solve these limitations by providing a durable hosting environment that can run many different games through a unified plugin interface.

The system creates dedicated Discord message threads for every new match, keeping game discussions and interactive button controls neatly contained without cluttering server channels. It includes built-in implementations of seven games, ranging from classic board games like Chess and Connect Four to social deduction games like Coup and Mafia, while allowing new games to be added as modular plugins.

Persistent state and crash recovery

The primary design goal for Strife was ensuring that a server restart or network glitch would never ruin an active match. To achieve this, the host records every game move into a PostgreSQL database as an append-only log of player actions and state transitions. If the bot restarts while games are in progress, it scans the database for active matches and replays each recorded move sequentially through the game engine, restoring the exact state of the board before re-enabling player controls.

Because the core game loop is completely separated from Discord's network APIs, the same game logic function can run in multiple contexts. During a live match it listens to Discord button clicks, in replay mode it reads past database records to generate an interactive playback, and in local development it runs directly in a terminal console, which makes testing new game rules much faster.

Discord thread slash, components Host lobby, session, routing play() live = replay = CLI Plugin GameContext Move log append-only, resume PostgreSQL 16 matches, players, live integrity
Data flow showing how user inputs pass through Discord interaction handlers, persist in PostgreSQL, and execute across modular game plugins.

Managing asynchronous execution and user interface state

Running interactive games on Discord introduces numerous edge cases around timeouts, concurrent button presses, and user navigation. Strife packs interaction metadata into signed payloads attached to Discord interface components, allowing the bot to route button clicks directly to the appropriate match without keeping large state trees in transient memory.

To keep slow game logic or unexpected loops from freezing Discord's asynchronous event loop, player moves are executed in a managed thread pool with strict timeout bounds. If a game plugin hangs or takes too long to respond, the host can safely terminate the turn and notify the players without impacting any other matches running on the server.