# GogoBee Matrix community bot with E2EE, 50 plugins, passive tracking, scheduled posts, and optional LLM features. Written in Go using [mautrix-go](https://github.com/mautrix/go) for encryption and [modernc.org/sqlite](https://modernc.org/sqlite) for storage. --- ## Table of Contents - [Features](#features) - [Requirements](#requirements) - [Installation](#installation) - [Configuration](#configuration) - [Running the Bot](#running-the-bot) - [Commands](#commands) - [Passive Features](#passive-features) - [Scheduled Posts](#scheduled-posts) - [Achievements](#achievements) - [Personality Archetypes](#personality-archetypes) - [External APIs](#external-apis) - [Architecture](#architecture) - [Database](#database) - [Troubleshooting](#troubleshooting) --- ## Features - **E2EE that actually works** - mautrix-go with goolm (pure Go). Crypto state lives in SQLite so device keys survive restarts. Cross-signing bootstraps on first run — the bot self-verifies its own device. - **No CGo, no system deps** - builds to a single static binary. Cross-compile to whatever you want. - **50 plugins** with dependency injection and ordered registration - **Games & economy** - Euro virtual currency, Hangman (collaborative, threaded, tiered scoring, multilingual clue mode via DreamDict, difficulty tier display), Blackjack (1-4 players, auto-play timeout), UNO (solo vs bot or 2–4 player multiplayer via DMs, with optional No Mercy mode), Texas Hold'em (2-9 players, CFR-trained NPC bot, DM-based gameplay with Ollama coaching tips, 1-hour idle auto-close with 45-min warning), Wordle (daily cooperative, DreamDict-powered, 5-20 letter words, guess persistence across restarts, midnight expiry announcements, video game themed bonus words with category hints, dupe prevention across last 500 puzzles, earnings tracked in stats), Adventure (daily idle RPG via DMs — dungeon, mine, forage, fish, shop, or rest with TwinBee NPC distributing level-scaled rewards, mid-day random events, tier shorthand buying, holiday double actions, hospital revival system, Robbie the Friendly Bandit automated inventory cleaner), Arena (5-tier combat gauntlet with 20 unique monsters, risk-reward cashout system, death lockout, leaderboard), Co-op Dungeons (2–7 day party runs with funding tiers, TwinBee-narrated floor events with voting, spectator parimutuel betting, basket/mimic gift system, weighted-roll item distribution including masterworks at T4–T5), all with channel restriction - **Moderation system** (optional) - deterministic detection only, no LLM. Word list with leetspeak variation matching, text/image flood, repeated messages, mention flooding, link rate limiting, invite flooding, join/leave cycling. Three-strike ladder (warn → mute → ban). Admin room notifications, DMs over public callouts. - **Passive tracking** - XP, stats, streaks, achievements, markov corpus, keyword alerts, all running silently - **Scheduled posts** via [robfig/cron](https://github.com/robfig/cron) - Palavra do Dia (Portuguese WOTD with en/fr translations and etymology), holidays, game releases, birthdays, anime/movie releases, concert digests, esteemed members - **LLM integration** (optional) - Ollama-powered sentiment analysis, roast profiles, room vibes, tarot readings, conversation summaries - **Markdown rendering** - auto-detects `**bold**`, `_italic_`, and `` `code` `` in messages and sends proper HTML to Matrix clients - **Encrypted quote wall** - AES-256-GCM encrypted quotes at rest, reply-to-save, search, leaderboard - **Space groups** - automatic room grouping via membership overlap. Leaderboards, stats, and trivia scores span all rooms in a group. No Matrix Spaces API needed — the bot infers community boundaries from shared members. - **SQLite everything** - one file, no external database needed --- ## Requirements - Go 1.22+ - A Matrix homeserver account for the bot Optional: - [Ollama](https://ollama.ai) for LLM features - API keys for various services (see [Configuration](#configuration)) --- ## Installation ### From Source ```bash git clone https://github.com/prosolis/gogobee.git cd gogobee cp .env.example .env # edit with your settings go build -tags goolm -o gogobee . ./gogobee ``` ### Docker ```bash docker build -t gogobee . docker run --env-file .env -v ./data:/app/data gogobee ``` ### Docker Compose ```bash docker compose up -d ``` --- ## Configuration Everything is configured through environment variables or a `.env` file. ### Required | Variable | Description | |----------|-------------| | `HOMESERVER_URL` | Matrix homeserver URL, e.g. `https://matrix.org` | | `BOT_USER_ID` | Bot's Matrix user ID, e.g. `@gogobee:matrix.org` | | `BOT_PASSWORD` | Bot's Matrix password | ### Core (optional) | Variable | Default | Description | |----------|---------|-------------| | `DATA_DIR` | `./data` | Where the database and device files live | | `BOT_DISPLAY_NAME` | `GogoBee` | Display name | | `LOG_LEVEL` | `info` | `debug`, `info`, `warn`, or `error` | | `ADMIN_USERS` | | Comma-separated admin user IDs | | `BROADCAST_ROOMS` | | Comma-separated room IDs for scheduled posts | ### API Keys (optional) | Variable | Service | Used By | |----------|---------|---------| | `RAWG_API_KEY` | [RAWG](https://rawg.io/apidocs) | `!game`, `!retro`, `!releases` | | `DREAMDICT_URL` | DreamDict (self-hosted) | `!translate`, `!wotd`, `!antonym`, `!pronounce`, `!etymology`, `!difficulty`, `!rhyme`, `!define` (antonyms), Hangman (multilingual clues + difficulty tier), Wordle (word selection + guess validation + definitions) | | `CALENDARIFIC_API_KEY` | [Calendarific](https://calendarific.com) | Holiday posts | | `OPENWEATHER_API_KEY` | [OpenWeather](https://openweathermap.org/api) | `!weather` | | `FINNHUB_API_KEY` | [Finnhub](https://finnhub.io) | `!stock` | | `BANDSINTOWN_API_KEY` | [Bandsintown](https://artists.bandsintown.com) | `!concerts` | | `TMDB_API_KEY` | [TMDB](https://www.themoviedb.org/documentation/api) | `!movie`, `!tv`, `!upcoming` | | `SERPAPI_KEY` | [SerpAPI](https://serpapi.com) | Esteemed member image fetching | ### Services (optional) | Variable | Description | |----------|-------------| | `OLLAMA_HOST` | Ollama server URL, e.g. `http://localhost:11434` | | `OLLAMA_MODEL` | Model name, e.g. `llama3.2` | | `DREAMDICT_URL` | DreamDict instance for `!translate`, `!wotd`, dictionary commands, Hangman clues, Wordle words (e.g. `http://127.0.0.1:7777`) | | `LLM_SAMPLE_RATE` | Fraction of messages to classify (0.0–1.0, default `0.15`) | ### Encryption | Variable | Description | |----------|-------------| | `QUOTE_ENCRYPTION_KEY` | Base64-encoded 32-byte AES-256 key for encrypted quote storage and Markov corpus. Generate with `openssl rand -base64 32`. If unset, `!quote` and `!markov` are disabled. | ### Miniflux RSS (optional) | Variable | Default | Description | |----------|---------|-------------| | `MINIFLUX_URL` | | Miniflux instance URL, e.g. `https://rss.example.com` | | `MINIFLUX_API_KEY` | | Miniflux API key (Settings → API Keys) | | `MINIFLUX_POLL_INTERVAL` | `15` | Minutes between polls | | `MINIFLUX_DEFAULT_ROOM` | `BROADCAST_ROOMS` | Default room for posts | | `MINIFLUX_MAX_PER_POLL` | `5` | Max entries per feed per poll cycle | ### Feature Flags | Variable | Description | |----------|-------------| | `FEATURE_URL_PREVIEW` | Set to anything to enable automatic URL previews | | `FEATURE_SHADE` | Set to anything to enable the shade plugin (stub) | | `FEATURE_TRIVIA` | Set to `false` to disable trivia (default: enabled) | | `FEATURE_ESTEEMED` | Set to anything to enable satirical esteemed member posts | | `ESTEEMED_ROOM` | Room ID for esteemed member posts (separate from broadcast rooms) | | `FEATURE_MODERATION` | Set to `true` to enable the moderation system (disabled by default) | | `FEATURE_MARKET` | Set to `true` to enable the market overview plugin | | `MARKET_BROADCAST_SUMMARY` | Set to `true` to auto-post daily market summary to broadcast rooms | | `DISABLE_WOTD_POST` | Set to `true` to suppress daily WOTD auto-post (the `!wotd` command and passive WOTD usage tracking still work) | ### Games & Economy | Variable | Default | Description | |----------|---------|-------------| | `GAMES_ROOM` | | Room ID where game commands work (trivia, hangman, blackjack, holdem, wordle, flip) | | `EURO_COOLDOWN_SECONDS` | `30` | Cooldown between passive euro earning per user | | `EURO_DEBT_REMINDER` | `true` | Weekly DM reminder if player is in debt | | `EURO_STARTING_CAP` | `2500` | Max starting balance seeded from corpus | | `HANGMAN_MAX_WRONG_GUESSES` | `6` | Lives before game over | | `HANGMAN_SOLUTION_BONUS_MULTIPLIER` | `2` | Bonus multiplier for early solution | | `HANGMAN_PHRASE_FILE` | | Path to newline-delimited phrase file | | `BLACKJACK_TIMEOUT_SECONDS` | `60` | Auto-play timeout per turn | | `BLACKJACK_AUTOPLAY_THRESHOLD` | `15` | Stand at or above, hit below | | `BLACKJACK_MIN_BET` | `1` | Minimum bet in euros | | `BLACKJACK_MAX_BET` | `500` | Maximum bet per hand | | `BLACKJACK_DEBT_LIMIT` | `1000` | Maximum debt before betting disabled | | `UNO_MIN_BET` | `10` | Minimum wager in euros (solo) | | `UNO_POT_TAUNT_THRESHOLD` | `500` | Pot size at which GogoBee starts taunting | | `UNO_MULTI_MIN_BET` | `25` | Minimum ante for multiplayer UNO | | `UNO_MULTI_MAX_BET` | `500` | Maximum ante for multiplayer UNO | | `UNO_MULTI_LOBBY_TIMEOUT` | `300` | Lobby expiry in seconds | | `UNO_MULTI_TURN_TIMEOUT` | `30` | Auto-play timeout in seconds | | `UNO_MULTI_MAX_AUTOPLAY` | `3` | Consecutive auto-plays before forfeit | | `HOLDEM_SMALL_BLIND` | `10` | Small blind amount | | `HOLDEM_BIG_BLIND` | `20` | Big blind amount | | `HOLDEM_MIN_BUYIN` | `200` | Minimum balance to join | | `HOLDEM_MAX_BUYIN` | `2000` | Maximum stack at buy-in | | `HOLDEM_TIMEOUT_SECONDS` | `90` | Action timeout per turn | | `HOLDEM_NPC_NAME` | `TwinBee` | NPC bot display name | | `HOLDEM_NPC_HOUSE_BALANCE` | `10000` | NPC starting bankroll | | `HOLDEM_CFR_POLICY` | `data/policy.gob` | Path to CFR policy file | | `WORDLE_DEFAULT_LENGTH` | `5` | Default word length (5-20) | | `ADVENTURE_MORNING_HOUR` | `8` | Hour (UTC) to send morning DMs with daily choices | | `ADVENTURE_SUMMARY_HOUR` | `20` | Hour (UTC) to post daily summary to games room | ### Moderation All moderation settings are optional. The system is disabled unless `FEATURE_MODERATION=true`. | Variable | Default | Description | |----------|---------|-------------| | `MOD_WORDLIST` | | Path to newline-delimited prohibited word list | | `MOD_WORDLIST_VARIATIONS` | `true` | Check leetspeak/spaced variants | | `MOD_STRIKE_EXPIRY_DAYS` | `30` | Days before strikes expire | | `MOD_MUTE_DURATION_MINUTES` | `60` | Temp mute duration on strike 2 | | `MOD_MAX_STRIKES` | `3` | Strikes before permanent ban | | `MOD_FLOOD_MESSAGE_COUNT` | `5` | Messages in window = flood | | `MOD_FLOOD_MESSAGE_WINDOW_SECONDS` | `10` | Text flood window | | `MOD_FLOOD_IMAGE_COUNT` | `3` | Images/files in window = flood | | `MOD_FLOOD_IMAGE_WINDOW_SECONDS` | `30` | Image flood window | | `MOD_MAX_MESSAGE_LENGTH` | `2000` | Max chars per message (0 = disabled) | | `MOD_REPEAT_COUNT` | `3` | Repeated messages before strike | | `MOD_REPEAT_WINDOW_SECONDS` | `60` | Repeat detection window | | `MOD_REPEAT_SIMILARITY_THRESHOLD` | `0.85` | How similar counts as "same" (0.0–1.0) | | `MOD_MENTION_MAX` | `5` | Max unique @mentions per message | | `MOD_MENTION_FLOOD_COUNT` | `3` | Mention-heavy messages in window | | `MOD_MENTION_FLOOD_WINDOW_SECONDS` | `30` | Mention flood window | | `MOD_LINK_RATE_NEW_MEMBER` | `3` | Max links per window (new members only) | | `MOD_LINK_RATE_WINDOW_SECONDS` | `60` | Link rate window | | `MOD_INVITE_MAX_PER_HOUR` | `5` | Max room invites per user per hour | | `MOD_JOIN_LEAVE_COUNT` | `3` | Join/leave cycles before flag | | `MOD_JOIN_LEAVE_WINDOW_MINUTES` | `10` | Join/leave window | | `MOD_NEW_MEMBER_DAYS` | `14` | Days before a member is no longer "new" | | `MOD_NEW_MEMBER_FLOOD_MULTIPLIER` | `0.5` | Multiply flood thresholds for new members | | `MOD_ADMIN_ROOM` | | Dedicated room for mod notifications | | `MOD_DM_ON_ACTION` | `true` | DM users when action is taken | ### Space Groups | Variable | Default | Description | |----------|---------|-------------| | `SPACE_GROUP_THRESHOLD` | `50` | Percentage of the smaller room's members that must overlap to group rooms together (1–100) | | `HOLIDAY_COUNTRIES` | `US` | Comma-separated ISO country codes for Calendarific holiday posts | ### Missing Members | Variable | Default | Description | |----------|---------|-------------| | `MISSING_THRESHOLD_DAYS` | `14` | Days of inactivity before considered missing | | `MISSING_MAX_DAYS` | `90` | Days after which they're considered gone, not missing | | `MISSING_MIN_MESSAGES` | `10` | Minimum lifetime messages to be eligible | | `MISSING_EXCLUDE_USERS` | | Comma-separated user IDs to never list as missing | ### Rate Limits | Variable | Default | Description | |----------|---------|-------------| | `RATELIMIT_WEATHER` | `5` | Daily weather lookups per user | | `RATELIMIT_CONCERTS` | `10` | Daily concert searches per user | --- ## Running the Bot ```bash # dev go run -tags goolm . # prod go build -tags goolm -o gogobee . ./gogobee ``` The `-tags goolm` flag selects the pure-Go crypto implementation. No C compiler or libolm needed. ### First Run 1. Start the bot. It logs in, creates a device, bootstraps cross-signing, and self-verifies automatically. 2. That's it. E2EE works across restarts from here on out. --- ## Commands ### XP & Leveling | Command | Description | |---------|-------------| | `!rank` | Your level, XP, and progress | | `!leaderboard` | Top 10 by XP | ### Reputation | Command | Description | |---------|-------------| | `!rep [@user]` | Reputation count | | `!repboard` | Top 10 by rep | Rep is earned when someone thanks you. The bot detects this automatically. ### Stats & Personality | Command | Description | |---------|-------------| | `!stats [@user]` | Message statistics (includes Wordle and UNO earnings) | | `!superstatsexplusalpha [@user]` | Comprehensive profile: economy, games W/L, adventure levels, achievements, and more | | `!rankings [category]` | Rankings by words, links, questions, or emojis | | `!personality` | Your community archetype | ### Streaks | Command | Description | |---------|-------------| | `!streak` | Current and longest streak | | `!firstboard` | Top first-posters-of-the-day | ### Trivia | Command | Description | |---------|-------------| | `!trivia [category] [difficulty]` | Start a question | | `!trivia scores` | Room leaderboard | | `!trivia categories` | List categories | | `!trivia fastest` | Fastest answers | | `!trivia stop` | End current question | ### Economy | Command | Description | |---------|-------------| | `!balance` | Check your euro balance | | `!baltop` | Euro leaderboard | | `!baltransfer @user €amount` | Send euros to another player | ### Games (games channel only) | Command | Description | |---------|-------------| | `!flip` | Coin flip | | `!games` | List available games | | `!hangman start [easy\|medium\|hard\|extreme]` | Start a Hangman game (optional difficulty) | | `!hangman [--clue ]` | Start a multilingual game (en/fr/pt-PT) with optional clue | | `!hangman [letter]` | Guess a letter | | `!hangman [phrase]` | Attempt full solution | | `!hangman submit [phrase]` | Submit a phrase to the pool | | `!hangman skip` | Skip game (admin only) | | `!hangboard` | Hangman leaderboard | ### Blackjack (games channel only) | Command | Description | |---------|-------------| | `!blackjack €amount` | Start/join a Blackjack table (1-4 players) | | `!hit` | Take a card | | `!stand` | End your turn | | `!blackjack leave` | Leave before game starts | | `!bjboard` | Blackjack leaderboard | | `!twinbeeboard` | GogoBee's victory record against players | ### UNO (games channel only) UNO can be played solo (vs GogoBee) or multiplayer (1-4 players + bots). All gameplay happens in DMs. The games channel is used for lobby management and public announcements. | Command | Description | |---------|-------------| | `!uno €amount` | Start a solo game vs GogoBee | | `!uno nomercy €amount` | Start a solo No Mercy game | | `!uno nomercy 7-0 €amount` | Solo No Mercy with 7-0 rule | | `!uno start €amount` | Create a multiplayer lobby | | `!uno start nomercy €amount` | Multiplayer No Mercy lobby | | `!uno start nomercy 7-0 €amount` | Multiplayer No Mercy with 7-0 rule | | `!uno join` | Join an open lobby | | `!uno addbot` | Add a bot opponent to the lobby (max 2, funded from community pot) | | `!uno removebot` | Remove the last added bot from the lobby | | `!uno go` | Start the game (host only, 2+ participants required) | | `!uno leave` | Leave the lobby (refunds ante) | | `!uno cancel` | Cancel the lobby (host/admin, refunds all) | **DM commands during gameplay:** reply with a card number to play, `draw` to draw, `uno` to call UNO (required when you have 2 cards), `quit` to forfeit. During draw stacking, type `accept` to absorb the stack. #### Classic Mode Standard 108-card UNO deck. Draw one card per turn (pass if unplayable). Wild Draw Four can be challenged — if the challenger catches a bluff, the player draws 4 instead. GogoBee has a personality system during solo play: she reads a book while playing, and puts it down when the game gets serious (opponent has few cards). Commentary changes based on book state. #### No Mercy Mode Based on UNO Show 'Em No Mercy (2023, Mattel). Bigger 168-card deck, meaner rules. **New cards:** | Card | Type | Effect | |------|------|--------| | Skip Everyone | Colored | Skips all other players — you go again | | Discard All | Colored | Play it and discard every other card of that color from your hand | | Draw Four | Colored | Like Wild Draw Four but matches by color (not wild) | | Wild Reverse Draw Four | Wild | Reverse direction + draw 4 + pick a color | | Wild Draw Six | Wild | Draw 6 + pick a color | | Wild Draw Ten | Wild | Draw 10 + pick a color | | Wild Color Roulette | Wild | Pick a color — next player flips cards from the deck until that color appears, keeping all flipped cards | **Rule changes:** - **Draw stacking** — when hit with a draw card, play a draw card of equal or higher value to pass the penalty to the next player. The stack keeps growing until someone can't (or won't) stack back. That player draws the entire total. - **Draw until playable** — no more drawing one and passing. You keep drawing until you find a playable card. - **Mercy rule** — reach 25 cards in your hand and you're eliminated. #### 7-0 Rule (optional, No Mercy only) Enabled by adding `7-0` to the command. When active: - **Play a 7** — swap hands with another player of your choice (in multiplayer, you pick the target) - **Play a 0** — all players pass their hand to the next player in play direction #### Sudden Death When a 2-player game (including bot matchups) exceeds 80 turns, a 20-turn countdown begins. At turn 100, both hands are scored by UNO card point values — lowest total wins. Tiebreaker: fewer cards, then advantage to the non-active player. #### Multiplayer Bots The default bot (GogoBee) is always present in multiplayer games. Up to 2 additional bots (WinBee, GwinBee) can be added via `!uno addbot` while the lobby is open. Addbot bots ante from the community pot, increasing the total pot. A single human can start a game if bots fill the remaining slots. ### Texas Hold'em (games channel only) No-limit Texas Hold'em poker for 2-9 players. Buy-in is debited from your euro balance when you sit down; your remaining stack is cashed out when you leave. Private cards and coaching tips are delivered via DM — the room only sees start/end announcements. An optional AI opponent (NPC) uses a CFR-trained poker solver. Add one with `!holdem addbot`. | Command | Description | |---------|-------------| | `!holdem join` | Sit down at the table | | `!holdem leave` | Leave the table (cashes out stack, shows refund) | | `!holdem start` | Start dealing (2+ players) | | `!holdem play` | Shortcut: join + start in one command | | `!holdem addbot` | Add a CFR-trained AI opponent | | `!holdem fold` | Fold your hand | | `!holdem check` | Check (no bet to call) | | `!holdem call` | Call the current bet | | `!holdem raise ` | Raise to a total of amount | | `!holdem allin` | Go all-in | | `!holdem status` | Current table state (sent via DM) | | `!holdem help` | Show in-game help | **DM commands:** `!holdem tips on/off` — toggle coaching tips (equity + pot odds analysis, powered by Ollama with rules-based fallback). **Idle timeout:** Tables with no hands dealt close after 1 hour. A warning is posted at 45 minutes. #### NPC Bot The NPC opponent uses Counterfactual Regret Minimization (CFR), specifically the External Sampling variant of Monte Carlo CFR. Instead of hardcoding poker strategy, the bot learns one through millions of rounds of self-play. On each iteration, it plays both seats of a heads-up hand, tracks how much it "regrets" not having taken each alternative action, and gradually shifts its strategy toward the actions it regrets not taking. Over time, the strategy converges toward a Nash equilibrium — a point where no single change in play can improve its expected winnings against a perfect opponent. The trained policy ships as a single `.gob` file loaded at startup, and the bot plays a mixed strategy: it doesn't always make the same play in the same spot, but randomizes according to its trained probability distribution, which makes it harder to exploit. The interesting engineering is in the abstraction layer. Real poker has roughly 10^17 possible game states — far too many for a tabular approach. We collapse this space down to around 23,000 information sets by bucketing hand strength into 12 equity tiers (computed via Monte Carlo rollout against random opponent hands), classifying boards as dry, wet, or paired based on flush/straight draw density and board pairing, tracking stack-to-pot ratio across 5 buckets, and encoding the last 6 actions as a compressed history string. All of this gets packed into a single `uint64` key — no string formatting, no allocations on the hot path. Preflop hands use a lookup table of the 169 strategically distinct hold'em starting hands, which eliminates Monte Carlo during the most frequently visited part of the game tree. Training runs at about 5 million iterations across all CPU cores with shared regret tables, periodic checkpointing, and regret pruning after a 500K warmup to skip deeply negative branches. The result is a bot that plays a solid, unpredictable game — not world-class, but strong enough to make the table interesting. #### Training the NPC A standalone training CLI is provided under `cmd/holdem-train/`. It requires the `training` build tag: ```bash # Build the training CLI go build -tags training -o holdem-train ./cmd/holdem-train/ # Train with 8 workers (defaults to all CPU cores if --workers is omitted) ./holdem-train --iterations 5000000 --workers 8 --output data/policy.gob # Resume from a checkpoint ./holdem-train --iterations 5000000 --workers 8 --resume data/policy.gob.checkpoint --output data/policy.gob # Validate the trained policy (10K hands vs random baseline) ./holdem-train --validate --output data/policy.gob ``` | Flag | Default | Description | |------|---------|-------------| | `--iterations` | `5000000` | Number of training iterations | | `--workers` | `runtime.NumCPU()` | Parallel workers | | `--output` | `data/policy.gob` | Output policy file | | `--resume` | | Resume from checkpoint | | `--validate` | `false` | Run validation instead of training | | `--checkpoint-every` | `500000` | Checkpoint interval | | `--seed` | `42` | Random seed | Progress is logged with overall completion percentage and ETA. Checkpoints are saved every 30 seconds during parallel training. ### Wordle (games channel only) Daily cooperative Wordle — one puzzle per day, the community works together with a shared 6-guess limit. Word selection powered by DreamDict with a bundled word list as fallback. A new puzzle auto-posts at midnight UTC. Word length is configurable (5-20 letters). Guesses persist across bot restarts. When a puzzle expires at midnight, the bot reveals the answer and announces it to the room. The puzzle pool includes video game themed words (loaded from `data/wordle_games.txt`) — when one is selected, a category hint is shown. Duplicate prevention ensures the same word won't appear within the last 500 puzzles. | Command | Description | |---------|-------------| | `!wordle ` | Submit a guess for today's puzzle | | `!wordle grid` | Re-post the current puzzle grid | | `!wordle stats` | All-time leaderboard with community streak | | `!wordle new` | Start a new puzzle (admin) | | `!wordle new <5-20>` | New puzzle with specific word length (admin) | | `!wordle skip` | Reveal answer and end puzzle (admin) | | `!wordle help` | Show commands | Economy rewards are tracked per player — `!wordle stats` shows total earnings. ### Adventure (DM-based idle RPG) A daily DM-driven idle RPG where each player takes one action per day — dungeon, mine, fish, forage, visit the shop, blacksmith, or rest. Outcomes resolve with flavor text and loot is credited to your euro balance. An evening summary posts to the games room. TwinBee is a permanent NPC adventurer who distributes rewards to active players. Characters auto-create on first `!adventure` (or `!adv`) command. All gameplay happens in DMs — reply to the bot's morning prompt with your choice. DM replies are only interpreted as adventure choices for 15 minutes after a menu is sent, so other DM-based games (UNO, Hold'em) won't conflict. | Command | Description | |---------|-------------| | `!adventure` / `!adv` | Open today's action menu (sent via DM) | | `!adventure status` | Character sheet (sent via DM) | | `!adventure shop` | Browse equipment for sale (sent via DM) | | `!adventure buy ` | Buy equipment by name or tier shorthand (`3 sword`, `t4 boots`) | | `!adventure sell ` | Sell an inventory item (credits euro balance) | | `!adventure sell all` | Sell entire inventory | | `!adventure equip` | Equip masterwork gear from inventory | | `!adventure inventory` | List current inventory | | `!adventure leaderboard` | Top adventurers | | `!adventure revive @user` | Revive a dead player (admin) | | `!adventure respond ` | Reply to today's action prompt (alternative to DM reply) | | `!adventure summary` | Force daily summary post (admin) | | `!adventure boost` | Double XP/money for all adventurers for a day (admin) | | `!adventure babysit [week\|month\|status\|cancel]` | Hire TwinBee to run your daily action (trains your weakest gathering skill) | | `!adventure blacksmith` | Show repair quotes for damaged gear | | `!adventure repair [all\|]` | Repair one slot or all damaged gear at the blacksmith | | `!adventure rivals` | Show the rival pool and any open challenges | | `!thom [shop\|buy\|pay\|payoff\|autopay\|petbuy]` | Thom Krooke — housing, mortgage, and pet adoption broker | | `!hospital` | Check in to St. Guildmore's Memorial Hospital for same-day revival (costs €25k × combat level) | **DM replies:** Reply to the morning prompt with a number (`1`–`7`) or activity name (`dungeon`, `mine`, `fish`, `forage`, `shop`, `blacksmith`, `rest`). You can specify a location: `1 Soggy Cellar`, `mine 3`, etc. #### Activities Four activity types across 5 tiers of locations. Higher tiers require higher character level and equipment. - **Dungeon** — combat XP, chance of death, best loot potential - **Mining** — mining XP, cave-in risk, ore and gem drops - **Fishing** — fishing XP, hazard risk, catch drops - **Foraging** — foraging XP, wildlife hazards, herb and reagent drops #### Mechanics - **Equipment** — 5 slots (weapon, armor, helmet, boots, tool) with tiered upgrades from the shop. Equipment degrades on bad outcomes and breaks at 0 condition. - **Masterwork gear** — rare skill-specific equipment drops from gathering activities (mining, fishing, foraging). 15 items across 5 tiers with decreasing drop rates (5% T1 down to 0.5% T5). Location-gated — drops only at matching tier. Auto-equips if better than current gear; otherwise goes to inventory for manual equipping via `!adventure equip`. Masterwork items provide a +5% skill bonus when the item's source skill matches the current activity. Character sheet marks masterwork items with a star. - **Treasures** — rare collectibles (up to 3) that provide passive bonuses (XP multipliers, death chance reduction, loot quality). Prompted to discard when at cap. - **Streaks** — consecutive days of activity grant escalating bonuses (XP, loot quality, death chance reduction). Resting resets your streak. Dead players' streaks are frozen — you won't lose your streak to involuntary downtime. - **Grudge** — dying at a location marks it as your grudge. Returning there grants +10% success and +25% XP. Clears on success. - **Party bonus** — if two players independently visit the same location on the same day, both get +10% loot value. - **Death** — locked out for 6 hours. Natural respawn happens automatically when the timer expires. Use `!hospital` for immediate revival at a cost. Death's Reprieve (surviving a lethal roll) sets all equipment to 1 condition instead of destroying it. Dead players' streaks are preserved with a grace period — if you die and can't act on revival day, your streak won't reset. - **Holidays** — on recognized holidays (~20/year across religious and cultural calendars), you get a second daily action. Hebrew and Islamic calendar support for floating holidays. - **TwinBee NPC** — takes a daily action (location tier capped by best player's combined level), distributes loot share to active players scaled quadratically by level, and occasionally gifts random buffs. - **Hospital** — St. Guildmore's Memorial Hospital offers same-day revival for dead players. The bill is comically inflated (€125k × combat level) but guild insurance covers 80%, leaving €25k × combat level. Players who can't afford it are discharged back to the natural respawn queue. Nurse Joy provides the bedside manner. - **Robbie the Friendly Bandit** — an automated NPC who visits at a random hour each day (8:00–21:00 UTC). Robbie takes sub-tier gear from your inventory (shop gear below your equipped tier, masterwork gear you've outgrown), leaves €50 per item as a "handling fee," and donates everything to the community pot. If he takes masterwork gear and you don't already have one, he drops a "Get Out of Medical Debt Free" card. No player command — Robbie comes to you. - **Mid-day events** — random events can trigger between actions, delivering bonus loot, buffs, or narrative encounters. - **Chat level perks** — active chat participation boosts your adventurer. +5% XP per 10 chat levels (capped at +25% at level 50+), plus +0.5% rare drop chance per 10 levels. #### Blacksmith & Repair Equipment accumulates damage on bad outcomes and breaks at 0 condition. The blacksmith repairs gear for a per-point fee that scales with tier (base rates T0→T5: €1, €2, €5, €12, €30, €80; masterwork and arena gear use the next tier up). The cost has a mild convexity (`baseRate × damage × (1 + damage/200)`), so repairing earlier is slightly cheaper per point than letting gear sit at low condition — but not punitively so. `!adventure blacksmith` previews quotes; `!adventure repair all` or `!adventure repair ` commits. Visiting the blacksmith counts as your daily action. #### Babysitting Service Busy days? Hire TwinBee to run your daily action for you. Daily cost is `€100 + combatLevel × €20`. TwinBee trains your weakest gathering skill (mining/fishing/foraging) so the service doubles as catch-up for neglected tracks. Subscribe by the week or month, or check/cancel anytime: `!adventure babysit week|month|status|cancel`. #### Rival Duels At combat level 5 and above you're entered into the rival pool. Every 3–4 days a random eligible player is matched as your rival and challenges you to a rock-paper-scissors duel via DM. You have 24 hours to accept and play. Stake is `(combatLevel / 5) × €1,000`, winner-take-all. Use `!adventure rivals` to see the pool and open challenges. #### Housing & Mortgage (Thom Krooke) Thom Krooke is the guild's housing broker. Four tiers are available: | Tier | Name | Price | |------|------|-------| | 1 | Base | €75,000 | | 2 | Livable | €150,000 | | 3 | Comfortable | €300,000 | | 4 | Established | €600,000 | Buy outright or finance with a mortgage. Rates track the real-world US 5/1 ARM via the FRED API (`MORTGAGE5US` series; requires `FRED_API_KEY`, defaults to 6.5% if unset). Autopay pulls from your euro balance each day. Commands: `!thom shop`, `!thom buy `, `!thom pay `, `!thom payoff`, `!thom autopay on|off`, `!thom petbuy`. #### Pets Once you reach the Livable tier (HouseTier ≥ 2) a stray pet may show up at your door — 15% daily chance. When a pet arrives you'll get a DM prompt to `chase` it away or `feed` it to adopt. Each pet interaction grants +1.5 XP to a random skill. At pet Level 10, Thom unlocks pet armor for purchase (`!thom petbuy `). #### Guest NPCs — Misty & Arina Two rotating guest adventurers can be hired to join you on encounters: - **Misty** — €100 hire fee, 7-day cooldown. - **Arina** — €5,000 hire fee, 7-day cooldown. After hiring, there's a 7.5% chance per action over the next 7 days that your NPC shows up mid-adventure and applies a buff to the outcome. #### Arena (`!arena`) A multi-tier combat gauntlet independent of the daily adventure action. Fight through 5 tiers of 4 rounds each — 20 unique named monsters with escalating lethality. Earnings accumulate across rounds but are forfeited on death. After clearing a tier, choose to descend deeper (keep earnings at risk) or cash out. Death locks you out of both arena and adventure for 6 hours. Each fight produces a turn-based combat log (Dragon Quest style) with fabricated HP pools and action narration — the outcome is determined by the roll, the log is assembled backward from the result. Arena losses award +60 participation XP. | Command | Description | |---------|-------------| | `!arena` | Show the arena tier menu | | `!arena tier <1-5>` | Select a tier (shows confirmation with R1 opponent) | | `!arena fight` | Confirm entry / fight current round | | `!arena cancel` | Back out of tier selection | | `!arena descend` | Descend to next tier after clearing (earnings carry over, still at risk) | | `!arena cashout` | Take your earnings and leave | | `!arena stats` | Your personal arena stats | | `!arena status` | Current run state | | `!arena leaderboard` | Top arena players | | `!arena help` | Arena help text | **Mechanics:** - **Death chance** — based on monster lethality, combat level, equipment tier, and battle skill. Clamped between 1% and 98%. - **Rewards** — tier base payout * round number + battle skill * tier multiplier. Higher tiers and later rounds pay more. - **Auto-cashout** — 10 minutes to decide after clearing a tier. GogoBee cashes out on your behalf if you're slow. - **Tier entry confirmation** — `!arena tier N` previews the first opponent; `!arena fight` commits. #### Co-op Dungeons (`!coop`) Multi-day party runs separate from solo. 2–4 players, 2–7 days depending on tier, scaled rewards, and a public game-room thread the whole community watches. The combat action is consumed once at lock; subsequent days only ask for a daily funding decision (harvest activities continue normally). | Tier | Days | Difficulty | Reward Pool | Optimal Funding | |------|------|------------|-------------|-----------------| | 1 | 2 | Moderate | €22,500 | Minimal/Standard | | 2 | 3 | Hard | €40,000 | Standard | | 3 | 4 | Very Hard | €72,500 | Standard | | 4 | 5 | Brutal | €120,000 | Standard or Aggressive | | 5 | 7 | Murderous | €600,000 | Aggressive (must commit) | | Command | Description | |---------|-------------| | `!coop list` | Show open invites | | `!coop start <1-5>` | Open an invite (24h window, pinned in the games room) | | `!coop join []` | Join an open invite (defaults to most recent) | | `!coop fund ` | Set today's funding (`none` / `minimal` / `standard` / `aggressive` / `all_in`) | | `!coop vote ` | Vote on the day's TwinBee-narrated floor event | | `!coop bet ` | Spectator parimutuel bet (10% rake) | | `!coop gift ` | Send a gift (1 harvest action) | | `!coop giftvote ` | Party votes whether to open a received gift | | `!coop status` | Your current run state | | `!coop stats` | Community-wide aggregates: outcomes, gold flow, betting, gifts, helpfulness | | `!coop cancel` | Leader cancels an open invite before lock | | `!coop admgift [sender]` | Drop a gift into an active run, bypassing party-member and harvest-action checks (admin only — debug/testing) | | `!coop help` | Co-op command list | **Funding tiers** add to the per-floor success modifier: None −10%, Minimal +0%, Standard +8%, Aggressive +18%, All-In +30%. None is free; Minimal €500/day; Standard €1,500; Aggressive €4,000; All-In €10,000. Funding is non-refundable. Inactive players auto-play None. **Floor events.** TwinBee narrates 1 of 4 categories per floor (Obstacle / Opportunity / Crisis / Encounter), tier-weighted. Each event has 2–3 options; majority vote wins, ties go to the leader, leader has the casting tiebreak. TwinBee always recommends an option — he is wrong roughly half the time. The party's vote modifier (−15 to +12 per floor depending on the option) stacks on the funding modifier. The 95% per-floor success cap means once you're saturated, more funding is wasted. **Party strength factors.** Each member contributes a small per-floor modifier based on their combat level relative to the tier minimum (clamped ±8) plus a pet bonus (max +2.5 at pet level 10). A maxed veteran party at T5 can succeed at Standard funding where a fresh party would need Aggressive. **Newbie liability.** Players below a tier's minimum combat level are flagged in the party post and capped at +8% funding modifier regardless of how much they pay. The party chose to let them in. Their reward share is unchanged — the cost is borne by the funding economy, not the post-run split. **Spectator betting.** Parimutuel pool, 10% rake. Bets can be placed or increased any time during the run; positions are locked in (success or failure can't be switched). Party members can bet on their own run — sandbagging while heavily bet against is exploitative and visible. Odds line shows estimated success% based on party levels, pets, neutral funding assumption, and a hidden TwinBee Helpfulness Rating (rolling last 30 floor events: how often his recommendation was right). Helpfulness shifts the line ±20% but is never shown directly — players notice the line moves after events resolve. **Gifts.** Anyone *not* in the run can spend one harvest action to send a Care Basket or a Mimic. The party never sees which type. Vote `open` or `leave`. Magnitudes are equalized across all four outcomes — both "always open" and "always leave" yield EV=0 with σ=6, so neither is risk-averse-dominant. The choice is purely about reading sender intent. | | Open | Leave | |-------------|------|-------| | **Care Basket** | +6% (boost) | −6% (basket explodes) | | **Mimic** | −6% (mimic does what mimics do) | +6% (sad mimic helps anyway) | Multiple gifts stack additively — coordinated senders can swing odds significantly. The full gift log is public at end of run. **Loot.** On success, gold pool splits evenly (5% community tax). 2–6 items drop from the corresponding solo dungeon loot table (count scales with tier). Each item goes to a member via weighted roll — your share of total funding is your odds. **T5 always drops a masterwork**; T4 has a 25% chance. Masterworks go to inventory (not auto-equipped) so winners with better gear can sell or trade. **Wipes.** No reward. Funding is gone. No combat-action refund (the tick already gave you a fresh one at midnight). Bet pool pays out to the failure side. The dungeon does not editorialize. **Pinning.** Invite posts are pinned in the games room when opened, unpinned when the run locks or cancels. Bot needs power level for state events. ### Reminders | Command | Description | |---------|-------------| | `!remindme