This project now uses a control-plane enrollment model as the primary way to connect Hermes agents to the Brio app.
apps/relay- Cloud control plane.
- Stores users, device sessions, owned agents, enrollments, pairings, and recovery state.
- Mobile app talks to this service first.
apps/companion- Runs next to Hermes on each machine.
- Exposes the local Brio API to Hermes.
- Opens an outbound relay tunnel for remote access.
apps/mobile- Signs into the relay.
- Lists owned agents.
- Generates enrollment codes.
- Connects to enrolled agents through the relay.
- User opens the mobile app.
- User signs into the relay with email + device name.
- User generates an enrollment code in the app.
- On the Hermes machine, user runs:
brio companion enroll --relay-url <relay-url> --code <code> --run- The companion claims the enrollment code, gets a relay token, and connects outbound.
- The agent appears in the app automatically.
- The user selects the agent from the app and connects.
pairing- Legacy/manual relay mode.
- Uses pairing payloads and pairing codes.
control-plane- Preferred mode.
- Uses enrollment and persistent agent ownership.
- Companion keeps a relay token locally and reconnects without manual pairing.
The companion config key is:
BRIO_RELAY_MODE=control-planeRun relay locally:
make dev-relayRun mobile locally:
make dev-mobileRun companion in legacy local mode:
make dev-companionEnroll a Hermes machine into the control plane:
brio companion enroll --relay-url http://127.0.0.1:8082 --code ABCD1234 --runRecover an enrolled agent if local relay state is lost:
brio companion recover \
--relay-url http://127.0.0.1:8082 \
--agent-id agent_xxx \
--device-token <owner-device-token> \
--restartAuthenticated device endpoints:
POST /auth/devicesGET /meGET /devicesDELETE /devices/{id}GET /agentsPOST /enrollmentsPOST /agents/{id}/recoverPOST /pairings/{code}/claim
Public companion-facing endpoints:
POST /enrollments/{code}/claimPOST /pairingsGET /pairings/{code}GET /tunnel/companion/{agentID}?token=...GET /tunnel/mobile/{agentID}?token=...
The relay needs persistent storage because it is the system of record for:
- users
- device sessions
- owned agents
- enrollment codes
- pairing codes
- companion token rotation
- recovery state
Without Postgres, the in-memory relay is only suitable for development.
Companion local state is written under:
~/.brio/companion.env~/.brio/pairing.json
Important config values:
BRIO_RELAY_URLBRIO_RELAY_TOKENBRIO_RELAY_MODEBRIO_AGENT_IDBRIO_TOKENHERMES_API_BASE
- Prefer the control-plane flow over manual pairing for product work.
- Keep direct local connect as a fallback for development and offline debugging.
- Recovery is owner-authenticated and intentionally separate from normal enrollment.
- Mobile relay sign-in is still lightweight and not a production identity system yet.
Use:
make checkThat runs Go tests plus mobile lint, typecheck, and static web export.