Pakobbix 2c1d444348
CI / Kotlin tests (android host + desktop) (push) Successful in 5m47s
CI / Gateway plugin tests (push) Failing after 15m58s
Merge pull request 'fix(http): don't let a half-open TLS connection wedge the accept loop' (#16) from fix/iris-tls-handshake-wedge into master
Reviewed-on: #16
2026-09-23 13:10:53 +00:00

Iris × Hermes

A chat app for hermes-agent: a native Android app and a desktop app (Linux, macOS, Windows) — both built from one shared Kotlin codebase (Compose Multiplatform).

Iris pairs with your running hermes gateway over a private, token-authenticated connection and gives you a Telegram-quality chat experience with your personal agent: streaming replies, visible reasoning, structured tool activity, channels, threads, media, search, and push notifications.

Features

  • Native Hermes-Gateway integration — your hermes → gateway → Iris app
  • Absolute Privacy! — chat stays on your own infrastructure (push: ntfy by default, but the default ntfy server is the public ntfy.sh — self-host ntfy to keep push metadata on your own machine; FCM is opt-in and routes push metadata via Google — see Push notifications)
  • 100 MB file uploads by default — configurable on the gateway via max_upload_bytes (see Media §7.7); all limits are set on the gateway side (hermes), not in the app
  • No 4,096-character message limit like Telegram — messages travel over your own gateway (hard frame-body cap: 1 MiB)
  • Full markdown support — tables, checkmarks, bold, inline code, code blocks + syntax highlighting…
  • HTML Artifact Preview — agent-sent HTML/CSS/JS rendered in an in-app WebView
  • All settings live in the app, not in hermes config.yml! Change everything on the fly.
  • Channels — create channels to keep track of your reports, cronjobs, webhook calls
  • Pin channels, rename them, change the color/icon
  • Customize how your chat should look like — color? Check! Images? Check!
  • Reasoning collapse/expandable in the chat bubble
  • Change the default behavior of tool & reasoning verbosity
  • Threads — create your own, or let the AI create them with a title
  • Search messages from everywhere

How it works

hermes-agent ──> hermes gateway ──(HTTP :8791)──> Iris app (Android / Desktop)
  • gateway-plugin/ is a hermes platform plugin (android). It runs inside the hermes gateway process and opens an HTTP server the apps connect to. Zero new Python dependencies, zero hermes-core changes.
  • app/ is one Compose Multiplatform Gradle project: :shared (KMP, most of the code), :androidApp (native Kotlin + Jetpack Compose client), :desktopApp (the same app, tweaked for a big screen).
  • The app is a first-class hermes messaging platform, so everything the gateway already does just works: slash commands, cron delivery, send_message routing, coexistence with Telegram/Discord/etc.
  • Push notifications: ntfy (default) or FCM (opt-in).

Push notifications

Push wakes a backgrounded/offline device; on reconnect the app syncs the outbox, so nothing is lost.

  • ntfy (default) — the backend for truly private communication. ⚠️ By default it uses the public https://ntfy.sh cloud service — push metadata (topic, notification title) passes through ntfy.sh's servers. Set NTFY_SERVER_URL to a self-hosted ntfy to keep push metadata on your own infrastructure (recommended; public ntfy.sh SSE is also flaky).
  • FCM (opt-in, IRIS_PUSH_BACKEND=fcm) — standard/reliable, but FCM push metadata (notification title, device token) is routed through Google's servers. If you want truly private communication, use ntfy instead.

Setup: docs/install.md; details: docs/08-push.md.

Install the gateway

Three commands on the machine where hermes runs:

cd hermes-agent && uv sync    # 1. hermes with its venv (separate project, not this repo)

# 2. install the Iris plugin — the #gateway-plugin suffix points the
#    installer at the plugin subfolder of this monorepo
hermes plugins install git@gitea.zephyre.one:ARIA/iris_x_hermes.git#gateway-plugin

# 3. generate the pairing token + server URL, then run the gateway
hermes gateway setup
hermes gateway

