%% Iris x Hermes — architecture (mermaid) %% Render with any mermaid viewer (e.g. https://mermaid.live or `mmdc`). flowchart TB subgraph HOST["User's machine (home server / PC)"] subgraph GW["hermes gateway (ONE process)"] AGENT["Agent core
(run_agent.py)"] SESS["Sessions
(SQLite + FTS5)"] CRON["Cron scheduler"] subgraph PLUGIN["android PLATFORM PLUGIN"] ADAPTER["AndroidAdapter
(BasePlatformAdapter)"] OUTBOX["Outbox (SQLite)
+ sync cursor"] PUSH["push.py
FcmBackend / NtfyBackend"] MEDIA["media.py
cache + chunk stream"] PAIR["pairing.py
token + device registry"] SEARCH["search.py
FTS5 bridge"] end WSS["WebSocket SERVER
(websockets) ws://host:8790/ws"] end AGENT -->|legacy stream callbacks| ADAPTER CRON -->|deliver=android:chat:thread| ADAPTER ADAPTER <--> WSS ADAPTER <--> OUTBOX ADAPTER <--> PUSH ADAPTER <--> MEDIA ADAPTER <--> PAIR ADAPTER <--> SEARCH ADAPTER <--> SESS end subgraph CLOUD["Cloud relays"] FCM["Google FCM"] NTFY["ntfy (self-host / ntfy.sh)"] end subgraph DEVICES["Clients"] PHONE["ANDROID APP
(Kotlin / Compose)
WS client + ExoPlayer + FCM"] DESKTOP["DESKTOP APP
(Compose Multiplatform)
WS client + tray + desktop player"] end WSS <-->|WSS JSON + binary media| PHONE WSS <-->|WSS JSON + binary media| DESKTOP PUSH -->|FCM HTTP v1| FCM PUSH -->|ntfy publish| NTFY FCM -->|wake (data msg)| PHONE NTFY -->|subscribe| PHONE classDef host fill:#eef,stroke:#333; classDef plugin fill:#efe,stroke:#333; classDef device fill:#fee,stroke:#333; classDef cloud fill:#ffe,stroke:#333; class GW,AGENT,SESS,CRON,OUTBOX,PUSH,MEDIA,PAIR,SEARCH,WSS host; class ADAPTER plugin; class PHONE,DESKTOP device; class FCM,NTFY cloud;