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.
This commit is contained in:
1 parent
597a28050f
commit
a61b47a947
15 files changed
+42
-38
No files matched your search
+2
-2
@@ -11,8 +11,8 @@ create.
|
||||
|
||||
## Goals
|
||||
|
||||
- **Native feel.** Real Android app (Kotlin/Compose), not a WebView. Desktop
|
||||
app that is the same app, resized for a big screen.
|
||||
- **Native feel.** Real native app (Iris on Android, Kotlin/Compose), not a
|
||||
WebView. Desktop app that is the same app, resized for a big screen.
|
||||
- **First-class gateway citizen.** The app is a hermes *messaging platform*, so
|
||||
everything the gateway already does "just works": slash commands, cron
|
||||
delivery, `send_message` routing, coexistence with Telegram/Discord/etc.
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
│ │ │ │ │
|
||||
│ │ ▼ legacy stream callbacks (delta / tool-progress / commentary) │ │
|
||||
│ │ ┌──────────────────────────────┐ ┌────────────────────────────────┐ │ │
|
||||
│ │ │ android PLATFORM PLUGIN │◄───────►│ WebSocket SERVER (websockets) │ │ │
|
||||
│ │ │ IRIS PLATFORM PLUGIN │◄───────►│ WebSocket SERVER (websockets) │ │ │
|
||||
│ │ │ IrisAdapter │ JSON │ ws://host:8790/ws │ │ │
|
||||
│ │ │ (BasePlatformAdapter) │ frames │ + media + FCM-token + pairing │ │ │
|
||||
│ │ │ • send / edit / stream │ └───────────────┬────────────────┘ │ │
|
||||
@@ -26,7 +26,7 @@
|
||||
│ │ Google FCM cloud │
|
||||
▼ │ │ │
|
||||
┌────────────────────────┐ │ ▼ │
|
||||
│ ANDROID APP │◄──┴── (wake) ┌──────────┐
|
||||
│ IRIS APP (ANDROID) │◄──┴── (wake) ┌──────────┐
|
||||
│ (Kotlin / Compose) │ WSS │ PHONE │
|
||||
│ • WS client (OkHttp) │◄───────────►│ MIX 2S │
|
||||
│ • ExoPlayer │ │ (API 29) │
|
||||
@@ -72,7 +72,7 @@ protocol (`04-wire-protocol.md`) that borrows familiar names (`message.*`,
|
||||
## Key architectural decisions + rationale
|
||||
|
||||
| Decision | Rationale |
|
||||
|---|---|
|
||||
| --- | --- |
|
||||
| **Community-style platform plugin** (`register(ctx)` → `ctx.register_platform`) | Zero hermes-core changes; survives hermes updates; follows `ADDING_A_PLATFORM.md` "Plugin Path". |
|
||||
| **Single WS transport** for chat, streaming, tools, media, pairing, FCM-token | One connection, one auth, one dependency (`websockets`, already core). Media as chunked binary frames avoids adding an HTTP server. |
|
||||
| **`websockets` + `httpx` only** | Both are hermes *core* deps → the plugin adds **zero** new Python dependencies (respects hermes supply-chain pinning policy). |
|
||||
@@ -80,7 +80,7 @@ protocol (`04-wire-protocol.md`) that borrows familiar names (`message.*`,
|
||||
| **Reasoning split in the adapter** | The gateway prepends reasoning to the final text when `show_reasoning` is on; the adapter splits the stable prefix into a `reasoning` field so the app renders a clean collapsible block. |
|
||||
| **Channels/threads = `chat_id`/`thread_id`** | The gateway's `SessionSource` already models this; cron delivery already targets `platform:chat_id:thread_id`. We map app concepts onto existing primitives. |
|
||||
| **SQLite outbox + sync cursor** | Offline delivery + reconnect catch-up without re-reading full history. |
|
||||
| **Compose Multiplatform** | Desktop is "the Android app, tweaked" → share protocol/state/UI; only platform services + layout differ. |
|
||||
| **Compose Multiplatform** | Desktop is "the Iris app, tweaked" → share protocol/state/UI; only platform services + layout differ. |
|
||||
|
||||
## Data flow (one turn)
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ and the canonical example `hermes-agent/plugins/platforms/irc/adapter.py`.
|
||||
|
||||
```yaml
|
||||
name: iris-platform
|
||||
label: Android
|
||||
label: Iris
|
||||
kind: platform
|
||||
version: 0.1.0
|
||||
description: >
|
||||
@@ -24,7 +24,7 @@ author: <you>
|
||||
requires_env:
|
||||
- name: IRIS_TOKEN
|
||||
description: "Shared pairing token the app presents on connect"
|
||||
prompt: "Android pairing token"
|
||||
prompt: "Iris pairing token"
|
||||
password: true
|
||||
optional_env:
|
||||
- name: IRIS_WS_HOST
|
||||
@@ -35,7 +35,7 @@ optional_env:
|
||||
description: "WS port (default 8790)"
|
||||
prompt: "WS port"
|
||||
password: false
|
||||
- name: ANDROID_HOME_CHANNEL
|
||||
- name: IRIS_HOME_CHANNEL
|
||||
description: "Default chat id for cron/notification delivery (default default)"
|
||||
prompt: "Home channel"
|
||||
password: false
|
||||
@@ -97,7 +97,7 @@ def register(ctx):
|
||||
install_hint="No extra packages needed (websockets + httpx are core deps)",
|
||||
setup_fn=interactive_setup, # hermes gateway setup flow
|
||||
env_enablement_fn=_env_enablement, # seed extra + home_channel from env
|
||||
cron_deliver_env_var="ANDROID_HOME_CHANNEL",
|
||||
cron_deliver_env_var="IRIS_HOME_CHANNEL",
|
||||
standalone_sender_fn=_standalone_send, # best-effort out-of-proc cron (stretch)
|
||||
parse_target_ref_fn=_parse_target_ref, # "iris:<chat>[:<thread>]"
|
||||
allowed_users_env="IRIS_ALLOWED_USERS",
|
||||
|
||||
@@ -23,10 +23,10 @@ gateway identity concepts**.
|
||||
## 6.2 Default chat
|
||||
|
||||
- On first connect, the plugin ensures a **default channel** exists:
|
||||
`chat_id = ANDROID_HOME_CHANNEL` (default `default`), `kind=default`,
|
||||
`chat_id = IRIS_HOME_CHANNEL` (default `default`), `kind=default`,
|
||||
`is_default=true`, name "Default".
|
||||
- It is also the **cron home channel** (`cron_deliver_env_var=
|
||||
ANDROID_HOME_CHANNEL`), so `deliver=android` (bare) routes here.
|
||||
IRIS_HOME_CHANNEL`), so `deliver=iris` (bare) routes here.
|
||||
- The app opens the default chat on launch.
|
||||
|
||||
## 6.3 Threads (toggle for overview)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# 10 — Android App (Kotlin + Jetpack Compose)
|
||||
# 10 — Iris App (Android; Kotlin + Jetpack Compose)
|
||||
|
||||
Native client. Lives in the Compose Multiplatform project at `app/`; the bulk of
|
||||
the code is in `app/shared` (commonMain) so the Desktop app reuses it.
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
# 11 — Desktop App (Kotlin + Compose Multiplatform)
|
||||
|
||||
The desktop app is **the Android app, tweaked for a big screen**. It reuses the
|
||||
The desktop app is **the Iris app, tweaked for a big screen**. It reuses the
|
||||
entire `app/shared` module (protocol, network, repositories, state, most UI) and
|
||||
only adds desktop platform services + a wider default layout.
|
||||
|
||||
## 11.1 What's shared vs desktop-specific
|
||||
|
||||
| Layer | Shared (commonMain) | Desktop-specific (desktopMain) |
|
||||
|---|---|---|
|
||||
| --- | --- | --- |
|
||||
| Protocol / WS client | ✅ | — |
|
||||
| Repositories / state | ✅ | — |
|
||||
| Most Compose UI | ✅ | layout tweaks, keyboard shortcuts |
|
||||
@@ -62,9 +62,9 @@ only adds desktop platform services + a wider default layout.
|
||||
- The desktop app connects to the **same** gateway WS server as the phone (the
|
||||
user's home server / Tailscale). It does **not** spawn its own backend (unlike
|
||||
hermes's existing Electron desktop, which spawns `hermes serve`) — our
|
||||
desktop is a pure client of the messaging gateway, matching the Android app.
|
||||
desktop is a pure client of the messaging gateway, matching the Iris app.
|
||||
|
||||
## 11.5 Parity checklist (same functionality as Android)
|
||||
## 11.5 Parity checklist (same functionality as the Iris app)
|
||||
|
||||
- [ ] Streaming, reasoning block, tool cards (3-level verbosity), commentary.
|
||||
- [ ] Channels + threads + new channel + cron target.
|
||||
|
||||
@@ -132,7 +132,7 @@ display:
|
||||
|
||||
```bash
|
||||
# 1. gateway up with plugin
|
||||
hermes gateway status | grep -i android
|
||||
hermes gateway status | grep -i iris
|
||||
|
||||
# 2. a raw WS client can pair + echo
|
||||
python - <<'PY'
|
||||
|
||||
+6
-2
@@ -10,16 +10,18 @@ without the app (critical for verifying frame shapes early).
|
||||
into the hermes `tests/gateway/test_android.py` pattern when running under
|
||||
hermes's suite).
|
||||
- **Run with hermes's hermetic runner** (never bare `pytest`):
|
||||
|
||||
```bash
|
||||
cd hermes-agent
|
||||
scripts/run_tests.sh tests/gateway/test_android.py
|
||||
scripts/run_tests.sh # full suite (CI parity)
|
||||
```
|
||||
|
||||
- Coverage to write (behavioral, not change-detector — per hermes test policy):
|
||||
- `register(ctx)` produces a valid `PlatformEntry` (name, cron env var,
|
||||
parse_target_ref).
|
||||
- `check_requirements` / `validate_config` / `is_connected` truth table.
|
||||
- `_parse_target_ref`: `iris:<chat>`, `iris:<chat>:<thread>`, non-android
|
||||
- `_parse_target_ref`: `iris:<chat>`, `iris:<chat>:<thread>`, non-iris
|
||||
→ None.
|
||||
- **Reasoning split:** given a `show_reasoning`-style final text, `send()`
|
||||
emits `message {reasoning, text}` correctly; no-prefix → no reasoning field.
|
||||
@@ -53,12 +55,13 @@ commentary classification and the reasoning prefix) before/while building the
|
||||
Kotlin client.
|
||||
|
||||
```bash
|
||||
hermes gateway & # with the android plugin
|
||||
hermes gateway & # with the iris plugin
|
||||
python gateway-plugin/tests/ws_probe.py --token <IRIS_TOKEN> \
|
||||
--send "list the files and summarize"
|
||||
# prints: hello.ack, typing, message.start, message.update…, tool.start, tool.end,
|
||||
# commentary, message.stop {reasoning,…}, …
|
||||
```
|
||||
|
||||
Use it to lock `04-wire-protocol.md` against reality and to debug the adapter
|
||||
without waiting for the app.
|
||||
|
||||
@@ -102,6 +105,7 @@ adb logcat -d > /tmp/logcat.txt
|
||||
```
|
||||
|
||||
**E2E scenarios (script where possible):**
|
||||
|
||||
1. **Pair:** connect screen → enter URL+token → `hello.ack` → main. (Verify auth
|
||||
leg, not just TCP.)
|
||||
2. **Text round-trip:** send "hello" → streamed reply appears (message.start →
|
||||
|
||||
@@ -161,11 +161,11 @@ has explicit **acceptance criteria**. Work top-to-bottom; don't skip M0/M1.
|
||||
- [x] `desktopMain`: tray + OS notifications; `MediaPlayer` actual (mpv/WebView);
|
||||
`MediaPicker` actual (file dialog); `SecureStore` actual; window mgmt.
|
||||
- [x] Two-pane default layout; keyboard shortcuts; optional inspector pane.
|
||||
- [ ] Parity pass vs Android feature checklist (`11-desktop-app.md`).
|
||||
- [ ] Parity pass vs Iris app feature checklist (`11-desktop-app.md`).
|
||||
- [x] jpackage builds (Linux first; macOS/Windows as available).
|
||||
- **Demo:** desktop app pairs to the same gateway; full feature parity; tray
|
||||
notifications; media plays.
|
||||
- **Accept:** all Android features work on desktop; tray + shortcuts work;
|
||||
- **Accept:** all Iris app features work on desktop; tray + shortcuts work;
|
||||
native binary launches.
|
||||
- **Status (complete, 2026-08-19):** All `desktopMain` actuals implemented and
|
||||
verified on Linux (X11). `DesktopSecureStore`: non-secrets in
|
||||
@@ -274,7 +274,7 @@ in-app scanner and `iris://pair` deep link (closes gap #12, `docs/20`).
|
||||
build it in M1.
|
||||
- **M3 (cron) and M5 (push) both touch the outbox** — build the outbox in M3,
|
||||
extend for push in M5.
|
||||
- **M6 (desktop) reuses M1–M5 shared code** — do it after the Android features
|
||||
- **M6 (desktop) reuses M1–M5 shared code** — do it after the Iris app features
|
||||
are stable so the shared module is settled.
|
||||
- Parallelizable: plugin (Python) and app (Kotlin) can be worked on
|
||||
concurrently once the protocol (`04-wire-protocol.md`) is agreed; the probe
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
| # | Decision | Choice | Rationale |
|
||||
| --- | --- | --- | --- |
|
||||
| 1 | Desktop app tech | **Compose Multiplatform** | Desktop = "the Android app, tweaked"; share protocol/state/UI. |
|
||||
| 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. |
|
||||
@@ -44,7 +44,7 @@ will proceed with unless you say otherwise.
|
||||
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_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.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# 18 — Code Review & Lint/LSP Cleanup (alpha → stable)
|
||||
|
||||
Comprehensive review of all three components — **gateway plugin**, **Android
|
||||
app**, and **Desktop app** — performed to take the project from alpha to a
|
||||
Comprehensive review of all three components — **gateway plugin**, **Iris app
|
||||
(Android)**, and **Desktop app** — performed to take the project from alpha to a
|
||||
clean, stable baseline. Each section records what was found, what was fixed,
|
||||
how it was verified, and what was deliberately left (with rationale).
|
||||
|
||||
@@ -50,7 +50,7 @@ findings. Categories:
|
||||
`hermes_cli.config`, but those live in `hermes_cli.cli_output`; it also imported
|
||||
a `print_code` that does not exist in hermes at all. The whole import block
|
||||
raised `ImportError`, which the surrounding `try/except` swallowed, so
|
||||
`hermes gateway setup` for the android platform **always bailed out early** with
|
||||
`hermes gateway setup` for the iris platform **always bailed out early** with
|
||||
"setup helpers unavailable" and never generated a token or prompted for
|
||||
host/port. Fixed by importing the print helpers from `hermes_cli.cli_output`,
|
||||
the env helpers from `hermes_cli.config`, and dropping the non-existent
|
||||
@@ -127,9 +127,9 @@ rule set (`E W F I UP B SIM PL RET C4`) and `line-length = 100`. Changes:
|
||||
|
||||
---
|
||||
|
||||
## 18.2 Android app (`app/androidApp` + `app/shared`)
|
||||
## 18.2 Iris app — Android (`app/androidApp` + `app/shared`)
|
||||
|
||||
The Android and Desktop apps share the `:shared` KMP module (`commonMain` +
|
||||
The Iris Android and Desktop apps share the `:shared` KMP module (`commonMain` +
|
||||
`jvmMain`), so most Kotlin code is covered here and in 18.3.
|
||||
|
||||
### 18.2.1 Findings (before)
|
||||
|
||||
@@ -315,7 +315,7 @@ interleaved (different languages, no shared surface).
|
||||
|
||||
- **QR display in the app** (showing a QR for other devices to scan) —
|
||||
single-device pairing today; revisit if multi-device lands.
|
||||
- **`hermes android pair` stretch CLI** (re-issue token + new QR,
|
||||
- **`hermes iris pair` stretch CLI** (re-issue token + new QR,
|
||||
`09-pairing-security.md` §9.2 line 48) — separate backlog item.
|
||||
- **WSS cert pinning** (gap #6) — orthogonal; QR carries `secure=1`
|
||||
already, pinning is app-side.
|
||||
|
||||
+3
-3
@@ -32,7 +32,7 @@ top-to-bottom once, then use the numbered docs as a lookup while implementing.
|
||||
| 7 | [`07-media.md`](07-media.md) | Media upload/download + playback. |
|
||||
| 8 | [`08-push.md`](08-push.md) | Push (ntfy default + FCM optional), outbox, sync. |
|
||||
| 9 | [`09-pairing-security.md`](09-pairing-security.md) | Pairing, auth, security model. |
|
||||
| 10 | [`10-android-app.md`](10-android-app.md) | When building the Android app. |
|
||||
| 10 | [`10-android-app.md`](10-android-app.md) | When building the Iris app (Android). |
|
||||
| 11 | [`11-desktop-app.md`](11-desktop-app.md) | When building the Desktop app. |
|
||||
| 12 | [`12-toolchain.md`](12-toolchain.md) | First time on a machine (JDK/SDK/uv/Firebase). |
|
||||
| 13 | [`13-testing.md`](13-testing.md) | Writing tests + on-device ADB workflow. |
|
||||
@@ -59,9 +59,9 @@ Machine-readable / diagrams:
|
||||
Python dependencies, zero hermes-core changes.**
|
||||
2. **`app/androidApp`** — native Kotlin + Jetpack Compose client.
|
||||
3. **`app/desktopApp`** — Kotlin + Compose Multiplatform client that *shares*
|
||||
the Android app's code and is "tweaked" for a big screen.
|
||||
the Iris app's code and is "tweaked" for a big screen.
|
||||
|
||||
The Android and Desktop clients live in **one Compose Multiplatform Gradle
|
||||
The Iris Android and Desktop clients live in **one Compose Multiplatform Gradle
|
||||
project** (`app/`) with a shared KMP module (`app/shared`).
|
||||
|
||||
---
|
||||
|
||||
@@ -6,8 +6,8 @@ flowchart TB
|
||||
AGENT["Agent core<br/>(run_agent.py)"]
|
||||
SESS["Sessions<br/>(SQLite + FTS5)"]
|
||||
CRON["Cron scheduler"]
|
||||
subgraph PLUGIN["android PLATFORM PLUGIN"]
|
||||
ADAPTER["AndroidAdapter<br/>(BasePlatformAdapter)"]
|
||||
subgraph PLUGIN["IRIS PLATFORM PLUGIN"]
|
||||
ADAPTER["IrisAdapter<br/>(BasePlatformAdapter)"]
|
||||
OUTBOX["Outbox (SQLite)<br/>+ sync cursor"]
|
||||
PUSH["push.py<br/>FcmBackend / NtfyBackend"]
|
||||
MEDIA["media.py<br/>cache + chunk stream"]
|
||||
@@ -33,7 +33,7 @@ flowchart TB
|
||||
end
|
||||
|
||||
subgraph DEVICES["Clients"]
|
||||
PHONE["ANDROID APP<br/>(Kotlin / Compose)<br/>WS client + ExoPlayer + FCM"]
|
||||
PHONE["IRIS APP (ANDROID)<br/>(Kotlin / Compose)<br/>WS client + ExoPlayer + FCM"]
|
||||
DESKTOP["DESKTOP APP<br/>(Compose Multiplatform)<br/>WS client + tray + desktop player"]
|
||||
end
|
||||
|
||||
|
||||
+1
-1
@@ -56,7 +56,7 @@ hermes gateway # or: hermes gateway restart after config changes
|
||||
> the LAN, re-run `hermes gateway setup` (or edit `~/.hermes/.env`) and set
|
||||
> `IRIS_WS_HOST` to the host's LAN IP (e.g. `192.168.1.10`).
|
||||
|
||||
## 2. Android app
|
||||
## 2. Iris app (Android)
|
||||
|
||||
Build and install (ADB device connected):
|
||||
|
||||
|
||||
Reference in new issue
Block a user