hermes-relay-pair
Skill432 starsChanged 4 months agoMITView on GitHub
Generate a signed setup QR for Hermes-Relay Android, preserving Dashboard/Gateway ownership and optional Relay or API routes.
- Reads credentials
In this repository11 other files it gives its agents.
- AGENTS.mdAGENTS.md
- website/AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- .github/copilot-instructions.mdCopilot instructions
- relay-serverSkill
- androidSkill
- hermes-relay-desktop-setupSkill
- hermes-relay-doctorSkill
- hermes-relay-self-setupSkill
- hermes-relay-statusSkill
- translate-android-localeSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
13 rules. About 0 are common, 5 are distinctive, and 8 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈5
Distinctive · estimate
This author's own choices. Worth a look.
8
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 29
Do NOT use this skill to start or install the relay server itself — that is a prerequisite.
- Very specific: line 37
Hermes-Relay plugin installed and enabled: Verify with hermes pair --help.
- Distinctive: line 61
When the current Hermes surface exposes an exact Dashboard origin, pass it rather than guessing from an API hostname.
- Very specific: line 106
If onboarding: tap Scan Pairing QR on the Connect page.
- Very specific: line 107
If already onboarded: go to Settings → Connection → Scan Pairing QR.
- Distinctive: line 128
Use this when QR scanning is physically impossible:
- Very specific: line 168
Plugin not installed: If hermes pair --help is unavailable, run hermes plugins install Codename-11/hermes-relay/plugin --enable.
- Very specific: line 169
Wrong venv: If hermes CLI is global but plugin is in the Hermes venv, python -m plugin.pair may resolve to the wrong Python.
- Distinctive: line 177
After the user scans, confirm all three of the following:
- Very specific: line 179
Phone side: Ask the user to open Settings → Connection.
- Very specific: line 183
Relay side: Run curl -s http://127.0.0.1:8767/health — clients should be >= 1 after the phone connects.
- Distinctive: line 184
Functional check: Ask the user to send a test message from the chat tab and switch to the terminal tab — the terminal should attach without …
- Distinctive: line 186
If any of those fail, fall back to the Pitfalls section and re-run the skill with appropriate flags.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Hermes-Relay Pairing
Hermes-Relay is a native Android client for Hermes. Standard Chat, Manage, and voice belong to upstream Dashboard/Gateway. API-only operation is explicit compatibility, never an automatic fallback for a Gateway-owned conversation. Relay adds optional terminal/bridge and other extensions. This skill generates a signed setup QR using plugin.pair.
When to Use
Invoke this skill when any of the following happens:
- User runs the
/hermes-relay-pairslash command. - User asks to "pair my phone", "connect the Hermes-Relay app", "scan a QR for Hermes", or anything equivalent.
- User is setting up the Hermes-Relay Android app for the first time, or re-pairing after uninstall / token loss.
- User reports terminal tab asking for a pairing code (the app needs a fresh relay code embedded in a QR).
Do NOT use this skill to start or install the relay server itself — that is a prerequisite. Reference hermes relay start and stop.
Dashboard alternative
Operators with the Hermes dashboard open can also mint the same QR from the web UI: Relay tab → Management → "Pair new device" (Mode + Prefer dropdowns), or Relay tab → Remote Access → "Regenerate QR" for the fuller preview + probe view. Both UIs call the same handle_pairing_mint endpoint this skill shells into. Prefer this skill when you're already in a terminal (faster + scriptable); prefer the dashboard when the operator needs to see + probe candidate endpoints before minting. The dashboard's "Advanced · API-server override" field should stay blank in almost every case — pinning a forward-auth-gated hostname there (e.g. Authelia-fronted FQDN) pairs WSS but breaks the API side. See docs/remote-access.md § "Forward-auth gateways".
Prerequisites
- Hermes-Relay plugin installed and enabled. Verify with
hermes pair --help. If the command is unavailable, runhermes plugins install Codename-11/hermes-relay/plugin --enable. Use the fullinstall.shpath instead only when the host also needs the relay service, editable package, and shell shims. - Dashboard/Gateway reachable at its configured origin for standard Chat, Manage, and voice. The API server is required only when explicitly including API-only compatibility;
plugin.pairreads optional API configuration from the Hermes configuration/environment. - Relay server running on
RELAY_HOST:RELAY_PORT(default0.0.0.0:8767) if the user wants terminal/bridge channels. The Relay may stay host-internal: current Android pairing normally reaches it through the Dashboard's same-origin plugin transport. Tailscale Serve normally exposes dedicated HTTPS10443and proxies the host-local Dashboard on9119; a raw LAN/tailnet route may reach9119directly. Listener443is an advanced explicit override only when it is free. Without a live relay, the QR will configure chat only. - Check optional host capabilities. Standard Dashboard setup and QR generation are independent of PTY support. Terminal requires the supported POSIX backend; do not present a Windows host as terminal-capable merely because pairing succeeded.
Procedure
For Secure Link, run hermes relay secure-link --host <reachable-server-address>
before minting. It is a read-only report shared with Dashboard and Desktop setup.
Resolve its blockers and have the operator apply the reviewed settings/restart
through the existing service owner; this pairing skill must not guess a service
or change it. Re-check until the requested listener is active, then use
hermes pair --png. Keep the certificate and pin in the signed invite. QR trust,
Dashboard sign-in, and Chat readiness are separate steps; never learn a pin from
an untrusted health response or downgrade the route after a TLS failure.
- Probe the relay —
curl -sf http://127.0.0.1:8767/health(or$RELAY_PORT). If it returns 200, Relay is up; that alone does not prove Dashboard sign-in or Gateway readiness. If it fails, standard setup can still use Dashboard's Connect mobile app QR. Optional Relay pairing requires a running Relay. Do not offer API-only as automatic recovery for a Gateway connection, and do not start Relay unless the user asks. Generate the QR — run via the
terminaltool:hermes pairWhen the current Hermes surface exposes an exact Dashboard origin, pass it rather than guessing from an API hostname. This is especially important for an external HTTPS origin or a Dashboard mounted below a path prefix:
python -m plugin.pair --dashboard-url https://hermes.example.comA trusted configured
HERMES_DASHBOARD_PUBLIC_URL/ Dashboard public URL is also suitable. If no exact origin is available, omit the flag; the pair backend will construct conventional LAN/raw-tailnet Dashboard candidates on9119, or advertise the HTTPS10443listener when Tailscale Serve maps it to local Dashboard9119. HTTPS443is used only after the operator explicitly selects that advanced listener and confirms it is free. Never substitute the API server URL or infer public port8767.On a full-relay or legacy editable install where an older Hermes host cannot register plugin CLI commands, use the Hermes venv explicitly:
~/.hermes/hermes-agent/venv/bin/python -m plugin.pair- Useful flags (pass only when needed, not by default):
--png— save PNG to/tmp/hermes-pairing-qr.pngand skip the Unicode terminal QR. Use when the user reports the terminal QR won't scan (small font, dark mode, non-Unicode terminal).--no-qr— text only, no QR at all. Use when the agent is running in a non-TTY context and QR output would be wasted.--no-relay— skip relay pre-pairing, render API-only QR. Use if the relay is intentionally offline.--host <ip>/--port <n>— override the API server host or port when config auto-detection picks the wrong values.--dashboard-url <url>— exact Dashboard origin to preserve in the pairing invite, including any path prefix. Prefer the current trusted Dashboard origin when the TUI/chat surface knows it; do not invent one from the API endpoint.--mode {auto,lan,tailscale,public}— endpoint discovery mode (ADR 24). Defaultautoprobes LAN + Tailscale (if the helper is installed) +--public-url(if passed) and bakes them into the QR as an ordered candidate list so the phone switches networks automatically. Each normal candidate uses its Dashboard origin plus/api/plugins/hermes-relay/transport;lan/tailscale/publicemit just that role. Example:python -m plugin.pair --mode auto --public-url https://hermes.example.com.--public-url <url>— public Dashboard origin for a reverse proxy / Cloudflare Tunnel. Must behttp://orhttps://; an external HTTPS Dashboard such ashttps://hermes.example.comkeeps Relay on that same authority and plugin transport path. It does not imply or expose public port8767.--prefer <role>— promote the named role to priority 0 in the endpoint list. Open vocab — commonlylan/tailscale/public. Useful when the user wants to force a specific path during testing without re-ordering defaults. Example:python -m plugin.pair --mode auto --prefer tailscaleemits all detected modes but with Tailscale as the first-probed endpoint. Warns (non-fatal) if the named role isn't detected.--legacy-direct-relay— also advertise the direct Relay port for older Hermes Relay Desktop CLI/UI clients, which cannot yet authenticate through Dashboard WebSocket ingress. Use only when pairing one of those clients and when that direct route is deliberately reachable; do not use it for normal Android pairing or infer it from a public Dashboard URL.--register-code <code>— manual fallback. Skip QR rendering entirely and just pre-register a 6-char code the user is reading off the phone screen. See "Manual fallback" below.
Show the output verbatim.
plugin.pairprints, in order:- Text block with
ServerURL, maskedAPI Key, and (if relay is up) aRelay (terminal + bridge)section withURLandCode. Copy/paste pairing invitesection with ahermes-relay://pair?payload=...URL. This is the preferred desktop GUI/CLI fallback when QR scanning is unavailable.- Unicode half-block QR (when stdout is a TTY).
PNG: /tmp/hermes-pairing-qr.pngline.WARNING: This QR contains credentials ...line (whenever an API key or relay code is present).
Relay the full output back to the user. Do NOT redact the QR — the user needs to scan it. DO repeat the credentials warning in your own words.
- Text block with
Tell the user how to scan. Give them these exact steps:
- Open the Hermes-Relay Android app.
- If onboarding: tap
Scan Pairing QRon the Connect page. - If already onboarded: go to
Settings→Connection→Scan Pairing QR. - Point the camera at the terminal (or the PNG file) until it auto-detects.
- Watch for the success toast and the status summary.
For Desktop pairing, tell the user to copy the
hermes-relay://pair?...invite URL into Hermes Relay Desktop → Pair → Paste invite, or run the host mint with the explicit compatibility route and then paste its invite:hermes pair --legacy-direct-relay hermes-relay pair --pair-qr 'hermes-relay://pair?payload=...'The current Desktop client does not yet obtain Dashboard WebSocket tickets, so a default Android-focused invite containing only same-origin Dashboard transport routes is intentionally not sufficient for Desktop pairing.
- Time constraint. The relay pairing code expires 10 minutes after generation and is single-use. If the user won't scan within that window, re-run the skill to mint a fresh code.
Manual fallback (--register-code)
Use this when QR scanning is physically impossible:
- The user is SSH'd into the host from their phone (the only camera-equipped device) and there's no second device to point at the screen.
- The host has no display attached (a headless server you ssh into from a terminal that can't render Unicode QR blocks, or where copying a PNG off-host is awkward).
- The user's phone is the device with the camera and the device that needs to pair — there's no way to scan its own screen.
Workflow:
- Tell the user to open the Hermes-Relay app → Settings → Connection → Manual pairing code (fallback). The app displays a locally-generated 6-char code (A-Z / 0-9). They read it to you (or paste it into the chat).
On the host, run:
hermes-pair --register-code ABCD12Replace
ABCD12with the code from the phone. The command pre-registers it with the relay via the same loopback/pairing/registerendpoint the QR flow uses, then prints a confirmation block listing the code, transport hint, session TTL, and what the user should tap next.- Tell the user to tap Connect in that same Manual pairing code card. The relay accepts the code, mints a session token, and the phone is paired.
TTL + grants compose with --register-code exactly like they do with the QR flow:
hermes-pair --register-code ABCD12 --ttl 30d --grants chat:never,bridge:7d
hermes-pair --register-code ABCD12 --ttl never
hermes-pair --register-code ABCD12 --transport-hint wssPass --transport-hint wss only when you know the relay is actually running behind TLS (e.g. an external reverse proxy) but the host-side check can't tell. Otherwise it's auto-detected from RELAY_SSL_CERT.
Exit codes:
0— code accepted, pairing pre-registered. Phone can now tap Connect.1— relay was unreachable, OR relay was reachable but rejected the code (loopback-only endpoint — confirm you're on the same host as the relay).2— argument validation failed (bad code format, wrong length, invalid TTL/grants spec).
Same 10-minute expiry rules apply — once the operator runs hermes-pair --register-code, the user has 10 minutes to tap Connect or the code is invalidated and they need a fresh one from the app + a fresh --register-code invocation.
Pitfalls
- Relay not running.
plugin.pairprints[info] Relay not running ... QR will configure chat onlyand renders an API-only QR. Terminal tab will then ask the user to paste a pairing code manually. Fix: start the relay first (hermes relay start) and re-run. - Plugin not installed. If
hermes pair --helpis unavailable, runhermes plugins install Codename-11/hermes-relay/plugin --enable. Useinstall.shfor the full relay/service/shim setup rather than constructing a manual editable install. - Wrong venv. If
hermesCLI is global but plugin is in the Hermes venv,python -m plugin.pairmay resolve to the wrong Python. Call the venv Python explicitly:~/.hermes/hermes-agent/venv/bin/python -m plugin.pair. - Pairing code expired. 10-minute TTL, one-shot. Re-run
python -m plugin.pairto mint a fresh code; the previous code is automatically invalidated on the next run. - QR won't scan on terminal. Likely causes: terminal font too small (zoom in), dark-mode color inversion mangling the blocks, or terminal lacks Unicode half-block support. Fix: re-run with
--pngand point the camera at the saved image, or open the PNG in an image viewer on a second screen. - Host resolves to
127.0.0.1. The phone on the LAN can't reach loopback.plugin.pairauto-detects the outbound LAN IP via a UDP socket trick, but if that fails setAPI_SERVER_HOST=0.0.0.0in~/.hermes/.envor pass--host <lan-ip>explicitly. - Relay is running but
/pairing/registerrejected. Printed as[warn] Relay is running but /pairing/register was rejected. The endpoint is gated to loopback callers — the relay must be on the same host as the agent running this skill. If it's on a different host, pairing has to be done there.
Verification
After the user scans, confirm all three of the following:
- Phone side. Ask the user to open
Settings→Connection. They should see:API Server: reachable, green status.Relay: connected, green status.Session: paired.
- Relay side. Run
curl -s http://127.0.0.1:8767/health—clientsshould be>= 1after the phone connects. - Functional check. Ask the user to send a test message from the chat tab and switch to the terminal tab — the terminal should attach without prompting for a pairing code.
If any of those fail, fall back to the Pitfalls section and re-run the skill with appropriate flags.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