hermes gateway setup prints the server URL and pairing token / QR the app needs on its Connect screen.

All options (LAN binding, TLS, push, device allowlist) and the full app pairing walkthrough: docs/install.md.

Build from source

Prerequisites

Where You need
Gateway host hermes-agent with its venv (uv sync)
Android build machine JDK 17, Android SDK (sdk.dir in app/local.properties or ANDROID_HOME), ADB with a connected device
Desktop build machine JDK 17 only

No system Gradle needed — both apps use the project wrapper (./gradlew).

1. Gateway (on the gateway host)

If you're developing from a checkout, skip hermes plugins install and symlink the plugin so it always tracks your working tree:

cd hermes-agent && uv sync
mkdir -p ~/.hermes/plugins
ln -s "$PWD/gateway-plugin" ~/.hermes/plugins/iris
hermes gateway status        # should list the Iris platform

hermes gateway setup         # generates IRIS_TOKEN, prints server URL + pairing QR
hermes gateway               # run the gateway

(Otherwise see Install the gateway above.)

2. Android app

cd app
./gradlew :androidApp:installDebug    # build + install on the connected ADB device
# or just build the APK:
./gradlew :androidApp:assembleDebug   # → app/androidApp/build/outputs/apk/debug/

3. Desktop app

cd app
./gradlew :desktopApp:run             # dev run
./gradlew :desktopApp:jpackage        # native app-image (bundles the JRE)

4. Pair

On the app's Connect screen:

  1. Server URL — http://<gateway-ip>:8791 (printed by hermes gateway setup).
  2. Pairing token — from the setup output, or IRIS_TOKEN in ~/.hermes/.env on the gateway host.
  3. Test & Connect.

Notes:

  • Android has a Scan QR button that reads the QR printed by hermes gateway setup and pre-fills URL + token; desktop uses manual entry.
  • The default bind is 127.0.0.1 (desktop on the same machine only). For a phone on the LAN, set IRIS_HTTP_HOST to the gateway's LAN IP.
  • Remote access: Tailscale/WireGuard, or a reverse proxy/tunnel with TLS (IRIS_HTTP_CERT / IRIS_HTTP_KEY).

Full walkthrough, push setup (ntfy/FCM), TLS, and troubleshooting: docs/install.md.

Contributing

Contributions are welcome! Before you start:

  1. Read the docs. The full reference library is in docs/ — start with docs/00-overview.md, then follow the numbered docs (architecture, wire protocol, plugin design, testing, …).

  2. Know the layout.

    Path What
    gateway-plugin/ Python hermes platform plugin (android); protocol.py is the frame source of truth
    app/shared KMP module with most of the client code (shared by Android + Desktop)
    app/androidApp Thin Android shell (package dev.iris.app)
    app/desktopApp Thin desktop shell
    docs/ Numbered reference library
  3. Run the tests.

    • Python (gateway plugin): cd hermes-agent && scripts/run_tests.sh tests/gateway/test_android.py (never bare pytest — hermes's runner sandboxes HERMES_HOME).
    • Kotlin: cd app && ./gradlew :shared:testDebugUnitTest
    • Live check (gateway must be running): tests/ws_probe.py and tests/e2e.py — see tests/README.md.
  4. Keep the protocol in sync. gateway-plugin/protocol.py, app/shared/.../protocol/Protocol.kt, and docs/protocol/frames.schema.json must always agree.

  5. Pre-commit hooks are configured (.pre-commit-config.yaml); run pre-commit install once after cloning.

Open an issue first for anything big, then send a pull request.

License

Apache License 2.0 — see LICENSE.

S
Description
Iris × Hermes — native Android + Desktop client for hermes-agent via a gateway platform plugin. Compose Multiplatform app (Kotlin) + Python WebSocket gateway adapter. See docs/ for the full reference library.
Readme Apache-2.0
7.8 MiB
0 Stars 1 Watchers 0 Forks
Latest
2026-08-31 21:44:41 +00:00
Languages
Kotlin 52.2%
Python 47.4%
Shell 0.4%