5.5 KiB
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 inhermes config/setup).adapter.py—IrisAdapter(BasePlatformAdapter)+register(ctx). The heart of the plugin. See03-gateway-plugin.md.ws_server.py—websocketsserver, 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.jsonis generated/mirrored from it).media.py— inbound chunked upload →cache_*_from_bytes; outboundmedia.offer/media.pullchunked streaming.outbox.py— SQLite outbox perchat_id+ monotonic sync cursor.push.py—PushBackendinterface;FcmBackend(httpx, FCM HTTP v1) andNtfyBackend(reuses hermes ntfy publish). Selected byIRIS_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,MediaPlayeractual.desktopMain— tray + OS notifications, desktop player, file dialog, window management,MediaPlayeractual.
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'sscripts/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 underhermes-agent/is staged.
Install layout (runtime)
- Plugin:
~/.hermes/plugins/iris/← copy ofgateway-plugin/(or a symlink for dev). Discovered by hermes'sPluginManager. - App (dev): installed on-device via
./gradlew :androidApp:installDebug. - App (desktop, dev):
./gradlew :desktopApp:run.