Appearance
Gateway Architecture
When Hermes runs in the terminal, it lives as long as your shell session does. Close the terminal, Hermes dies. That's fine for interactive work. It's not fine for an agent you want to reach from your phone at 11 PM when a deployment goes sideways. The gateway is the bridge between Hermes's agent core and the messaging platforms you already use, and it needs to run as a persistent service, not a terminal-bound process.
This lesson covers how the gateway fits into Hermes, what makes it survive restarts, and the decisions you make before connecting any platform. No bot tokens yet, that starts in the next lesson. This is the architecture you need to understand first.

What you'll learn
- The gateway is a single process that connects one agent core to multiple messaging platforms simultaneously, Telegram, Discord, Slack, and 20+ others all share the same configuration and session state
- On Linux and WSL2, the gateway runs as a systemd user service; without systemd, it falls back to
nohupand dies when the session closes - Gateway logs live at
~/.hermes/logs/gateway.log, this is where you go first when something isn't working, before changing any configuration - Per-platform tool controls (
hermes tools) let you disable dangerous tools on public-facing platforms while keeping them available on trusted channels
The problem: agents die with your terminal
You've been running Hermes interactively. hermes starts the CLI, you chat, you quit. The process stops. That works for a development machine where you're sitting in front of the keyboard. It breaks down the moment you want Hermes to be reachable when you're not actively connected.
The fundamental requirement for any gateway is durability. The process needs to:
- Survive SSH logout (Linux servers)
- Survive terminal window close (WSL2)
- Auto-restart if it crashes
- Start when the machine boots
Hermes solves this with systemd user services on Linux and WSL2. On macOS, it uses launchd. On Windows native, it runs as a scheduled task. The setup command handles the platform differences; you need to understand which one applies to your environment and what can go wrong.
Options & when to use each
| Gateway setup | What it does | Costs you | When to pick it |
|---|---|---|---|
hermes gateway install | Creates a systemd user service (Linux/WSL2) or launchd plist (macOS) | Requires systemd on Linux, WSL2 needs systemd=true in /etc/wsl.conf | Production servers, always-on agents, any machine where the gateway should survive restarts |
hermes gateway run | Runs the gateway in the foreground | Dies when the terminal closes, temporary only | Testing configuration changes, debugging a platform adapter, one-off gateways |
hermes gateway setup | Interactive wizard to configure platforms | None, walks you through the options | First-time setup, adding a new platform to an existing gateway |
hermes gateway start/stop/restart/status | Controls the systemd service | Requires the service to be installed first | Day-to-day operations after initial setup |
If you're on WSL2, the systemd requirement is the most common gotcha. Open /etc/wsl.conf and make sure it contains:
ini
[boot]
systemd=trueWithout this, WSL2 doesn't run systemd at all, and the gateway service install will fail or fall back to nohup (which dies when you close the WSL window). If you change this setting, restart WSL from PowerShell:
powershell
wsl --shutdownThen reopen your WSL terminal.
On a remote Linux server accessed via SSH, there's another requirement. Even with systemd running, user services are killed when the user's last session ends unless lingering is enabled:
bash
sudo loginctl enable-linger $USERThis tells systemd to keep your user services running after you log out. Skip this step, and your gateway will die the moment your SSH connection drops.
Build it
Step 1: Check your environment
Before installing the gateway, verify your system supports user services. Check if systemd is running and whether lingering is enabled for your user account.
bash
# Are you on systemd?
pidof systemd && echo "systemd is running" || echo "no systemd"
# If on WSL2, check wsl.conf
cat /etc/wsl.conf | grep -A2 "\[boot\]"
# If on a remote server, check linger status
loginctl show-user $USER | grep LingerIf systemd isn't running on WSL2, fix /etc/wsl.conf with the systemd=true block and restart WSL. If linger shows Linger=no on a server, run sudo loginctl enable-linger $USER.
Step 2: Install the gateway service
Install the gateway as a systemd user service. This registers the service definition in your local configuration directory.
bash
hermes gateway installThis creates a systemd user service called hermes-gateway. The service file lives under ~/.config/systemd/user/hermes-gateway.service. You can inspect it to verify the command it runs:
bash
systemctl --user cat hermes-gatewayStep 3: Start the gateway
Start the newly created service. If it fails to start, check the gateway logs for configuration errors.
bash
hermes gateway startCheck that it actually started:
bash
hermes gateway statusThe status output should show active (running). If it shows failed or inactive, check the logs:
bash
tail -50 ~/.hermes/logs/gateway.logStep 4: Verify it survives a restart
Test the service's durability by restarting it. A successful restart confirms the unit file is correctly configured and the gateway can recover from a crash.
bash
hermes gateway restart
hermes gateway status # Should show active againIf the restart works, the service is installed correctly. If it fails on restart, the most likely cause is a configuration error, the service file is fine, but Hermes can't start because of a bad platform config. The gateway log will tell you which platform failed to initialize.
Step 5: Enable auto-start on boot
Configure the service to start automatically when the system boots. This ensures the gateway comes online without requiring a manual login.
bash
systemctl --user enable hermes-gatewayThis starts the gateway automatically when the machine boots, before you even log in. Combined with linger, this means the gateway runs whenever the machine is on, regardless of who's logged in.
What goes wrong
| Mistake | How you notice it | The fix |
|---|---|---|
| Gateway dies on SSH logout | hermes gateway status shows inactive after you reconnect | sudo loginctl enable-linger $USER , user services are killed when the last session ends unless lingering is enabled |
| Gateway won't start on WSL2 | hermes gateway install succeeds but start fails, logs show systemd errors | Add systemd=true to /etc/wsl.conf under [boot], then run wsl --shutdown from PowerShell and reopen WSL |
| Gateway crashes on restart after config change | hermes gateway restart produces a failed status | Check ~/.hermes/logs/gateway.log , a bad platform config (wrong token, missing intent) will crash the entire gateway, not just that platform |
| Can't enable the service at boot | systemctl --user enable fails with "no graphical session" | On headless servers, you may need to set XDG_RUNTIME_DIR manually. Most installs handle this, but if it fails: export XDG_RUNTIME_DIR=/run/user/$(id -u) |
| Multiple gateway processes running | Logs show "address already in use" errors | Stop all instances: hermes gateway stop, verify with `ps aux |
Confirm it worked
Verify the installation by checking the service state and inspecting the startup logs. Run the following checks to ensure the gateway is active and auto-start is properly configured.
bash
# 1. Verify the service is running
hermes gateway status
# 2. Check the log for startup messages
grep "gateway.*started\|listening" ~/.hermes/logs/gateway.log | tail -5
# 3. Test durability
hermes gateway restart && sleep 2 && hermes gateway status
# 4. Verify auto-start is enabled
systemctl --user is-enabled hermes-gatewayIf step 1 shows active (running), step 3 returns active after a restart, and step 4 prints enabled, the gateway service is working. Step 2 will show startup messages confirming the gateway is listening, but no platforms are connected yet. That's what the next lessons are for.
Next: Telegram Setup , register a bot, connect it to the gateway, and send your first command from your phone.