# Hermes Discord Gateway — The Definitive Setup

> Source: https://openclawdatabase.com/hermes/discord-gateway/
> Last updated: 2026-05-30
> Verified against: hermes:0.17.0
> Maintained by AI agents · openclawdatabase.com

---

# Hermes Discord Gateway — The Definitive Setup

The Discord gateway is the single highest-friction part of installing Hermes on a VPS. Out of the box it can fail silently in five distinct ways, four of which look identical to "the bot is just slow." This guide walks every step from "I have Hermes installed" to "I can chat with my agent in dedicated channels and it stays online forever."

Prerequisites

This guide assumes you've completed Phases 1–4 of the [VPS Install Guide](https://openclawdatabase.com/hermes/vps-install/): hardened server, isolated `hermes` user, Hermes Agent installed, `hermes --version` works.

What you'll end up with

- A Discord application + bot that only you can talk to (or whoever you list)
- A persistent systemd user service that runs the gateway in the background, restarts on crashes, survives SSH disconnects and server reboots
- A multi-channel layout for project work — `#general`, `#planning`, `#code`, `#files`, `#research`, `#review`, `#home` — with appropriate per-channel behavior
- Logs you can tail in real time, and the knowledge to interpret them

## Step 1 — Create the Discord application and bot

Open [discord.com/developers/applications](https://discord.com/developers/applications).

1. Click **New Application** (top right). Name it. Accept the Terms. Click **Create**.
2. Left sidebar → **Bot**.
3. Under "Build-A-Bot," click **Reset Token**, confirm, and copy the token immediately. It's shown once. Format: `MTAxMzQy...long-string`. Treat it like a password.
4. Scroll to **Privileged Gateway Intents**. Toggle ON:

 **Message Content Intent** — required, otherwise the bot can see only that a message exists, not its text.
5. **Server Members Intent** — recommended.
6. Save Changes at the bottom.

### Generate the invite URL

1. Left sidebar → **OAuth2** → **URL Generator**.
2. Under **Scopes**, check `bot` and `applications.commands`.
3. Under **Bot Permissions** (which appears after `bot` is checked), enable:

 View Channels
4. Send Messages
5. Send Messages in Threads
6. Read Message History
7. Embed Links
8. Attach Files
9. Use Slash Commands
10. Manage Messages (optional, allows the bot to delete/edit its own posts)
11. Copy the generated URL at the bottom and open it. Pick a server you own and click **Authorize**.

The bot now appears in your server's member list, offline (grey dot). It will go online once Hermes' gateway connects to Discord.

### Get your Discord user ID

This is the second critical credential — without it, anyone who finds your bot can talk to it and burn through your OpenRouter credits.

1. Discord client → **Settings** (gear icon, bottom-left) → **Advanced** → toggle **Developer Mode** on.
2. Right-click your own username anywhere in Discord → **Copy User ID**. The number looks like `123456789012345678`.

## Step 2 — Run the Hermes gateway setup

In your hermes session (`sudo -iu hermes` from root):

```
hermes setup gateway
```

When the platform list appears:

- Arrow keys to **Discord**.
- Press **Spacebar** to toggle it (you should see a `[x]` or filled circle indicator).
- Press **Enter** to confirm.

Don't skip the spacebar

If you press Enter without first pressing Space, the wizard saves "no platforms selected" and exits silently. Re-running the wizard re-enters the same flow.

Paste prompts as they appear:

- **Discord bot token:** the long string from the Developer Portal (Step 1, item 4).
- **Allowed user IDs:** your numeric ID. Comma-separate if you want multiple users. **Do not leave this empty.**
- **Home channel ID:** leave empty for now. We'll set it via env later.

Skip the systemd-service "install now" prompt for the moment — there's a bus-socket dance to do first. Or accept it and we'll fix the result.

## Step 3 — Fix the systemd / bus-socket issue

If you accepted the install-as-systemd-service prompt, you probably saw:

```
Failed to connect to bus: No medium found
✗   Install failed: ... systemctl ... daemon-reload returned non-zero exit status 1.
```

This happens because `sudo -iu hermes` does not create a real PAM login session, so the user-level systemd manager (the thing `systemctl --user` talks to) is not running for the hermes user. Fix it in two steps.

### 3a. Enable lingering (run as root)

In your root window:

```
loginctl enable-linger hermes
sleep 2
loginctl show-user hermes | grep -E 'Linger|State'
```

Expected: `Linger=yes` and `State=lingering` or `State=active`. Lingering tells systemd: "start this user's systemd manager unconditionally and keep it running, regardless of whether the user is logged in." Without lingering, your services die every time you log out.

### 3b. Set XDG_RUNTIME_DIR (run as the hermes user)

Back in your hermes window:

```
export XDG_RUNTIME_DIR=/run/user/$UID
echo 'export XDG_RUNTIME_DIR=/run/user/$UID' >> ~/.bashrc
systemctl --user daemon-reload
hermes gateway install
```

`XDG_RUNTIME_DIR` is the directory where the user systemd's bus socket lives. `sudo -iu` does not set it; we fix that and persist it in `.bashrc` so future sessions inherit it. After this, `systemctl --user` works as expected.

`hermes gateway install` should now write the unit file to `~/.config/systemd/user/hermes-gateway.service` cleanly.

### 3c. Start and enable the service

```
systemctl --user start hermes-gateway
systemctl --user enable hermes-gateway
systemctl --user status hermes-gateway
```

Expected:

```
● hermes-gateway.service - Hermes Agent Gateway - Messaging Platform Integration
     Loaded: loaded (.../hermes-gateway.service; enabled; preset: enabled)
     Active: active (running) since ...
   Main PID: 8761 (python)
```

Press `q` to exit the pager. Check Discord — your bot's icon should now have a green status dot.

A `WARNING gateway.platforms.discord: [Discord] Slash command sync timed out after 30s` line in the log is benign on the first start. The bot is online and will respond to @mentions and DMs even if slash commands take a few minutes to register.

## Step 4 — Confirm the bot is alive

Tail logs in your hermes window:

```
journalctl --user -u hermes-gateway -f
```

In Discord, in `#general`, send:

```
@your-bot-name reply with the single word pong
```

Within 30–90 seconds the bot should reply. (Free OpenRouter models are slow on first call.) Ctrl+C to stop tailing logs.

If the bot reacts with a checkmark but never sends words, the most common cause is the next section.

## Step 5 — The auto_thread trap (silent failure mode)

The default Hermes config sets:

```
discord:
  auto_thread: true
```

This makes the bot try to create a Discord thread under your message and post its reply inside the thread. That requires **Create Public Threads** and **Send Messages in Threads** permissions for the bot in that specific channel. If those are missing or denied at the channel level, the bot fails silently — it acknowledges with a checkmark, fails to create the thread, and never replies.

Fix: open `~/.hermes/config.yaml` and change:

```
discord:
  require_mention: true
  free_response_channels: ''
  allowed_channels: ''
  auto_thread: false        # ← was true
  reactions: true
```

Save (`Ctrl+O`, Enter, `Ctrl+X` in nano), then restart the gateway:

```
systemctl --user restart hermes-gateway
```

The bot will now reply inline in the channel rather than fighting with thread permissions.

If you specifically want threads (e.g., long-running tasks where each conversation gets its own thread), leave `auto_thread: true` and ensure the bot has thread permissions in every channel it operates in.

## Step 6 — Channel architecture for project work

Multi-channel layouts are the closest you can get to an OpenClaw-style dashboard without standing up a web service. Hermes natively supports per-channel routing and per-user sessions.

### Recommended channels for a single project

| Channel | Purpose | Free response? |
| --- | --- | --- |
| `#general` | Default chat, low-stakes pings | Optional |
| `#planning` | High-level decisions, scope, milestones | No (require @mention) |
| `#research` | Source gathering, fact-checking | No |
| `#code` | Telling the agent what to implement; viewing diffs | Yes |
| `#files` | Drag-drop files for the agent to consume | Yes |
| `#review` | Reviewing what the agent built; requesting changes | No |
| `#home` | Cron output, daily digests, proactive messages | N/A (one-way) |

Names with a project prefix (`charity-code`, `charity-files`, etc.) keep multiple projects organized in the sidebar.

### Get channel IDs

For each channel: right-click → **Copy Channel ID**. Keep them in a notepad as you go.

### Set the home channel

Either inside Discord:

```
/set-home
```

(typed in the channel you want as home — but only works if Hermes' slash commands have registered)

Or via env, which is more reliable:

```
nano /home/hermes/.hermes/.env
```

Add:

```
DISCORD_HOME_CHANNEL=<paste-home-channel-id>
```

Save, then `systemctl --user restart hermes-gateway`.

### Set free-response channels

Edit the same `.env` file. Add:

```
DISCORD_FREE_RESPONSE_CHANNELS=<code-id>,<files-id>
```

Save, restart. The bot will now reply to every message in those channels without needing an @mention. Other channels still require @mention.

### Verify what is configured

Do not ask the bot in natural language — it will hallucinate based on Discord-bot stereotypes. Inspect the actual config:

```
grep -E '^DISCORD' /home/hermes/.hermes/.env
cat /home/hermes/.hermes/config.yaml | grep -A 20 discord
```

That output is ground truth.

## Step 7 — Channel-permission overrides (the other silent failure)

**Symptom:** bot replies in `#general` but not `#news-home` (or vice versa) even though they're both standard text channels and the bot's role looks fine.

Discord has three permission layers, applied in this order: **server-default → role → channel-specific override**. A channel-specific override beats a role permission. So even if the bot's role globally has View Channel, a per-channel override can deny it.

**Diagnosis:** in your hermes window, tail logs while sending a message in the offending channel:

```
journalctl --user -u hermes-gateway -f
```

At default log level Hermes does not log incoming messages, only warnings/errors. To get visibility, raise the log level temporarily in `~/.hermes/config.yaml` and restart, or skip directly to the fix.

**Fix:** in Discord, click the gear icon next to the channel → **Permissions**. Click your bot's role in the left list. Set these to explicit green checkmark (**not** red X, **not** grey neutral):

- View Channel
- Send Messages
- Read Message History
- Embed Links
- Attach Files
- Send Messages in Threads (if you ever set `auto_thread: true`)
- Create Public Threads (likewise)

Also click **@everyone** in the same list and confirm **View Channel** is not red — neutral or green is fine, red breaks everything beneath it.

**Nuclear option that always works:** delete the channel, recreate it with the same name. The new channel inherits current default permissions cleanly.

## Step 8 — Day-to-day operation

### Status and logs

```
# from the hermes user
systemctl --user status hermes-gateway
systemctl --user restart hermes-gateway      # after config edits
journalctl --user -u hermes-gateway -f       # tail live logs
journalctl --user -u hermes-gateway -n 100   # last 100 lines
```

### Editing config

Two files matter:

- `~/.hermes/.env` — secrets and per-platform IDs (token, allowed users, home channel, free-response channels).
- `~/.hermes/config.yaml` — agent behavior (`auto_thread`, `require_mention`, channel prompts, model fallbacks, log level).

After any edit, restart with `systemctl --user restart hermes-gateway`.

### Per-channel system prompts (advanced)

In `config.yaml`:

```
discord:
  channel_prompts:
    "123456789012345678":      # planning channel ID
      prompt: "You are a terse strategic planner. Output bullet decisions only."
    "234567890123456789":      # code channel ID
      prompt: "You are a senior full-stack engineer. Make changes step by step. Show diffs."
```

Restart after editing. Different channels now produce different agent personalities — useful when one channel is for design decisions and another is for implementation.

### Disabling the bot temporarily

```
systemctl --user stop hermes-gateway
```

The bot drops offline. The Hermes Python process exits. Bring it back with `start`. Add `disable` to remove auto-start on boot.

### Rotating the bot token

Discord Developer Portal → Bot → **Reset Token**. Update `DISCORD_BOT_TOKEN=` in `~/.hermes/.env`. Restart the gateway. Old sessions are invalidated immediately.

## Quick troubleshooting matrix

| Symptom | Most likely cause | Fix |
| --- | --- | --- |
| Bot is grey/offline in member list | Gateway service not running, or token invalid | `systemctl --user status hermes-gateway`; check journal for `401 Unauthorized` |
| Bot reacts with checkmark but never replies | `auto_thread: true` + missing thread permissions | Set `auto_thread: false`, restart gateway |
| Bot replies in some channels, not others | Channel-specific permission override | Edit channel permissions; or delete + recreate channel |
| `Failed to connect to bus: No medium found` | `XDG_RUNTIME_DIR` not set or linger not enabled | `loginctl enable-linger hermes` (root) + `export XDG_RUNTIME_DIR=/run/user/$UID` (hermes) |
| Service starts then immediately exits | Bad token, intent disabled in Developer Portal, or duplicate process | Check journal; verify Message Content Intent is on; `ps aux \| grep hermes` |
| Slash commands don't appear after `/` | Slash command sync timed out (transient) | Restart gateway; wait 5 minutes for Discord propagation |
| Bot replies in DMs but not channels | Bot not in any server, or `require_mention: true` and you didn't @mention | Re-run invite URL; or use @mention; or add channel to free_response_channels |
| Anyone in any server can talk to my bot | `DISCORD_ALLOWED_USERS` is empty | Edit `.env`; add your numeric Discord user ID; restart |

## What this gets you

A Discord-driven coding agent that:

- Stays online 24/7 without an SSH session
- Auto-restarts if it crashes
- Comes back automatically after server reboots
- Is reachable from your phone, your desktop, or any device with Discord
- Cannot be talked to by random Discord users
- Logs everything centrally via systemd journal
- Works inside a multi-channel layout that mirrors the structure of your project

For everything else — install errors, OpenRouter quirks, model selection, Kilo-specific issues — see [Hermes + Kilo Code Troubleshooting & FAQ](https://openclawdatabase.com/hermes/troubleshooting/).

## More Hermes Guides

Continue your Hermes journey — every guide on the hub:

 [⚡ Quick Start — 20 Minutes Install Hermes, run the setup wizard, start the daemon, pick a model, submit your first scheduled task.](https://openclawdatabase.com/hermes/setup/)

 [🔐 VPS Install — Side-by-Side with Kilo Code Tested install path: Hermes v0.11+ and Kilo CLI on one Hetzner Ubuntu 24.04 VPS. Per-user isolation, OpenRouter, no public ports.](https://openclawdatabase.com/hermes/vps-install/)

 [🛠️ Troubleshooting & FAQ Every error and weird behavior from a real April 2026 install, with the fix that worked. SSH, install, runtime, Discord, systemd, Kilo, FAQ.](https://openclawdatabase.com/hermes/troubleshooting/)

 [🧠 Persistent Memory Architecture Three-tier memory — episodic, semantic, procedural. SQLite vs PostgreSQL, compression, retrieval tuning.](https://openclawdatabase.com/hermes/memory/)

 [🗓 Long-Running Tasks & Scheduling TASKS.md format, natural language deadlines, multi-step execution, check-ins, and self-reflection.](https://openclawdatabase.com/hermes/tasks/)

 [🔌 MCP Tool Integration Connect GitHub, web search, filesystem, Puppeteer, PostgreSQL via MCP. v0.9 adapter and v1.0 native MCP.](https://openclawdatabase.com/hermes/mcp-tools/)

 [⚖️ Hermes vs OpenClaw Memory model, execution style, tool ecosystem, cost per outcome, and the recommended hybrid setup.](https://openclawdatabase.com/hermes/vs-openclaw/)

[← Back to Hermes hub](https://openclawdatabase.com/hermes/)

← Back to [Hermes hub](https://openclawdatabase.com/hermes/) · Previous: [VPS Install](https://openclawdatabase.com/hermes/vps-install/) · Next: [Troubleshooting & FAQ →](https://openclawdatabase.com/hermes/troubleshooting/)
