- 'No file limit' -> 100 MB default, configurable via max_upload_bytes - 'No character limit' -> 'No 4,096-character limit like Telegram' (hard frame-body cap: 1 MiB) - Note that limits are set on the gateway side (hermes), not in the app - Sync docs/playstore-listing.md (same overclaim)
159 lines
6.7 KiB
Markdown
159 lines
6.7 KiB
Markdown
# Iris × Hermes
|
||
|
||
A chat app for [hermes-agent](https://github.com/NousResearch/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 WebSocket 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!** — everything stays on your own infrastructure
|
||
(push: ntfy by default; FCM is opt-in and routes push metadata via Google —
|
||
see [Push notifications](#push-notifications))
|
||
- **100 MB file uploads by default** — configurable on the gateway via
|
||
`max_upload_bytes` (see [Media](docs/07-media.md) §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 ──(WebSocket :8790)──> Iris app (Android / Desktop)
|
||
```
|
||
|
||
- `gateway-plugin/` is a hermes **platform plugin** (`android`). It runs inside the
|
||
`hermes gateway` process and opens a WebSocket 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)** — push metadata stays on your own infrastructure
|
||
(self-hosted ntfy recommended). This is the backend for truly private
|
||
communication.
|
||
- **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/setup.md`](docs/setup.md) §4; details:
|
||
[`docs/08-push.md`](docs/08-push.md).
|
||
|
||
## Build from source
|
||
|
||
### Prerequisites
|
||
|
||
| Where | You need |
|
||
| --- | --- |
|
||
| Gateway host | [hermes-agent](https://github.com/NousResearch/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)
|
||
|
||
```bash
|
||
# hermes-agent is a separate project (not part of this repo)
|
||
cd hermes-agent && uv sync
|
||
|
||
# install the Iris plugin into the live hermes home
|
||
mkdir -p ~/.hermes/plugins
|
||
ln -s "$PWD/gateway-plugin" ~/.hermes/plugins/android
|
||
hermes gateway status # should list "android"
|
||
|
||
hermes gateway setup # generates ANDROID_TOKEN, prints the server URL
|
||
hermes gateway # run the gateway
|
||
```
|
||
|
||
### 2. Android app
|
||
|
||
```bash
|
||
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
|
||
|
||
```bash
|
||
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** — `ws://<gateway-ip>:8790/ws` (printed by `hermes gateway setup`).
|
||
2. **Pairing token** — from the setup output, or `ANDROID_TOKEN` in `~/.hermes/.env`
|
||
on the gateway host.
|
||
3. **Test & Connect.**
|
||
|
||
Notes:
|
||
|
||
- The app has **no QR scanner** — pairing is manual URL + token entry.
|
||
- The default bind is `127.0.0.1` (desktop on the same machine only). For a phone
|
||
on the LAN, set `ANDROID_WS_HOST` to the gateway's LAN IP.
|
||
- Remote access: Tailscale/WireGuard, or a reverse proxy with CA-signed WSS
|
||
(`ANDROID_WS_CERT` / `ANDROID_WS_KEY`).
|
||
|
||
Full walkthrough, push setup (ntfy/FCM), and troubleshooting:
|
||
[`docs/setup.md`](docs/setup.md).
|
||
|
||
## Contributing
|
||
|
||
Contributions are welcome! Before you start:
|
||
|
||
1. **Read the docs.** The full reference library is in [`docs/`](docs/README.md) —
|
||
start with [`docs/00-overview.md`](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): `gateway-plugin/tests/ws_probe.py` and
|
||
`gateway-plugin/tests/e2e.py` — see [`gateway-plugin/tests/README.md`](gateway-plugin/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](LICENSE).
|