Desktop/Mobile Native Shell as a Consumer Surface — Tauri Host over the Daemon, Never a Protocol Component
Accepted
Context
The ontoref-daemon already exposes the full surface a native host would wrap: an axum HTTP /ui/ with rendered pages (graph, api_catalog, actions, login), a unified key-to-session auth model (ADR-005, ADR-021 UI lift-out into ontoref-ui), a NATS event fabric (platform-nats, feature-gated), an actor notification barrier (ADR-002), a passive drift watcher that emits exactly the events worth surfacing to a user (doc drift vs ontology node descriptions, gate-state changes), a multi-project daemon (ONTOREF_PROJECT_ROOT + remote-projects.ncl), and a Quick Actions catalog. The sibling project provisioning ships provisioning-desktop: ~3500 LOC of thin Tauri 2 host that wraps its daemon's /ui/ in a webview and adds the four things a browser cannot — system tray, native OS notifications, supervision of the local daemon child process (graceful SIGTERM), and native keyring — while the same lib compiles for iOS/Android via tauri::mobile_entry_point. The question is whether ontoref should grow an equivalent ontoref-desktop. The prerequisites already exist, so the decision is not feasibility but placement and identity: where such a crate lives, what it may depend on, and which named tension it occupies. Three options were evaluated: (A) no native host — users open the daemon UI in a browser; (B) a native host placed inside the protocol adoption surface, linking protocol internals or bundled into the daemon; (C) a from-scratch native UI (egui/iced) reimplementing the views in Rust. Option D — a thin Tauri shell as a separate consumer that wraps the daemon /ui/ and surfaces drift-watcher events as native notifications — is chosen.
Decision
Permit a native shell (ontoref-desktop, with the same Tauri lib targeting desktop and mobile) as a strictly separate consumer of the daemon, modeled on provisioning-desktop. It MUST consume the daemon over HTTP and NATS only — wrapping the existing /ui/ in a webview, bridging NATS/drift-watcher events to native OS notifications and a system tray, supervising the local daemon as a child process, and managing one local-spawn plus N remote-connect connection profiles against the multi-project daemon. It MUST NOT be a dependency of ontoref-ontology, ontoref-reflection, or the daemon: the dependency arrow points shell -> daemon, never the reverse, and never into the protocol-minimal adoption surface (ADR-001). It MAY depend on ontoref-ui for shared presentation. It lives either as its own constellation sub-repo (sibling to code/, per ADR-048) or as a workspace crate explicitly excluded from the installed/adopted set — in both cases outside the protocol footprint a consumer project receives. Within positioning (ADR-035/043) the desktop/mobile surface is declared as a consumer audience and the candidate occupant of the openness-vs-sustainability capture seam, while the protocol itself stays unmetered.
Constraints
- Hard ontoref-ontology must never list a desktop/native-shell crate as a dependency
- Hard ontoref-reflection must never list a desktop/native-shell crate as a dependency
- Hard ontoref-daemon must never depend on the desktop/native-shell crate; the dependency arrow points shell -> daemon only
- Hard The native shell lives as its own constellation sub-repo or as a workspace crate explicitly excluded from the installed/adopted protocol footprint, consuming the daemon over HTTP/NATS only
- Soft When the native surface occupies the openness-vs-sustainability seam, it does so as a declared consumer audience in positioning; the protocol surface itself is never metered
Alternatives considered
- No native host — users open the daemon /ui/ in a browser (option A) — rejected: Forfeits the four browser-impossible capabilities, chief among them native notifications for the drift watcher and ADR-002 barrier. The daemon already produces the events; leaving them trapped behind a manually-refreshed page wastes the notification-barrier design.
- Native host inside the protocol adoption surface — linking protocol internals or bundled into the daemon (option B) — rejected: Violates Protocol-Not-Runtime and ADR-001: it would make a GUI consumer part of the surface a consumer project adopts, coupling the minimal protocol crates to a heavy platform toolchain. The dependency arrow would point the wrong way (protocol -> host).
- From-scratch native UI in egui/iced reimplementing the views (option C) — rejected: Duplicates the daemon /ui/ and ontoref-ui, creating two view surfaces that drift apart. High maintenance, no single source of truth for the graph/catalog/actions pages, and it discards the reason a thin Tauri host stays small.
Anti-patterns
- Native host inside the adoption surface — Placing the desktop/mobile crate beside the protocol-minimal crates, or making ontoref-ontology/-reflection/the daemon depend on it, or bundling it into the daemon. This inverts the shell -> daemon arrow and drags a platform/webview toolchain into the surface a consumer project adopts, breaking Protocol-Not-Runtime.
- Native view-surface fork — Reimplementing the daemon /ui/ views (graph, api_catalog, actions, qa) natively in egui/iced instead of wrapping the existing HTML in a webview. Creates two view surfaces that drift apart and discards the single-source-of-truth that keeps the host thin.
- Metering the protocol to capture value — Putting the openness-vs-sustainability capture on the protocol surface itself — gating tier-0 adoption, schemas, or describe queries behind payment — instead of on a consumer surface. Collapses the Spiral toward Yang by tolling the gift that produces the visibility funnel.
Related ADRs
ADR-002 · ADR-001 · ADR-021 · ADR-016 · ADR-038 · ADR-029 · ADR-035 · ADR-043 · ADR-048 · ADR-031