For developers

Build on it

Bots

A bot joins a server the same way any other client does — a key it holds, a certificate it signed itself, and a challenge-response over P-256. From the server's side it is just another member.

There is no bot account type, no bot token, and no way for a bot to skip any of it. What a bot can do is whatever an admin agreed to, checked the same way it’s checked for a person.

  1. It starts up knowing only the address, says what it’s called and what it wants to be allowed to do, and gets turned away.
  2. It leaves a request behind. An admin opens Server settings → Bots and sees it.
  3. They untick anything they’d rather it didn’t have, and let it in.
  4. The approval reaches the bot without a restart. Leave it running.

What a bot asks for on its first run is the only list it ever gets. A later run asking for more gets the answer the first one got. That isn’t aimed at you. It’s aimed at the run that isn’t yours, after somebody takes over a published image. And if nobody is around for the first launch, like in a compose file or CI, an admin can decide it all up front and hand over a single-use token.

bot.ts
import { GrytBot } from "@gryt/bot";

const bot = new GrytBot({
  host: "chat.example.com",
  nickname: "Helper",
  wants: ["read_messages", "send_messages"],
});

bot.command("ping", async (ctx) => ctx.reply("pong"));

void bot.start();

bot.can() answers from what the server said, not from what you asked for. And it keeps up if an admin changes their mind while the bot is running.

A bot runs as a container. The example below builds on its own, since @gryt/bot comes off npm like any other dependency.

compose.yml
services:
  support-bot:
    build: .
    restart: unless-stopped
    environment:
      GRYT_HOST: chat.example.com
    volumes:
      - support-bot-identity:/data

volumes:
  support-bot-identity:

gryt-bot-identity.json is the bot. The id the server knows it by comes from the key inside it. Keep that file on a volume and the bot keeps its permissions across restarts and upgrades. Lose it and the server sees a stranger knocking, holding nothing.

Mounting the volume isn’t enough by itself. By default the bot writes that file next to the code, and only the bot can move it. identityPath is an option on GrytBot, and the SDK reads no environment variables of its own. The example passes process.env.GRYT_IDENTITY_PATH, and its Dockerfile sets that to /data/gryt-bot-identity.json. Miss it and the bot works, keeps its identity across restarts, and loses it the next time you rebuild the image.