Skip to main content
HERMES DOCUMENTATIONDOCS / CURRENT

Running Many Gateways at Once

Operate multiple profiles — each with its own bot tokens, sessions, and memory — as managed services on a single machine. This page covers the operational concerns: starting them all together, viewing logs across profiles, preventing the host from sleeping, and recovering from common launchd/systemd quirks.

If you only run one Hermes agent, you don't need this page — see Profiles for the basics.

When to use this​

You want this setup when you have two or more Hermes agents that should all be online at the same time. Common reasons:

  • A personal assistant on one Telegram bot and a coding agent on another
  • One agent per family member or one per Slack workspace
  • Sandbox + production instances of the same configuration
  • A research agent + a writing agent + a cron-driven bot — each with isolated memory and skills

Every profile already gets its own per-platform LaunchAgent (ai.hermes.gateway-<name>.plist) or systemd user service (hermes-gateway-<name>.service). This guide adds the patterns for managing them collectively.

Quick start​

# Create profiles (once)
hermes profile create coder
hermes profile create personal-bot
hermes profile create research

# Configure each
coder setup
personal-bot setup
research setup

# Install each gateway as a managed service
coder gateway install
personal-bot gateway install
research gateway install

# Start them all
coder gateway start
personal-bot gateway start
research gateway start

That's it — three independent agents, each on its own process, restarting automatically on crash and on user login.

Start, stop, or restart all gateways at once​

The CLI ships with single-profile lifecycle commands. To act across every profile, wrap them in a shell loop. Put the snippet below in ~/.local/bin/hermes-gateways and chmod +x it:

#!/bin/sh
set -eu

# Add or remove profile names here as you create / delete profiles.
profiles="default coder personal-bot research"

usage() {
echo "Usage: hermes-gateways {start|stop|restart|status|list}"
}

run_for_profile() {
profile="$1"
action="$2"
if [ "$profile" = "default" ]; then
hermes gateway "$action"
else
hermes -p "$profile" gateway "$action"
fi
}

action="${1:-}"
case "$action" in
start|stop|restart|status)
for profile in $profiles; do
echo "==> $action $profile"
run_for_profile "$profile" "$action"
done
;;
list)
hermes gateway list
;;
*)
usage
exit 2
;;
esac

Then:

hermes-gateways start      # start every configured profile
hermes-gateways stop # stop every configured profile
hermes-gateways restart # restart all
hermes-gateways status # status across all
hermes-gateways list # delegates to `hermes gateway list`
tip

The default profile is targeted with hermes gateway <action> (no -p), not hermes -p default gateway <action>. The wrapper above handles both forms.

Manage one profile​

The shortcut commands every profile installs:

coder gateway run        # foreground (Ctrl-C to stop)
coder gateway start # start the managed service
coder gateway stop # stop the managed service
coder gateway restart # restart
coder gateway status # status
coder gateway install # create the LaunchAgent / systemd unit
coder gateway uninstall # remove the service file

These are equivalent to hermes -p coder gateway <action> — useful if a profile alias is not on PATH or if you target profiles dynamically from a script.

Service files​

Each profile installs its own service with a unique name, so installations never clash:

PlatformPath
macOS~/Library/LaunchAgents/ai.hermes.gateway-<profile>.plist
Linux~/.config/systemd/user/hermes-gateway-<profile>.service

The default profile keeps the historical names: ai.hermes.gateway.plist / hermes-gateway.service.

Viewing logs​

Each profile writes to its own log files:

# Default profile
tail -f ~/.hermes/logs/gateway.log
tail -f ~/.hermes/logs/gateway.error.log

# Named profile
tail -f ~/.hermes/profiles/<name>/logs/gateway.log
tail -f ~/.hermes/profiles/<name>/logs/gateway.error.log

Stream every profile's log simultaneously:

