STYGION Documentation Search the docs

Discord

Chat both ways, accounts verified from a code typed in game, roles and bans held in step, and the console mirrored where you can read it.

Keystone 0.2.8 Updated 5 min read

This page is older than Keystone 0.2.8, released 18 October 2026. Something may have changed since.

On this page 8 parts
  1. Getting it talking
  2. Chat
  3. Linking an account
  4. Roles and bans, held in step
  5. The console, where you can read it
  6. Alerts
  7. The "is this you?" question
  8. Tickets on Discord

Discord

Everything here is discord.toml, or the Settings screen in the panel.

Getting it talking

#
  1. Make a bot at discord.com/developers, and give it the Message Content and Server Members intents — without the first one the bot sees empty messages and nothing comes back to the game.
  2. /keystone set discord.token <token> and /keystone set discord.server <server id>.
  3. /keystone set discord.chat-channel <channel id> — the room the game talks to.
  4. Invite it with permission to read, send and manage webhooks in that channel.

The token is a secret and Keystone masks the command that sets it out of logs and consoles. It is still written into discord.toml, so that file is not something to publish.

Chat

#
Setting What it does
game-to-discord What is said in game appears on Discord.
discord-to-game And the other way.
speak-as-players Each player speaks under their own name and face, through a webhook, rather than everything arriving as the bot.
avatar Where a face comes from. Defaults to a public head renderer, keyed by name.
joins-and-leaves Arrivals and departures too.
topic / topic-every The channel topic carries who is on, refreshed on a timer.
queue How many messages to hold when Discord is unreachable, so an outage does not lose the conversation.

With chat channels on (0.2.1), each game channel may have its own Discord room (discord=<channel id>, or discord=main for chat-channel): a line goes only to its channel's room, and a message from a room only into its channel, to the players who may read it. A channel without a room never leaves the game. Invite the bot to every room you name, with permission to read, send and manage webhooks.

Linking an account

#

In game:

Code
/discord link      # hands you a code
/discord status    # whether you are linked, and to whom
/discord unlink    # undo it

Then /link <code> on Discord — as a slash command, so the code never becomes a message anybody has to delete, and the reply is visible only to them. No website, no email.

Or a button, in a room nobody can write in (0.2.1). /discord panel <channel-id> (keystone.discord.panel, staff) posts a panel into a Discord channel with a Link account button. The button opens a form that only the person who pressed it sees; the code typed into it is spent exactly like /link — the same checks, the same answer, the same limit of accounts. Make that channel read-only for everybody: Discord takes slash commands away with Send Messages, and a code pasted as a plain message can be read by anybody until somebody deletes it. The button's id is fixed (keystone:link), so a panel posted by other tooling under the same bot works too. /link stays for rooms people can write in.

  • link.required-to-join turns it into a gate: an unlinked player is shown the screens.not-linked message with their code, their invite link and how long the code lasts, and is not let in until they have done it.
  • link.accounts-per-user is how many game accounts one Discord user may hold.
  • link.rename-nickname renames them on Discord to the name they play under.
  • link.code-lasts is how long a code is worth typing.
  • link.invite is the invite that screen shows.

And what it is worth outside the game: on a server that is not in online mode, a link is the only proof of identity there is — it was made from inside the game under that name and confirmed by an account the game does not hand out. So it can be asked about over the API: GET /v1/discord/links?discord=<id> with the players.read scope says which game accounts that person holds. That is how a shop learns who to deliver a purchase to, rather than believing a name typed into a form.

Roles and bans, held in step

#
  • roles.follow pairs a Discord role with a Keystone group, in both directions: give somebody the role and they get the group.
  • ban.game-to-discord and ban.discord-to-game carry a ban across. Turned off by default, because it is a decision, not a convenience — and ban.who-may says whose bans on Discord are allowed to reach the game. See moderation.

The console, where you can read it

#

console.channel mirrors the server's log into a Discord room, batched every console.every so a busy server is readable rather than a firehose. console.levels picks what is worth mirroring and console.ignoring drops the lines you are tired of. console.most-lines caps a single batch.

Anybody who can read that room can read your server's log. Put it somewhere only your team can see.

Alerts

#

alerts.channel is where Keystone says something is wrong — TPS under operations.alerts.tps-below, memory over operations.alerts.memory-above-percent, sustained for must-last and then quiet for quiet-for so one bad minute does not become forty messages. alerts.ping-role is who gets woken up. alerts.runs-channel is where finished load tests land.

The server's state. status-channel says that the server is up, is going down, or will restart in so many minutes (once per restart, not at every warning). By default ("chat") it goes to the chat channel, where the players are; a channel id sends it elsewhere and blank nowhere. The lines are language keys (discord.news.up, .down and .restart) a server can reword. news-channel is no longer read — a news channel is for news.

The list of channels and roles is read at most once per half minute (discord.names-every), so changing ten channels does not spend Discord's ten-a-minute budget shared with everything else the same bot does.

The "is this you?" question

#

With accounts.ask-on-discord on, a linked player gets a direct message when somebody joins under their name — who, from where, two buttons. In detail on the accounts page.

Tickets on Discord

#

tickets.category and tickets.roles put private ticket channels in a category and give your staff roles access. The rest is on the tickets page.

Did this page help?

Opens the feedback panel with this page attached. It lands in the same queue as everything else.