Files
iris_x_hermes/docs/02-monorepo.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.5 KiB

02 — Monorepo Structure

One repository, three artifacts. hermes-agent/ is not part of the repo (git-ignored reference).

Top-level tree

iris_x_hermes/
├── .gitignore                  # MUST exclude hermes-agent/ (see below)
├── README.md                   # Repo root readme (short; points to docs/)
├── docs/                       # ← THIS reference library
│
├── hermes-agent/               # ⚠️ READ-ONLY REFERENCE — NEVER PUSHED (git-ignored)
│
├── gateway-plugin/             # ① Python plugin → installed to ~/.hermes/plugins/iris
│   ├── plugin.yaml             #    manifest (kind: platform, env vars, home channel)
│   ├── __init__.py
│   ├── adapter.py              #    IrisAdapter(BasePlatformAdapter) + register(ctx)
│   ├── ws_server.py            #    websockets server, connection registry, framing
│   ├── protocol.py             #    frame schemas (source of truth, mirrored in Kotlin)
│   ├── media.py                #    inbound cache + outbound chunked streaming
│   ├── outbox.py               #    SQLite offline outbox + sync cursor
│   ├── push.py                 #    PushBackend: FcmBackend + NtfyBackend
│   ├── pairing.py              #    token gen/verify, device registry
│   ├── search.py               #    FTS5 session search bridge
│   └── tests/                  #    pytest (run via hermes scripts/run_tests.sh)
│
├── app/                        # ② + ③ Compose Multiplatform project (Kotlin)
│   ├── settings.gradle.kts
│   ├── build.gradle.kts
│   ├── gradle.properties
│   ├── gradle/  gradlew  gradlew.bat
│   ├── shared/                 #    KMP module — the bulk of the code
│   │   ├── build.gradle.kts
│   │   └── src/
│   │       ├── commonMain/kotlin/iris/…   # protocol, WS client, repo, state, Compose UI
│   │       ├── androidMain/kotlin/…       # FCM, ExoPlayer, SAF picker, notifications
│   │       └── desktopMain/kotlin/…       # tray, file dialog, player, window
│   ├── androidApp/             #    thin Android shell (Application, MainActivity)
│   │   ├── build.gradle.kts
│   │   └── src/main/…          #    AndroidManifest, res, Firebase options
│   └── desktopApp/             #    thin Desktop shell (main(), window)
│       ├── build.gradle.kts
│       └── src/main/kotlin/…
│
└── (no other top-level code)

Module responsibilities

gateway-plugin/ (Python)

  • plugin.yaml — manifest: name: iris-platform, kind: platform, requires_env / optional_env (surfaced in hermes config/setup).
  • adapter.py — IrisAdapter(BasePlatformAdapter) + register(ctx). The heart of the plugin. See 03-gateway-plugin.md.
  • ws_server.py — websockets server, per-device connection registry, frame encode/decode, heartbeat, broadcast routing to all connected devices.
  • protocol.py — dataclasses/constants for every frame (single source of truth; docs/protocol/frames.schema.json is generated/mirrored from it).
  • media.py — inbound chunked upload → cache_*_from_bytes; outbound media.offer/media.pull chunked streaming.
  • outbox.py — SQLite outbox per chat_id + monotonic sync cursor.
  • push.py — PushBackend interface; FcmBackend (httpx, FCM HTTP v1) and NtfyBackend (reuses hermes ntfy publish). Selected by IRIS_PUSH_BACKEND.
  • pairing.py — token generation/verification (constant-time), device registry (SQLite), QR payload.
  • search.py — FTS5 query bridge over the hermes session store.

app/shared (Kotlin KMP)

  • commonMain — protocol models (kotlinx-serialization), GatewayClient (OkHttp WS), repositories (Room), ViewModels (StateFlow), and the Compose UI (design system, screens). ~80% of app code.
  • androidMain — FCM service, ExoPlayer, SAF media picker, system notifications, MediaPlayer actual.
  • desktopMain — tray + OS notifications, desktop player, file dialog, window management, MediaPlayer actual.

app/androidApp / app/desktopApp

Thin shells: Application/MainActivity (Android) and main()/window (Desktop). They compose the shared UI and inject platform services.

Build systems

  • Python plugin: no build step (pure Python, stdlib + hermes core deps). Installed by copying/symlinking into ~/.hermes/plugins/iris. Tested with hermes's scripts/run_tests.sh.
  • Kotlin/CMP: Gradle (Kotlin DSL) with the Compose Multiplatform plugin. ./gradlew :androidApp:installDebug, ./gradlew :desktopApp:run, ./gradlew :shared:testDebugUnitTest.

.gitignore (root) — critical

# hermes-agent is a read-only research reference — NEVER commit/push it
/hermes-agent/

# Python
__pycache__/
*.pyc
.venv/
venv/

# Kotlin / Gradle
.gradle/
build/
local.properties
*.iml
.idea/

# Android / Firebase
app/androidApp/src/main/res/values/secrets.xml
google-services.json
*.jks
keystore.jks

# OS / misc
.DS_Store
*.log

The /hermes-agent/ line is non-negotiable. Add a pre-commit guard (or CI check) that fails if any path under hermes-agent/ is staged.

Install layout (runtime)

  • Plugin: ~/.hermes/plugins/iris/ ← copy of gateway-plugin/ (or a symlink for dev). Discovered by hermes's PluginManager.
  • App (dev): installed on-device via ./gradlew :androidApp:installDebug.
  • App (desktop, dev): ./gradlew :desktopApp:run.