tail -f ~/.hermes/logs/gateway.log ~/.hermes/profiles/*/logs/gateway.log

The CLI also has a structured log viewer:

hermes logs -f                  # follow default profile
hermes -p coder logs -f # follow one profile
hermes logs --help # filters, levels, JSON output

Identify what's actually running​

hermes profile list             # profiles + model + gateway state
hermes-gateways status # full status across every profile
launchctl list | grep hermes # macOS — PIDs and labels
systemctl --user list-units 'hermes-gateway-*' # Linux — units

Editing configuration​

Every profile keeps its config inside its own directory:

~/.hermes/profiles/<name>/
├── .env # API keys, bot tokens (chmod 600)
├── config.yaml # model, provider, toolsets, gateway settings
└── SOUL.md # personality / system prompt

The default profile uses ~/.hermes/ directly with the same three files.

Edit them with any editor or via the CLI:

hermes config set model.model anthropic/claude-sonnet-4    # default profile
coder config set model.model openai/gpt-5 # named profile

After editing .env or config.yaml, restart the affected gateway:

coder gateway restart
# or, for everything:
hermes-gateways restart

Keeping the host awake​

The gateway process can run all day, but the operating system will still try to sleep when idle. Two patterns:

macOS — caffeinate​

caffeinate is built into macOS and prevents sleep while it runs. No install.

caffeinate -dis                    # block display, idle, and system sleep
caffeinate -dis -t 28800 # same, auto-exit after 8 hours
caffeinate -i -w $(cat ~/.hermes/gateway.pid) & # awake while default gateway runs

# Persistent: run in background and forget
nohup caffeinate -dis >/dev/null 2>&1 &
disown

# Inspect / stop
pmset -g assertions | grep -iE 'caffeinate|prevent|user is active'
pkill caffeinate
FlagEffect
-dblock display sleep
-iblock idle system sleep (default)
-mblock disk sleep
-sblock system sleep (AC-powered Macs only)
-usimulate user activity (prevents screen lock)
-t Nauto-exit after N seconds
-w Pexit when PID P exits
Lid-close still sleeps the Mac

caffeinate cannot override the hardware-driven lid-close sleep on MacBooks. For lid-closed operation, change your Energy Saver / Battery preferences or use a third-party tool.

Linux — systemd-inhibit or loginctl​

# Inhibit suspend while a command runs
systemd-inhibit --what=idle:sleep --who=hermes --why="gateways running" \
sleep infinity &

# Allow user services to keep running after logout (recommended)
sudo loginctl enable-linger "$USER"

After enabling lingering, your systemd user units (including hermes-gateway-<profile>.service) continue running across SSH disconnects and reboots.

Token-conflict safety​

Each profile must use unique bot tokens for each platform. If two profiles share a Telegram, Discord, Slack, WhatsApp, or Signal token, the second gateway refuses to start with an error naming the conflicting profile.

To audit:

grep -H 'TELEGRAM_BOT_TOKEN\|DISCORD_BOT_TOKEN' \
~/.hermes/.env ~/.hermes/profiles/*/.env

Updating the code​

hermes update pulls the latest code once and syncs new bundled skills into every profile:

hermes update
hermes-gateways restart

User-modified skills are never overwritten.

Troubleshooting​

"Could not find service in domain for user gui: 501"​

You ran hermes gateway start after a previous hermes gateway stop. The CLI's stop does a full launchctl unload, which removes the service from launchd's registry. The CLI catches this specific error on start and automatically re-loads the plist (↻ launchd job was unloaded; reloading service definition). The service starts normally. Nothing to fix.

Stale PID after a crash​

If a profile's gateway shows not running but a process is still alive:

ps -ef | grep "hermes_cli.*-p <profile>"
cat ~/.hermes/profiles/<profile>/gateway.pid
kill -TERM <pid> # graceful
kill -KILL <pid> # if that fails after a few seconds
<profile> gateway start

Forcing a hard reset of one service​

# macOS
launchctl unload ~/Library/LaunchAgents/ai.hermes.gateway-<profile>.plist
launchctl load ~/Library/LaunchAgents/ai.hermes.gateway-<profile>.plist

# Linux
systemctl --user restart hermes-gateway-<profile>.service

Health check​

hermes doctor                  # default profile
hermes -p <profile> doctor # one profile