# GogoBee Matrix community bot with E2EE, 43 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. - **43 plugins** with dependency injection and ordered registration - **Games & economy** - Euro virtual currency, Hangman (collaborative, threaded, tiered scoring), Blackjack (1-4 players, auto-play timeout), UNO (solo vs bot or 2–4 player multiplayer via DMs, with optional No Mercy mode), 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) - WOTD, 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 - **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` | | `WORDNIK_API_KEY` | [Wordnik](https://developer.wordnik.com) | Word of the Day | | `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` | | `LIBRETRANSLATE_URL` | LibreTranslate instance for `!translate` | | `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. Generate with `openssl rand -base64 32`. If unset, `!quote` is disabled. | ### 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) | ### Games & Economy | Variable | Default | Description | |----------|---------|-------------| | `GAMES_ROOM` | | Room ID where game commands work (trivia, hangman, blackjack, 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 | ### 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_TRANSLATE` | `20` | Daily translation limit 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 | | `!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 [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 (2-4 players + bot). 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 go` | Start the game (host only, 2+ players 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 ### Reminders | Command | Description | |---------|-------------| | `!remindme