| .. | ||
| dist | ||
| src | ||
| tests | ||
| Cargo.lock | ||
| Cargo.toml | ||
| README.md | ||
Hermes Pair (hermes-pair)
Fast, lightweight, cross-platform pairing helper for Hermes Agent and the Hermes Android App.
hermes-pair bridges your host computer (running Hermes) with the mobile companion app by generating high-contrast QR codes and standard pairing URIs (hermes://pair?data=...) containing host network information, authentication state, and cryptographically secure random nonces.
Features
- 🖥️ Native GUI & Terminal UI Modes: Runs as a lightweight native GUI window (
eframe/egui) on desktop or an interactive/single-shot ANSI terminal interface on headless servers. - 🔍 Smart Network Interface Discovery: Automatically discovers and prioritizes physical LAN interfaces (
192.168.x.x,10.x.x.x,172.16-31.x.x) and Tailscale overlays (100.x.x.x), while filtering out loopback and link-local adapters. - ⚡ Real-Time Hermes Status Probing: Connects to
http://127.0.0.1:<port>/api/statusandhttp://<lan_ip>:<port>/api/statusto detect whether Hermes is active, verify version and auth requirements, and warn if Hermes is mistakenly bound only to loopback (127.0.0.1). - 🛡️ Built-in Security Safeguards:
- Automatically warns if Hermes is exposed over LAN without authentication.
- Generates single-use, 16-byte cryptographically secure random nonces.
- Enforces configurable TTL expiry (default: 120 seconds).
- Validates payload structure, versioning, and UUID integrity.
- 💾 Persistent Host Identity: Manages a persistent UUIDv4
host_idsaved atomically to%APPDATA%\HermesPair\config.json(Windows) or~/.config/hermes-pair/config.json(Linux).
Pairing Protocol Specification (v1)
The generated QR code encodes a custom URI:
hermes://pair?data=<BASE64URL_ENCODED_JSON>
Decoded JSON Payload (PairingPayloadV1)
{
"v": 1,
"type": "hermes-pair",
"host_id": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d",
"name": "Gaming-PC",
"host": "192.168.1.34",
"port": 9119,
"scheme": "http",
"expires_at": 1756012800,
"nonce": "k7a_QW9jRz1M..."
}
| Field | Type | Description |
|---|---|---|
v |
u32 |
Protocol schema version (1). |
type |
string |
Payload identifier (hermes-pair). |
host_id |
string |
Persistent UUIDv4 identifying the host machine. |
name |
string |
Human-readable computer or host display name. |
host |
string |
Reachable IPv4 address or hostname for the mobile client. |
port |
u16 |
HTTP port on which Hermes Agent is listening (e.g. 9119). |
scheme |
string |
Connection scheme (http or https). |
expires_at |
u64 |
Unix epoch timestamp (seconds) after which this payload is rejected. |
nonce |
string |
16 cryptographically random bytes, Base64URL-encoded. |
Installation & Build
Prerequisites
- Rust 1.80+ (tested on Rust 1.98.0)
Building from Source
# Clone the repository
git clone https://github.com/ochenstarik-ui/hermes-pair.git
cd hermes-pair
# Run tests
cargo test
# Build release binary
cargo build --release
Release binaries are produced at:
- Windows:
target/release/hermes-pair.exe - Linux:
target/release/hermes-pair
Usage
1. Native GUI Mode (Default)
Simply execute hermes-pair without flags to open the native desktop window:
hermes-pair
GUI Controls:
- Status Badge: Shows Hermes connectivity (Running, Offline, Loopback Only) and auth status.
- Network Interface Dropdown: Switch between Wi-Fi, Ethernet, Tailscale, or virtual adapters.
- [ 🔄 Regenerate QR ]: Generates a new payload with a fresh nonce and resets the countdown.
- [ 📋 Copy Link ]: Copies
hermes://pair?data=...directly to the system clipboard. - [ 🔄 Check ]: Retries probing the Hermes status endpoint immediately.
2. Interactive Terminal UI Mode
For remote SSH sessions or terminals without a display server:
hermes-pair --terminal
# or short flag:
hermes-pair -t
Output:
Hermes: Running (v1.2.0, Auth: Required)
Host: Gaming-PC
Address: http://192.168.1.34:9119
Host ID: 7b31d044...
Expires in: 01:58
██████████████████████████████
██ ██ ██ ██
██ ██████ ██ ██ ██████ ██
██ ██████ ██ ██ ██████ ██
██ ██ ██ ██
██████████████████████████████
...
Pairing Link: hermes://pair?data=eyJ2Ijox...
3. Headless / Single-Shot Script Mode
To print the QR code once to stdout (useful for automation, provisioning scripts, or terminal output piping):
hermes-pair qr
# or
hermes-pair --no-gui
4. Command Line Options
Usage: hermes-pair [OPTIONS] [COMMAND]
Commands:
qr Output QR code once to stdout and exit
help Print this message or the help of the given subcommand(s)
Options:
-t, --terminal Run interactive terminal mode with periodic refresh
--no-gui Print QR once to stdout and exit (headless/script mode)
--port <PORT> Port of Hermes Agent [default: 9119]
--hermes-url <URL> Hermes status API URL (e.g. http://127.0.0.1:9119)
-i, --interface <INTERFACE> Specific network interface name or IPv4 address to advertise
--ttl <TTL> Pairing QR validity TTL in seconds [default: 120]
-h, --help Print help
-V, --version Print version
Configuration & Storage
hermes-pair generates a persistent host_id on first launch and stores it in JSON format:
- Windows:
%APPDATA%\HermesPair\config.json - Linux / macOS:
~/.config/hermes-pair/config.json
Example configuration:
{
"host_id": "7b31d044-cf64-4e78-9df2-bb58a8f5e1a1",
"display_name": "Studio-Workstation"
}
Troubleshooting & Warnings
Warning: Loopback Only
If Hermes is started with default 127.0.0.1 binding, other devices on the LAN cannot connect.
Start Hermes binding to all interfaces:
hermes serve --host 0.0.0.0 --port 9119
Warning: Unauthenticated Network Access
If Hermes has no authentication configured, any device on your local network could access the API. Consider enabling token or password authentication for production usage.
License
Licensed under the MIT License.