To connect Hermes Agent to Discord, create a Discord application and bot, turn on the Message Content intent, and invite the bot with the bot and applications.commands scopes. Then put the bot token in DISCORD_BOT_TOKEN and your Discord user ID in DISCORD_ALLOWED_USERS in ~/.hermes/.env, and start the messaging gateway with hermes gateway. hermes gateway setup asks for the same two values if you'd rather not edit the file.
The allowlist is not optional. Current Hermes connects to Discord without one and then refuses every message, which is the most common reason a Hermes bot shows as online and says nothing.
This guide is about Hermes Agent, the open-source agent from Nous Research (NousResearch/hermes-agent on GitHub). Unlike OpenClaw, I haven't connected Hermes to a Discord bot of my own. Everything here comes from the official docs and source as of September 27, 2026, for Hermes Agent v0.21.5 (release v2026.9.24, published September 24, 2026).
I installed that release in a sandbox, checked each command against its CLI help, and ran Hermes' own config loader and Discord authorization code on the settings below, without connecting to Discord or a model provider. The official install script pulls Hermes' main branch, so a fresh install can be newer than v0.21.5.
Before you start
- Hermes installed, with a model provider set. For a command-line install on Linux, macOS or WSL2, the docs give
curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash, with a PowerShell one-liner for native Windows and an APT package for Termux. The script needs Git and curl, and brings its own Python, Node.js, ripgrep and FFmpeg. On macOS only Apple Silicon is supported. Pick a provider withhermes model. - A machine that stays on. The gateway holds the Discord connection; when it stops, the bot goes offline.
- A Discord server where you have Manage Server. Start with a private one.
Step 1: Create the Discord application and bot
- In the Discord Developer Portal, click New Application, name it and note the Application ID on General Information.
- Open Bot and set the username.
- Decide on Public Bot. Hermes' docs recommend turning it on so the Installation tab can generate a Discord-provided invite link. Discord's docs say that with it off, "only you can add the bot to guilds." For a personal agent I'd leave it off and use the manual invite link in Step 3.
- Click Reset Token and copy the token. Store it in a password manager and never paste it into a chat, including one with the agent.
Step 2: Turn on the intents
Still on the Bot page, under Privileged Gateway Intents:
| Intent | What Hermes does with it | Setting |
|---|---|---|
| Message Content | Always requested. Without it, messages arrive with empty text | On |
| Server Members | Requested only for username allowlists or DISCORD_ALLOWED_ROLES (v0.21.5) |
On if you use either |
| Presence | Not needed | Off |
The setup steps in Hermes' docs mark Server Members as required, but its own troubleshooting section and the v0.21.5 code only ask for it in the two cases above. Discord asks developers to enable only the intents they need, so with numeric user IDs you can leave it off.
The docs also still describe Discord's old rule of free toggles below 100 servers. Since June 10, 2026, the line is 10,000 unique users who can see the app, so a personal bot can switch these on without a review.
Step 3: Invite the bot with the right permissions
Hermes' docs give two permission integers. Decoded against Discord's permission table, they contain slightly more than the docs' lists say:
| Set | Integer | What it grants |
|---|---|---|
| Hermes docs, "minimal" | 117760 |
View Channels, Send Messages, Embed Links, Attach Files, Read Message History |
| Hermes docs, "recommended" | 274878286912 |
The minimal set plus Add Reactions, Send Messages in Threads and Use External Emojis |
| What I'd use | 309237763136 |
The minimal set plus Add Reactions, Create Public Threads and Send Messages in Threads |
The difference that matters is Create Public Threads. Hermes starts a thread for every @mention in a text channel by default, and Discord's permission table lists Create Public Threads as what "allows for creating public and announcement threads." In v0.21.5, if the thread can't be created, Hermes posts "Hermes could not create a Discord thread for this message, so the request was not processed" and skips the message.
Build the link by hand with your Application ID:
Open it, pick your server and authorize. You can check any integer or invite link with the permissions calculator, and the guide to adding bots covers servers that don't show up in the list.
Then turn on Developer Mode in Discord under User Settings > Advanced, right-click your own name and choose Copy User ID. Channel and server IDs are copied the same way.
Step 4: Add the token and your user ID
The guided route is hermes gateway setup: choose Discord and paste the token and your user ID when asked.
The manual route is two lines in the .env file in Hermes' home folder:
DISCORD_BOT_TOKEN=paste-your-token-here
DISCORD_ALLOWED_USERS=284102345871466496Separate several user IDs with commas. Then start the gateway in the foreground:
The docs say the bot comes online within a few seconds. DM it to test. To keep it running, install it as a service (systemd on Linux, launchd on macOS, a scheduled task on Windows):
After you edit .env or config.yaml, run hermes gateway restart, which lets running turns finish before it restarts.
Step 5: Decide where it answers
Hermes' default behavior in Discord, from its docs:
| Where | What Hermes does |
|---|---|
| DMs | Answers every message from an allowed user. Each DM is its own session |
| Server channels | Answers only when @mentioned, and starts a thread for each mention |
| Free-response channels | Answers without a mention, inline, in channels listed in DISCORD_FREE_RESPONSE_CHANNELS |
| Shared channels | Keeps a separate session per person, so two people don't share one transcript |
To keep it to one channel on your server, add a channel allowlist next to your user ID:
DISCORD_BOT_TOKEN=paste-your-token-here
DISCORD_ALLOWED_USERS=284102345871466496
DISCORD_ALLOWED_CHANNELS=1234567890123456789
DISCORD_FREE_RESPONSE_CHANNELS=1234567890123456789Hermes now answers only you, only in that channel and in DMs, without needing an @mention there. In my test of the v0.21.5 authorization code, your ID in that channel was allowed, another user in the same channel was refused, and your ID in a different channel was refused.
The channel settings also have discord: keys in ~/.hermes/config.yaml (allowed_channels, free_response_channels), where lists are easier to read. Environment variables win when both are set. A few that are worth writing down there:
discord:
require_mention: true
ignored_channels:
- "345678901234567890" # never answer here, even when mentioned
allow_mentions:
everyone: false # the default: no @everyone or @here pings
roles: false # the default: no role pingsDM pairing instead of an allowlist
Hermes can also approve people one at a time. An unknown user who DMs the bot gets a one-time code, and you approve it on the host:
Codes expire after an hour. One detail from the v0.21.5 source: by default, pairing codes are only sent when no allowlist is configured. Once DISCORD_ALLOWED_USERS is set, a stranger's DM gets no reply. Hermes logs it and, the first time, tells your home channel if you have one.
To send codes anyway, put unauthorized_dm_behavior: pair inside the discord: section of config.yaml (under platforms: discord: works too). In my test, the same key at the top level of the file did not override the allowlist.
Keep the agent scoped
Hermes' docs are direct about the stakes: "authorized users have full access to the agent's capabilities, including tool use and system access." Treat the allowlist as the list of people you'd let use your terminal.
- Always set users or roles. Since v0.18 Hermes denies everyone when no allowlist is configured. Keep it that way, and don't use
DISCORD_ALLOW_ALL_USERS=trueorGATEWAY_ALLOW_ALL_USERS=trueoutside a private test server. - Don't rely on a channel list alone.
DISCORD_ALLOWED_CHANNELSwithout a user or role list lets anyone in those channels use the agent. In my test, a stranger in an allowed channel was accepted. Pair it withDISCORD_ALLOWED_USERSorDISCORD_ALLOWED_ROLES. - Use roles for teams.
DISCORD_ALLOWED_ROLEStakes role IDs and works alongside the user list. - Split admins from users.
allow_admin_fromanduser_allowed_commandsundergateway.platforms.discord.extralimit which slash commands non-admins can run./whoamishows each person their tier. - Leave the safe defaults on. The bot can't ping @everyone, @here or roles, and ignores other bots (
DISCORD_ALLOW_BOTS=none). - Discord side: no Administrator permission, and Public Bot off if only you should add it.
Troubleshooting Hermes Agent on Discord
| What you see | Likely cause | Where to look |
|---|---|---|
| Online, never answers | No allowlist, Message Content off, or no @mention | Silent |
PrivilegedIntentsRequired at startup |
An intent is off in the portal | Intents |
| Shows as offline | Gateway stopped, token rejected, adapter paused | Offline |
| "This bot is private and you're not on its allowed list" | Your ID isn't allowed | Not allowed |
| Every reply arrives twice | Two gateways on one token | Duplicates |
Online, but not responding
- No allowlist. v0.21.5 logs
Discord messages are being denied because no allowlist is configuredto~/.hermes/logs/gateway.log. SetDISCORD_ALLOWED_USERSand restart. - Message Content is off. Messages arrive with empty text. Turn it on, save and run
hermes gateway restart. - You didn't @mention it in a normal channel. With
DISCORD_IGNORE_NO_MENTIONon (the default), a message that mentions someone else but not the bot is also ignored. - The channel is filtered. It isn't in
DISCORD_ALLOWED_CHANNELS, or it is inDISCORD_IGNORED_CHANNELS, which wins over everything. - The bot can't see the channel. Give its role View Channel and Read Message History there.
- It says it couldn't create a thread. Add Create Public Threads, or set
DISCORD_AUTO_THREAD=false.
PrivilegedIntentsRequired (close code 4014)
Discord closes the connection with code 4014 when a bot asks for a privileged intent that isn't switched on. Hermes prints which intents it requested and a link to the fix. Turn them on under Bot > Privileged Gateway Intents, save, and run hermes gateway restart. The docs put it plainly: this is "a portal configuration error, not a flaky network issue." The general 4014 section explains the error for any bot.
The bot is offline
- The gateway isn't running. Check
hermes gateway statusand start it. - The token was rejected. Hermes reports
Discord bot token rejectedand tells you to regenerate it. Reset it in the portal, updateDISCORD_BOT_TOKENand restart. - The adapter was paused. Repeated failures, such as network errors, rate-limit replies or disconnects, trip a circuit breaker that pauses Discord and does not resume by itself. Run
/platform listfrom a Hermes CLI session or another connected chat; if Discord showspaused-by-breaker, check Discord's status page, then run/platform resume discord. - A proxy is in the way. Set
DISCORD_PROXY(http, https or socks5) if you need one. If the service inherits a proxy you don't want, setgateway.trust_env: falseinconfig.yaml.
"This bot is private and you're not on its allowed list"
That is the private reply Hermes v0.21.5 sends when someone who isn't allowed uses a slash command, and the docs' "User not allowed" case. Add the user's ID to DISCORD_ALLOWED_USERS, give them an allowed role, or approve them through pairing, then restart the gateway.
Replies twice, or slash commands keep changing
Two Hermes gateways are running on the same bot token, for example a service plus a copy started by hand, and both answer. hermes gateway status shows the running service, and hermes gateway run refuses to start a second copy next to a service unless you pass --force. If you deliberately run two gateways on one application, the docs say only one should register slash commands: set slash_commands: false under gateway.platforms.discord.extra on the other.
OpenClaw or Hermes on Discord?
Both are self-hosted agents that reach you through a Discord bot you create, and the Discord side (application, token, intents, invite) is identical. They differ in their defaults:
| Hermes Agent | OpenClaw | |
|---|---|---|
| Discord support | Bundled with Hermes | Official plugin, @openclaw/discord |
| Where settings live | ~/.hermes/.env and config.yaml |
OpenClaw's JSON5 config under channels.discord |
| Unknown DMs | Denied; pairing codes only without an allowlist | Pairing code by default |
| Servers | Allowed users can @mention it in any channel it can see | Ignored until you allowlist the server |
The OpenClaw guide covers its setup and the errors people search for.
If you want a bot for your community
A personal agent with tools is the wrong shape for answering a community: every member who can reach it can try to steer it. For that job I build Discord AI support bots that answer only from your docs, link their sources and hand off to staff when unsure, on your own bot application and model key. Most land in the Community tier from $1,490, with hosting on Care at $49 a month. Send me a short brief and I'll reply with questions or a fixed quote.