# Headless Setup and QR Onboarding ODS can be prepared as a local AI appliance: install it on hardware, ship or hand over the machine without a monitor, and let the recipient finish setup from a phone, laptop, tablet, or TV browser. This page is the hardware-neutral map of the code that makes that possible. Strix Halo, DGX Spark, NUC-style mini PCs, repurposed desktops, and home lab servers should all follow the same high-level flow once their platform-specific installer path is working. ## Current Status The headless setup stack is implemented on `main` across the setup-card script, dashboard, dashboard API, host agent, mDNS announcer, AP-mode script, and Caddy proxy extensions. Status is **deployed in code and partially validated on the real hardware fleet** for the LAN, mDNS, dashboard, magic-link, and Hermes access paths. The packaged appliance handoff still needs per-image validation because routers, Wi-Fi chipsets, AP-mode behavior, and client devices vary. In particular: - Magic-link generation, QR rendering, first-run state, and dashboard flows have unit/integration coverage. - Wi-Fi management is implemented for Linux hosts with NetworkManager / `nmcli`. - AP mode is available but intentionally disabled by default because it takes over a wireless interface. - mDNS plus `ods-proxy` provide the friendly LAN URLs. Fleet validation covers representative LAN behavior, but each packaged hardware image should still be validated on its target router/client environment. ## User Journey 1. The device is pre-installed with ODS and given a friendly `ODS_DEVICE_NAME` such as `ods`, `studio`, or `kitchen-ai`. 2. The operator prints or ships a setup card with: - QR #1: a Wi-Fi QR code for the device setup AP, if AP mode is used; - QR #2: either the setup URL for first-run provisioning, or a permanent owner-card magic link that lands the new owner in ODS Talk. 3. The recipient scans the setup QR, opens the first-boot wizard, and joins the device to their home network when needed. 4. ODS generates an owner-card magic link and QR code for the first user. 5. After redemption, the user lands in ODS Talk, a mobile-first local chat portal backed by Hermes. Power users can still open the dashboard and the advanced Hermes surface for model, service, and diagnostics controls. ## Main Components | Component | Code | Tests / Docs | Purpose | |---|---|---|---| | Setup card generator | [`scripts/generate-setup-card.py`](../scripts/generate-setup-card.py) | [`tests/test_setup_card.py`](../tests/test_setup_card.py), [`SETUP-CARD.md`](SETUP-CARD.md) | Produces printable cards with Wi-Fi + setup QR codes or Wi-Fi + owner ODS Talk QR codes. | | First-run state | [`extensions/services/dashboard-api/routers/setup.py`](../extensions/services/dashboard-api/routers/setup.py), [`extensions/services/dashboard/src/hooks/useFirstRun.js`](../extensions/services/dashboard/src/hooks/useFirstRun.js) | [`tests/test_setup.py`](../extensions/services/dashboard-api/tests/test_setup.py), [`App.test.jsx`](../extensions/services/dashboard/src/App.test.jsx) | Server-side setup sentinel that decides whether the wizard should appear. | | Phone-first wizard | [`extensions/services/dashboard/src/pages/FirstBoot.jsx`](../extensions/services/dashboard/src/pages/FirstBoot.jsx) | [`FirstBoot.test.jsx`](../extensions/services/dashboard/src/pages/FirstBoot.test.jsx) | Guides first setup and shows the owner-card QR. | | Magic-link auth and QR | [`extensions/services/dashboard-api/routers/magic_link.py`](../extensions/services/dashboard-api/routers/magic_link.py), [`extensions/services/dashboard/src/pages/Invites.jsx`](../extensions/services/dashboard/src/pages/Invites.jsx) | [`test_magic_link.py`](../extensions/services/dashboard-api/tests/test_magic_link.py), [`Invites.test.jsx`](../extensions/services/dashboard/src/pages/Invites.test.jsx), [`HERMES-SSO.md`](HERMES-SSO.md) | Creates revoke-only owner cards and temporary guest links, renders QR codes, redeems tokens, and issues signed session cookies. | | Wi-Fi setup API | [`extensions/services/dashboard-api/routers/setup.py`](../extensions/services/dashboard-api/routers/setup.py), [`bin/ods-host-agent.py`](../bin/ods-host-agent.py) | [`test_network_config.py`](../extensions/services/dashboard-api/tests/test_network_config.py), [`test_host_agent.py`](../extensions/services/dashboard-api/tests/test_host_agent.py) | Lets the dashboard ask the host agent to scan, connect, check status, and forget Wi-Fi profiles. | | First-boot AP mode | [`scripts/ap-mode.sh`](../scripts/ap-mode.sh), [`scripts/systemd/ods-ap-mode.service`](../scripts/systemd/ods-ap-mode.service), [`scripts/ap-mode.conf.example`](../scripts/ap-mode.conf.example) | [`test-ap-mode.sh`](../tests/test-ap-mode.sh), [`AP-MODE.md`](AP-MODE.md) | Optional setup access point for devices that are not yet on the user's network. | | LAN discovery | [`bin/ods-mdns.py`](../bin/ods-mdns.py), [`scripts/systemd/ods-mdns.service`](../scripts/systemd/ods-mdns.service) | [`MDNS.md`](MDNS.md) | Publishes `.local` and service subdomains on the local network. | | LAN reverse proxy | [`extensions/services/ods-proxy/Caddyfile`](../extensions/services/ods-proxy/Caddyfile), [`extensions/services/ods-proxy/compose.yaml`](../extensions/services/ods-proxy/compose.yaml) | [`ODS-PROXY.md`](ODS-PROXY.md) | Routes `chat..local`, `dashboard..local`, `talk..local`, `auth..local`, `api..local`, and `hermes..local`. | | Agent surface | [`extensions/services/hermes-proxy/Caddyfile`](../extensions/services/hermes-proxy/Caddyfile) | [`HERMES.md`](HERMES.md), [`HERMES-SSO.md`](HERMES-SSO.md) | Gates Hermes behind ODS magic-link session auth. | ## Operator Prep Checklist For a hardware image or pre-installed unit: 1. Install ODS normally for the target platform. 2. Set a unique `ODS_DEVICE_NAME` in `.env`. 3. Set `ODS_SESSION_SECRET` so magic-link redemption can issue signed `ods-session` cookies. 4. Enable the LAN entry path: - `ods-proxy` for friendly HTTP routing; - `ods-mdns` for local `.local` discovery where supported; - `hermes-proxy` if the Hermes Agent should be LAN-reachable behind auth. 5. For AP-based out-of-box setup, write `/etc/ods/ap-mode.conf`, install the `ods-ap-mode.service` unit, and generate a setup card or factory owner card. 6. Validate the exact QR flow on the target image before shipping. ## Validation Checklist Use this checklist for each target hardware profile: - Fresh install completes without a monitor attached. - Setup card Wi-Fi QR joins the setup AP. - Setup URL QR opens the first-boot wizard. - Wi-Fi scan returns nearby networks on Linux NetworkManager hosts. - Wi-Fi connect succeeds and the device remains reachable after network handoff. - `ods-proxy` answers on port 80 from another device on the LAN. - `.local`, `chat..local`, `dashboard..local`, and `auth..local` resolve on at least one phone and one laptop. - Owner-card magic link redeems repeatedly, sets the signed cookie, and redirects to Hermes until revoked. - Temporary guest invite links still redeem, set the signed cookie, and redirect to their selected target. - Hermes is reachable through `hermes..local` when enabled. - Mobile voice is validated from HTTPS/Tailscale HTTPS when the packaged Hermes surface exposes microphone controls; plain HTTP is expected to show fallback readiness rather than promise mic access. - Dashboard remains available for power users after first-run completion. ## Known Limits - AP mode is Linux-only and assumes NetworkManager, `hostapd`, `dnsmasq`, `iptables`, and a Wi-Fi interface capable of AP mode. - AP mode is disabled by default because it is intentionally disruptive to a wireless interface. - mDNS behavior varies by client OS, router, VPN, and enterprise network policy. - The complete AP-mode appliance handoff still needs repeated end-to-end testing on each target packaged hardware image. - Owner cards are physical credentials. They are not device-bound in v1 and should be revoked if a card is lost, photographed, or replaced.