Dawnsorrow 09e3b6ca66
Build and Push Image / build (push) Has been cancelled
Initial commit: Stoat Role Bot
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-17 19:45:26 -06:00
2026-02-17 19:45:26 -06:00
2026-02-17 19:45:26 -06:00
2026-02-17 19:45:26 -06:00
2026-02-17 19:45:26 -06:00
2026-02-17 19:45:26 -06:00
2026-02-17 19:45:26 -06:00
2026-02-17 19:45:26 -06:00
2026-02-17 19:45:26 -06:00
2026-02-17 19:45:26 -06:00
2026-02-17 19:45:26 -06:00
2026-02-17 19:45:26 -06:00

Stoat Role Bot

Self-hosted bot for Stoat (open-source chat platform at 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 <name> / !role remove <name> 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 → SettingsBots (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

    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 rightclick 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 messages 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.<SERVER_ID>.reaction_roles.<MESSAGE_ID>: map emoji (unicode or custom emoji ID) → role name.
    • servers.<SERVER_ID>.assignable_roles: list of role names that can be used with !role add/remove.

Example:

{
  "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 <name> Everyone Give yourself a self-assignable role.
!role remove <name> Everyone Remove a self-assignable role.
!setreactionroles <message_id> 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 emojis 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):

    "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):

"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 <message_id> 👍=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 and Stoat developers.

Hosting the image on Gitea (automated pull on NAS)

New to Gitea? See 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 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):

export GITEA_REGISTRY=gitea.example.com
export GITEA_OWNER=myuser
./push-to-gitea.sh

Run without Docker

Requires Node.js 22+.

npm install
cp .env.example .env
# Set STOAT_BOT_TOKEN in .env
export CONFIG_PATH=./config
node bot/index.js

License

MIT.

S
Description
No description provided
Readme 56 KiB
Languages
JavaScript 92.3%
Shell 6%
Dockerfile 1.7%