Files
iris_x_hermes/docs/16-open-questions.md
T
ARIA 7a6d922d12
CI / Kotlin tests (android host + desktop) (push) Successful in 8m5s
CI / Gateway plugin tests (push) Successful in 9m47s
Add QR pairing (terminal QR, in-app scanner, iris://pair deep link)
2026-08-22 22:43:13 +02:00

5.1 KiB
Raw Blame History

16 — Decisions & Open Questions

Locked decisions (from planning, 2026-08-19)

# Decision Choice Rationale
1 Desktop app tech Compose Multiplatform Desktop = "the Android app, tweaked"; share protocol/state/UI.
2 Push backend Both — FCM primary, ntfy fallback FCM is standard/reliable; ntfy for self-hosters with no Firebase. IRIS_PUSH_BACKEND.
3 Media transport Over the WebSocket One transport, zero new Python deps; chunked binary frames.
4 Phone default layout User-toggleable, single-pane default App-like on phones; auto two-pane on large screens; desktop defaults two-pane.

Additional decisions made during planning

Decision Choice Note
Connection point Messaging gateway (platform plugin iris), not tui_gateway Makes cron/send_message/slash/coexistence native.
Plugin style Community plugin (register(ctx)) Zero hermes-core changes.
Python deps None new (websockets + httpx are core) Respects hermes pinning policy.
Tool events Structured frames; app controls verbosity Gateway sends full data; app = everything/truncated/nothing.
Reasoning Adapter splits the show_reasoning prefix Clean reasoning field → collapsible block above message.
Channels/threads Map onto chat_id/thread_id Existing gateway primitives; cron targets them.
Offline SQLite outbox + sync cursor Catch-up on reconnect; push on disconnect.
Default chat id default Home channel + cron default.
WS port 8790 (default) Configurable.
minSdk 26 (test device API 29) Broad coverage.
Frame routing Broadcast to all connected devices (no per-chat subscribe) Single-user model; simpler.
Initial channel load history frame (paginated) sync only replays outbox; history loads full messages.
Slash menu commands.catalog + commands.complete frames Gateway serves catalog; app renders bottom sheet + autocomplete.
Agent lifecycle agent.busy/agent.idle events + agent.stop/agent.steer requests App shows thinking indicator; user can abort or steer mid-turn.
Local DB (KMP) SQLDelight (not Room) Room is Android-only; SQLDelight works in commonMain for both platforms.
Voice input Record → upload as audio media (no client-side STT) Agent's STT (if configured) handles transcription.
QR encoder Pure-stdlib (gateway-plugin/qr.py) No qrcode/segno/Pillow; byte mode, EC M→L, v1–10, ISO penalty masking. Keeps the plugin's zero-new-dep rule.
QR scanner ML Kit barcode (not zxing-android-embedded) On-device, no Google Play services; better accuracy/latency, Google-maintained. Android-only (desktop has no camera).

Open questions (resolve during implementation)

These are implementation-time details, not blockers. Each has a default we will proceed with unless you say otherwise.

  1. Tool-progress vs commentary classification (M2). The exact signal that distinguishes a tool-progress send() from a regular send()/commentary in the legacy path. Default: per-chat turn-state machine + line-format heuristic, verified empirically with the ws_probe.py harness against the live gateway. If a clean metadata marker exists, prefer it.
  2. Reasoning prefix format stability (M2). We split on the code-style 💭 **Reasoning:**\n```\n…\n```\n\n prefix. Default: set reasoning_style: code for android and split on that; fallback = no reasoning field (full text) if the prefix isn't found. Verify in M2.
  3. Per-device tokens vs shared token (M1/M5). Default (v1): shared IRIS_TOKEN + optional IRIS_ALLOWED_USERS device allowlist. Per-device revocable tokens are a stretch.
  4. Desktop video backend (M6). Default: libmpv/mpv-backed Compose surface, WebView fallback. Confirm mpv availability on target OSes during M6.
  5. Remote access default (M1). Default: document Tailscale as the recommended remote path; WSS + reverse proxy as alternatives. No public bind by default.
  6. Streaming cadence (M2). If live updates look chunky, tune display.platforms.iris.streaming / consumer edit interval. Default: follow global streaming config.
  7. App package name / branding. Default: applicationId dev.iris.app, app name "Iris". Confirm final product name + package + icon.
  8. ntfy in-app listener (M5). Default: a foreground service maintaining the ntfy subscription (no extra native lib) — or a lightweight ntfy client lib if one is acceptable. Decide in M5.
  9. Auto-update for desktop (M7). Default: out of scope (manual download). Revisit post-v1.
  10. iOS port. Out of scope for v1 (protocol is transport-agnostic, so it's a future port). No action now.

Explicit non-goals (v1)

  • Multi-user / group chat (personal 1-user agent).
  • End-to-end encryption (transport WSS only).
  • Standalone-cron delivery while the gateway process is fully down (best-effort push only).
  • iOS.