A collaborative “crafting” mini‑game for Discord: players combine items like fire+water to discover new ones, working together until someone (or the server) discovers life.
This repo is built around discord.py + a lightweight storage layer + an LLM-powered crafting engine (OpenAI). It’s intentionally simple: one channel, one shared inventory, and a lot of human creativity.
- Crafting via chat: type
fire+water(spaces okay) to craft. - Shared server inventory persisted to disk per guild (
data/). - LLM crafting engine that returns one real word + emoji, with guardrails.
- Interactive, paginated inventory UI (Discord buttons).
- Admin controls: start/stop rounds, ping contributors.
- Quality of life:
- Fuzzy item matching (so typos don’t kill the vibe).
- Suggestions when an item isn’t found.
- “Top crafters” leaderboard stats.
- Auto-restore a running round after bot restart.
- A round starts with seed items: fire, water, earth, air.
- Players craft by submitting
itemA+itemB. - The bot:
- Finds both items in the inventory (exact match, then fuzzy match).
- Calls the LLM to generate a single, real word result + emoji.
- Adds new items to the shared inventory (duplicates are allowed as “already discovered”).
- Tracks contributor stats.
- The round ends when life exists in the inventory.
All commands work in the configured game channel only.
| Command | What it does |
|---|---|
!game_of_life / !gol |
Show help |
!game_of_life inv |
Show inventory (paginated) |
!game_of_life page <n> |
Jump to page n |
!game_of_life find <word> |
Search inventory (whole-word match, then fuzzy suggestions) |
!game_of_life top |
Show top crafters |
!game_of_life start |
Admin/host only: start a new round |
!game_of_life stop |
Admin/host only: stop the round |
!game_of_life ping |
Admin/host only: mention contributors + stats |
Crafting input format:
fire+waterfire + waternature's gift + nature's gift(apostrophes supported)
- Python 3.10+ recommended
- A Discord application + bot token
- An OpenAI API key (used for crafting results)
Install these (you can pin versions however you like):
pip install -U discord.py python-dotenv openaiIf you prefer a requirements.txt, create one with:
discord.py>=2.3
python-dotenv>=1.0
openai>=1.0
Copy .env.example to .env:
cp .env.example .envFill in:
DISCORD_BOT_TOKEN="your_discord_bot_token"
OPENAI_API_KEY="your_openai_api_key"Edit:
cogs/game_of_life/config.py
AUTHORIZED_USER_ID = 123456789012345678
GAME_OF_LIFE_CHANNEL_ID = 123456789012345678
COMMAND_PREFIX = "!game_of_life"
GOL_ALIAS = "!gol"AUTHORIZED_USER_IDis the single user allowed to start/stop/ping.GAME_OF_LIFE_CHANNEL_IDis the only channel where the bot responds.
Give it permissions to:
- Read messages
- Send messages
- Embed links
- Use external emojis (optional)
- Use message content intent (required for reading
fire+water)
Important: You must enable the Message Content Intent in the Discord Developer Portal and in code (already enabled in bot.py via intents.message_content = True).
From the repo root:
python bot.pyYou should see:
- Logged in as
<botname> - Then you can use
!golin the configured channel.
All server data is stored in data/:
inventory_<guild_id>.json– shared inventory itemscontributors_<guild_id>.json– contributors for the current roundstate_<guild_id>.json– whether a round is activestats_<guild_id>.json– per-user craft counts and new item counts
This is deliberately simple JSON storage. If you deploy to an ephemeral filesystem (some PaaS), you’ll want a persistent volume or a real database.
The crafting engine (llm.py) uses a strict system prompt plus post-validation to keep results sane:
- Must return STRICT JSON:
{"status":"ok","result_name":"<one word>","emoji":"<emoji>"} result_namemust be:- one lowercase word (letters and optional hyphens)
- a real, recognizable word (not a made-up blend)
- not equal to either input
- When inputs are identical, the result must not regress (e.g.,
ocean+oceanshould not becomesea). - Built-in fallback pairs for common combos (e.g.,
fire+water -> steam), plus safe fallback words if parsing fails.
- cooldowns / per-user limits
- caching crafted pairs
- cheaper models or a local ruleset for early-game combos
This bot runs anywhere Python runs. The only “special” requirement is persistent storage if you want inventories to survive restarts.
Common options:
- A VPS with systemd
- Docker with a mounted volume for
data/ - A hobby server like Raspberry Pi (humans love reinventing space heaters)
Example systemd service idea (sketch):
[Unit]
Description=Game of Life Discord Bot
After=network.target
[Service]
Type=simple
WorkingDirectory=/path/to/game-of-life
EnvironmentFile=/path/to/game-of-life/.env
ExecStart=/path/to/venv/bin/python bot.py
Restart=always
[Install]
WantedBy=multi-user.targetMIT. See LICENSE.