Hermes-Relay Self-Setup
Hermes-Relay is a native Android client for the Hermes AI agent platform. It ships a Python plugin (relay server + tools + skills) that runs alongside hermes-agent on the host, plus a Kotlin Compose Android app that talks to it. This skill is the canonical, agent-readable setup recipe — it covers fresh installs, updates, verification, pairing, troubleshooting, and uninstallation.
When to Use
Invoke this skill when any of the following happens:
- User runs the
/hermes-relay-self-setupslash command. - User asks to "install Hermes-Relay", "set up the Android app", "update Hermes-Relay", "fix my Hermes-Relay install", or anything equivalent.
- User reports any of: missing
hermes-pair/hermes-statusshims, missingandroid_*tools, "Bridge is disabled" 403s,phone_connected: falsefrom the relay, stale plugin tools after agit pull. - User pasted the "For AI Agents" copy-paste block from the Hermes-Relay README or docs site and asked you to follow it.
Do NOT use this skill to write feature code or modify the plugin source. This is a setup/maintenance skill, not a development one.
Prerequisites
hermes-agent already installed at
~/.hermes/hermes-agent/. Verify with:ls ~/.hermes/hermes-agent/venv/bin/pythonIf that file doesn't exist, stop and ask the user to install hermes-agent first — you cannot install hermes-relay without it. Hermes-Relay is a plugin, not a standalone product.
Linux or macOS host. The relay's terminal channel uses a real PTY, which is POSIX-only. Windows hosts can run chat/bridge but the terminal tab won't work.
Internet access to fetch the install script from GitHub. The one-liner installer pulls from
raw.githubusercontent.com.
Procedure
A. Fresh install (or repair)
The canonical install command is idempotent — safe to re-run on any existing install. It pulls the latest main, refreshes the editable pip install, recreates the shell shims, re-registers the skills directory, restarts the relay service, and prompts before restarting hermes-gateway.
curl -fsSL https://raw.githubusercontent.com/Codename-11/hermes-relay/main/install.sh | bash
Confirm before running if the user has active chat sessions — the optional gateway restart will interrupt them for ~2 seconds. The installer prompts for the gateway restart by default; you do not need to opt in unless the user added new plugin tools and wants them re-imported immediately.
To opt into the gateway restart automatically (for scripted runs):
HERMES_RELAY_RESTART_GATEWAY=1 curl -fsSL https://raw.githubusercontent.com/Codename-11/hermes-relay/main/install.sh | bash
To skip it entirely:
HERMES_RELAY_NO_RESTART_GATEWAY=1 curl -fsSL https://raw.githubusercontent.com/Codename-11/hermes-relay/main/install.sh | bash
B. Update an existing install
Same command. The installer is idempotent — it detects an existing clone, fast-forwards it from main, and re-runs every step. Do not suggest manual git pull + pip install -e + shim recreation; the one-liner does all of that more reliably.
C. Verify the install
After install completes, run these checks in order. Stop and report if any fail.
Relay health endpoint (unauthenticated, fastest signal):
curl -s http://localhost:8767/healthExpect:
200 OKwith a JSON body containing"status": "ok"and a non-blank"version".Status endpoint (loopback only, expects no phone yet on a fresh install):
curl -s http://localhost:8767/bridge/statusExpect:
503+{"phone_connected": false, "error": "no phone connected"}until a phone has paired and pushed a status envelope.Shell shims installed:
command -v hermes-pair && command -v hermes-statusExpect: both resolve to
~/.local/bin/.Plugin loaded by hermes-agent:
~/.hermes/hermes-agent/venv/bin/python -c "import plugin.pair; import plugin.status; print('plugin OK')"Expect:
plugin OKwith noModuleNotFoundError.Systemd service running (if installed as a user service):
systemctl --user is-active hermes-relay.serviceExpect:
active.
If any check fails, jump to the relevant entry in the Troubleshooting section below.
D. Pair the phone
Once the install verifies green, pair the user's Android device:
hermes-pair
Or, from any Hermes chat session:
/hermes-relay-pair
Both invoke the hermes-relay-pair skill which generates a single QR code that configures both the chat (API server) and bridge/terminal (relay) channels. Tell the user to open the Hermes-Relay Android app → Settings → Connection → Scan Pairing QR (or the Connect page during onboarding).
If you can't scan a QR
If the user is SSH'd in from the same phone they want to pair, the host has no display attached, or there's otherwise no second camera-equipped device available, fall back to the manual code flow instead of the QR:
- Have the user open the Hermes-Relay app →
Settings→Connection→Manual pairing code (fallback). The card displays a locally-generated 6-char code (A-Z / 0-9). Ask them to read it back. - On the host, run:
Replacehermes-pair --register-code ABCD12ABCD12with the code from the phone. The command pre-registers it with the relay over the same loopback/pairing/registerendpoint the QR flow uses and prints a confirmation block. Same TTL / grants flags compose:hermes-pair --register-code ABCD12 --ttl 30d --grants chat:never,bridge:7d. - Tell the user to tap Connect in that same Manual pairing code card. The relay accepts the code, the phone is paired.
The full procedure lives in the hermes-relay-pair skill under "Manual fallback (--register-code)" — defer to that for the canonical recipe.
After scan (or after manual --register-code + Connect), verify with:
hermes-status
Expect: phone_connected: yes with device name, battery, granted permissions, and safety state populated.
E. Update vs. fresh install — same command
Both are the same one-liner. The user does not need to know which mode they're in; the installer figures it out.
F. Uninstall
bash ~/.hermes/hermes-relay/uninstall.sh
Or, if the clone is gone:
curl -fsSL https://raw.githubusercontent.com/Codename-11/hermes-relay/main/uninstall.sh | bash
The uninstaller is idempotent and never touches shared state (~/.hermes/.env, state.db, the hermes-agent venv core). Useful flags:
--dry-run— preview without changing anything--keep-clone— leave the git tree in place for later--remove-secret— also wipe the QR signing identity (only do this if explicitly requested)
Troubleshooting
hermes-agent not found at ~/.hermes/hermes-agent
The user hasn't installed hermes-agent yet. Hermes-Relay is a plugin — it requires hermes-agent as a host. Direct them to the upstream installer at https://github.com/NousResearch/hermes-agent (or the user's preferred fork) and stop until they confirm it's installed.
pip install -e ... failed
Either the venv Python is broken or the venv is missing build tools. Try:
~/.hermes/hermes-agent/venv/bin/python -m pip install --upgrade pip
~/.hermes/hermes-agent/venv/bin/python -m pip install -e ~/.hermes/hermes-relay
Surface any error to the user — do not try to "fix" venv internals.
hermes-status says phone_connected: false after pairing
The relay's status cache is wiped on every restart (in-memory only). The phone re-pushes its status envelope every 30 seconds. Either wait, or have the user toggle Bridge off + on in the Android app — that triggers an immediate pushNow().
Bridge commands return 403 "Bridge is disabled"
The user has the bridge master toggle off. They need to open the Hermes-Relay app → Bridge tab → flip "Allow Agent Control" on. This is a deliberate gate; do not bypass it.
android_phone_status tool not found by the agent
hermes-gateway hasn't re-imported the plugin since git pull. Restart it:
systemctl --user restart hermes-gateway
Or re-run the installer with HERMES_RELAY_RESTART_GATEWAY=1 to do this automatically.
Pairing rate-limited
The relay clears all rate-limit blocks on /pairing/register. Re-run hermes-pair and the previous block lifts.
Relay won't start as a systemd service
Check the journal:
journalctl --user -u hermes-relay -n 30 --no-pager
Most common cause: another python -m plugin.relay instance is holding port 8767. Fix:
pkill -f 'python -m plugin.relay'
systemctl --user restart hermes-relay
phone_connected: false plus last_seen_seconds_ago: null
No phone has ever pushed a status envelope to this relay process. This is the normal pre-pairing state — pair a phone first.
Phone is paired but the agent's android_* tool calls fail
Check that the bridge is enabled AND the relevant permission is granted. Use hermes-status to see what's actually granted. If screen_capture_granted is false, the user needs to tap the Screen Capture row in the Bridge tab to launch the system consent dialog. If accessibility_granted is false, they need to enable Hermes-Bridge in Android Settings → Accessibility.
Verification (final)
After install + pair, confirm all of the following before declaring the setup complete:
curl -s http://localhost:8767/healthreturns200+ valid JSONhermes-statusreturnsphone_connected: yeswith the user's device name- The user can send a test chat message from the Android app and receive a streaming response
- The agent can successfully call
android_phone_status()from a Hermes chat and receive a structured payload (this verifies the gateway has re-imported the plugin tools)
If all four pass, the install is healthy. If any fail, return to the matching Troubleshooting entry.
Safety
- Always confirm before running install commands. Do not run them silently.
- Never restart
hermes-gatewaywithout asking. It interrupts active chat sessions. - Do not modify
~/.hermes/.envor~/.hermes/config.yamloutside what the installer does. Those are user-owned config. - Do not bypass the bridge master toggle, the destructive-verb confirmation modal, or the blocklist. Those are deliberate safety features.
- Do not push to origin for the user. Updates go through the installer; code changes go through their own workflow.
Source: Codename-11/hermes-relay — distributed by TomeVault.