# Stoat Role Bot Self-hosted bot for **[Stoat](https://stoat.chat)** (open-source chat platform at [stoat.chat](https://stoat.chat)) that gives members **roles** via **reactions** or **text commands** in server channels. Stoat is the rebrand of Revolt and uses the same API; this bot works with Stoat and Revolt instances. ## Features - **Reaction roles**: Users react to a specific message with an emoji to get (or remove) a role. - **Text commands**: Users run `!role add ` / `!role remove ` for self-assignable roles; `!roles` lists them. - **Admin commands**: Configure reaction-role message and assignable role list from the chat (or via `config/roles.json`). ## Quick start (Docker) 1. **Create a bot on your Stoat server** - In Stoat, open your server → **Settings** → **Bots** (or equivalent). - Create a bot and copy its **token**. - Ensure the bot has **Assign Roles** permission (and that its role is above any roles it should assign). 2. **Configure and run** ```bash cp .env.example .env # Edit .env and set STOAT_BOT_TOKEN=your_bot_token cp config/roles.json.example config/roles.json # Edit config/roles.json: replace YOUR_SERVER_ID and MESSAGE_ID (see below) docker compose up -d ``` 3. **Server ID**: In Stoat, enable developer mode if available, then right‑click your server → copy ID. Use that in `roles.json` as `YOUR_SERVER_ID`. 4. **Reaction-role message**: Send a message in the channel (e.g. “React to get roles”), then copy that message’s ID. Put it under `reaction_roles` in `roles.json` with emoji → role name. When users add/remove reactions, the bot will add/remove the role. ## Configuration - **Environment** - `STOAT_BOT_TOKEN` or `REVOLT_BOT_TOKEN` (required): Bot token from your Stoat/Revolt server. - `PREFIX` (optional): Command prefix (default `!`). - `CONFIG_PATH` (optional): Path to config dir inside container (default `/app/config`). - **`config/roles.json`** - `servers..reaction_roles.`: map emoji (unicode or custom emoji ID) → role name. - `servers..assignable_roles`: list of role names that can be used with `!role add/remove`. Example: ```json { "servers": { "01ABC123DEF456": { "reaction_roles": { "01MSG789XYZ": { "👍": "Notifications", "🔔": "Announcements" } }, "assignable_roles": ["Notifications", "Announcements", "Gamer"] } } } ``` The bot writes updated config when admins use the admin commands below, so the container needs write access to the mounted `config` directory. ## Commands | Command | Who | Description | |--------|-----|-------------| | `!roles` | Everyone | List self-assignable roles. | | `!role add ` | Everyone | Give yourself a self-assignable role. | | `!role remove ` | Everyone | Remove a self-assignable role. | | `!setreactionroles emoji=RoleName ...` | Admin (Manage Role) | Set which message and emoji→role pairs are used for reaction roles. | | `!setassignableroles Role1, Role2, Role3` | Admin (Manage Role) | Set the list of self-assignable roles (comma-separated names). | For **custom server emojis** in reaction roles, use the emoji’s ID in `roles.json` (see Stoat/Revolt docs for how to get it). Unicode emojis (e.g. 👍) can be used as-is. ## Setting up reaction roles in config 1. **Create the message in Stoat** In the channel where you want reaction roles, send a message (e.g. "React below to get roles"). That message must stay there; the bot will watch reactions on it. 2. **Get the message ID** In Stoat, enable developer mode if available, then **right-click that message** and copy its ID. It's a long string like `01ABC123MSG456...`. 3. **Edit `config/roles.json`** Under your server (same `SERVER_ID` you use for `assignable_roles`), add a `reaction_roles` block. The key is the **message ID**; the value is an object mapping **emoji to role name** (role names must match your server's roles exactly): ```json "reaction_roles": { "01ABC123MSG456": { "👍": "FFXIV", "🎮": "Minecraft", "🃏": "MtG" } } ``` - **Unicode emojis** (👍, 🎮, etc.): use the character as the key. - **Custom server emojis**: use the emoji's ID as the key. 4. **Save the file.** The bot reloads config on each reaction; restart the container only if needed. 5. **Add the reactions to the message** Add the same emojis to the message. When users click a reaction they get the role; when they remove it they lose the role. **Example** for your server (replace `PASTE_MESSAGE_ID_HERE` with the real message ID): ```json "01KHEGSQZB7HXG0YCKMCA2W5PW": { "reaction_roles": { "PASTE_MESSAGE_ID_HERE": { "👍": "FFXIV", "🎮": "Minecraft", "🃏": "MtG" } }, "assignable_roles": ["FFXIV", "Ascension", "Tarnished", "Minecraft", "Tabletop", "MtG", "Smash", "Soul Calibur", "Hearthstone", "Degenerate"] } ``` **Alternative:** An admin can set reaction roles from chat: `!setreactionroles 👍=FFXIV 🎮=Minecraft 🃏=MtG` ## Self-hosted Stoat / custom API URL If you run your own Stoat (or Revolt) instance, point the bot at your API and WebSocket. Set the client configuration when building the bot (revolt.js accepts a `configuration` object with `revolt` and `ws` URLs). The default in revolt.js is the public Revolt/Stoat API (`api.revolt.chat` / `wss://ws.revolt.chat`). To use a different instance you would need to pass a custom configuration to the `Client` constructor; see [revolt.js](https://revolt.js.org/) and [Stoat developers](https://developers.stoat.chat/). ## Hosting the image on Gitea (automated pull on NAS) **New to Gitea?** See **[docs/GITEA-SETUP.md](docs/GITEA-SETUP.md)** for a simple step-by-step guide. To build in Gitea and pull the image on your NAS: 1. **Push this repo to your Gitea** (e.g. `myuser/stoat-role-bot`). 2. **Enable Gitea Actions** and add **Secrets** for the container registry: - **Settings → Secrets**: `REGISTRY_USER` = your Gitea username, `REGISTRY_PASSWORD` = your password or a Personal Access Token (with package write). 3. **On every push to `main`**, the workflow in `.gitea/workflows/docker.yml` builds and pushes the image to your Gitea Container Registry. The image will be at: `{your-gitea-host}/{owner}/stoat-role-bot:latest` (e.g. `gitea.example.com/myuser/stoat-role-bot:latest`). 4. **On your NAS**, use the image from Gitea instead of building locally: - Create `.env` with `GITEA_IMAGE=gitea.example.com/myuser/stoat-role-bot:latest`, plus `STOAT_BOT_TOKEN`, etc. - Run: `docker compose -f docker-compose.pull.yml pull && docker compose -f docker-compose.pull.yml up -d` - To **auto-update**: use [Watchtower](https://containers.dev/run/watchtower) or a cron job that runs `docker compose -f docker-compose.pull.yml pull` and restarts the container. **Manual push** (from your PC, without Actions): ```bash export GITEA_REGISTRY=gitea.example.com export GITEA_OWNER=myuser ./push-to-gitea.sh ``` ## Run without Docker Requires Node.js 22+. ```bash npm install cp .env.example .env # Set STOAT_BOT_TOKEN in .env export CONFIG_PATH=./config node bot/index.js ``` ## License MIT.