Depends on Phase 1. Part of #734.
The data model already supports this: XRDrivers is a []string. Only the logic hardcodes alvr.
Scope in hydrabody:
- Add xrDriverWiVRn alongside xrDriverALVR (pkg/provider/alvr.go), and generalise xrCapable() from "has the alvr role and the ALVR dir exists" to a per-driver check. A body may advertise several drivers, or none.
- Report every capable driver from xrStatusFields().
- Implement arm and disarm for WiVRn: start the server, confirm it is listening and published over avahi, expose the pairing state, and tear down on doff. Reuse the existing state machine (idle -> armed -> connected/failed) with the existing doff grace and connect timeout rather than inventing a second lifecycle.
- The Linux equivalents of the XR tick and supervision currently no-op in alvr_other.go.
Note the split: ALVR arms SteamVR plus a driver; WiVRn IS the OpenXR runtime and launches the application itself via its application config key. Arming WiVRn therefore means running the server and pointing it at the experience, not registering a driver with a third-party runtime.
Done when: msi1060 reports xr_drivers ["wivrn"] and a WiVRn session is armed and torn down by hydrabody, observable in body status.
PARTIALLY DONE 2026-09-15, hydrabody master fdc2167.
Landed:
- xrDriverWiVRn ("wivrn") alongside xrDriverALVR, and xrDrivers() returning every driver the body can serve. xrStatusFields no longer hardcodes a single-element list, so xr_drivers finally carries what the protocol always allowed.
- wivrnCapable(): the wivrn role AND the server binary AND Linux. A Windows body never advertises it, since WiVRn's server is Monado-based and Linux only. A body with no XR role reports nothing, so existing flat and ALVR bodies are byte-for-byte unchanged.
- wivrnArm/wivrnDisarm/wivrnServing drive hydra-wivrn.service, a Hydra-owned user unit mirroring how Sunshine already runs on an Omarchy body: packaged binary, cluster-owned config under /var/lib/hydra, separate from the user's own settings.
- desktopService now takes the unit name instead of hardcoding Sunshine's.
- Unit tests for role detection and the Linux-only rule; runbook section comparing the two drivers and their asymmetry.
NOT done, and needed before this ticket closes:
- hydra-wivrn.service does not exist on any machine yet. Something must create it, the way hydra-sunshine.service is created today. That is #738's packaging work, and until it lands wivrnCapable is false everywhere.
- The arm and disarm functions are not called from the XR state machine. They exist and compile; nothing drives them on arm, doff or connect timeout yet.
- The experience is chosen by the WiVRn config rather than by a hydrabody launch, because WiVRn starts the application itself. Rendering that config from the assigned experience is unresolved and is the substantive remaining design question here. Note the traps: the key is "encoder" SINGULAR, the third stream is alpha and cannot be pyrowave, and bitrate is a CLIENT setting.
- hydrabody is not released, so no body runs any of this.