Files
iris_x_hermes/docs/16-open-questions.md
ARIA a61b47a947
CI / Gateway plugin tests (push) Successful in 5m19s
CI / Kotlin tests (android host + desktop) (push) Successful in 6m59s
docs: replace stale 'android' name mentions with 'iris'
The plugin is named 'iris' (IrisAdapter, IRIS_HOME_CHANNEL, label Iris),
but several docs still referred to it as the android platform/plugin and
to the product as 'the Android app'. Rename name-mentions to iris/IRIS
and product-mentions to 'Iris app'; keep legitimate OS references
(androidApp, Android SDK, Android 10, androidx, test_android.py, ...).

Also includes pi-lens markdown-lint autofixes (table spacing, trailing
newlines) in the touched files.
2026-08-24 21:44:02 +02:00

5.2 KiB
Raw Permalink Blame History

16 — Decisions & Open Questions

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

# Decision Choice Rationale
1 Desktop app tech Compose Multiplatform Desktop = "the Iris app, tweaked"; share protocol/state/UI.
2 Push backend Both — ntfy default, FCM optional (issue #10: FCM metadata — title, device token — is routed via Google's servers, contradicting the privacy claim; ntfy keeps it on your own infrastructure) 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 iris 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.