Android client for Hermes Agent — chat with your Hermes sessions from a phone or tablet over local Wi-Fi or a private Tailscale network.
- Version: 1.0.8
- Package:
com.hermesagent.hermes_android - Recommended APK for most modern phones:
app-arm64-v8a-release.apk - Other APKs:
app-armeabi-v7a-release.apk,app-x86_64-release.apk - Download: GitHub Releases
- Reverse-proxy path prefixes — configure separate path prefixes for the Gateway API and dashboard, e.g.
/profile/peterbefore/apiand/v1, and/dashboardbefore dashboard/apiroutes. - Proxied dashboard mode — enable Dashboard behind proxy when nginx/Caddy/your host injects dashboard authentication. In this mode the app sends clean dashboard requests without trying to scrape a dashboard session token or perform password login.
- Prefix-aware validation and chat — API-key validation, session browsing, existing chat history, streaming chat completions, and dashboard drawer screens all use the configured prefixes.
- Password-protected dashboards — the Memory/Cron/Skills/Settings tabs now work against a dashboard secured with basic-auth, not just an open (
--insecure) one. The app logs in via the dashboard's/auth/password-loginflow and reuses the session cookie (the same mechanism the desktop client uses). - Configurable dashboard port — set a custom dashboard port per connection when it isn't the default
9119. - Dashboard details in the connection flow — set the dashboard port/username/password while adding a connection (expand Custom dashboard details) or later via ⋮ → Dashboard Login, with validation before saving.
- Voice chat support — tap the microphone in chat to dictate a message to Hermes, and Hermes can speak the response back.
- Spoken replies can be toggled from the chat input bar.
- Android/iOS microphone and speech-recognition permissions are included.
- Hermes chat on Android — browse sessions, create new chats, and send prompts to your Hermes Agent.
- Streaming responses — chat uses the Hermes Gateway OpenAI-compatible streaming endpoint:
POST /v1/chat/completions. Tokens appear in real-time with smooth auto-scroll. - Messaging-style UI — dark/light/system themes, gold Hermes accent color (
#D4AF37), markdown rendering, relative timestamps, and responsive phone/tablet layouts. - Gold/black Hermes branding — distinctive gold accent on black background, custom app icon with mipmap densities, agent messages use grey bubbles.
- Gateway API integration — sessions and chat run through the Hermes Gateway API Server, normally on port
8642, with HTTP and HTTPS endpoints supported. Reverse-proxy deployments can set a gateway path prefix that is applied before/apiand/v1routes. - Dashboard integrations — Memory, Cron Jobs, Skills, and Settings screens use the Hermes dashboard API (default port
9119, configurable per connection) on the same host. Works with open (--insecure) dashboards, password-protected dashboards via the built-in login, and proxied dashboards where auth is injected upstream. - Model settings — view and change the configured Hermes model where the dashboard exposes model settings.
- Cron management — list, trigger, pause/resume, create, edit, and delete scheduled Hermes cron jobs.
- Skills browser — view available Hermes skills with descriptions and trigger conditions.
- Memory viewer — inspect conversation memory across sessions.
- Verbose mode toggle — show raw message metadata (role, tool calls, timestamps) in chat.
- Three-way theme toggle — Dark / Light / System default.
- Keyboard handling — auto-scroll on keyboard open, send action on Enter, FAB to scroll to bottom.
- Voice chat — microphone dictation sends recognised speech to Hermes, with optional text-to-speech replies.
![]() Session list |
![]() Navigation drawer |
![]() Cron jobs |
![]() Add cron job |
![]() Memory |
![]() Settings |
![]() Skills |
- Android device or emulator (Android 8+).
- Hermes Agent installed on the host machine.
- Hermes Gateway API Server reachable from the Android device.
API_SERVER_KEYfrom the Hermes host environment (~/.hermes/.env).- Optional: Hermes dashboard reachable for Memory/Cron/Skills/Settings screens.
Hermes Agent docs: https://hermes-agent.nousresearch.com/docs
Download the latest APK from the GitHub Releases page.
For most Android phones, install the arm64 APK:
adb install app-arm64-v8a-release.apkIf sideloading directly on Android, enable Install unknown apps for your browser or file manager, then open the downloaded APK.
The Android chat/session features connect to the Hermes Gateway API Server. It must bind to an address your phone can reach, not only 127.0.0.1.
Use your normal Hermes gateway/API-server startup command and confirm:
- host/IP is reachable from Android
- port is usually
8642 API_SERVER_KEYis available in~/.hermes/.env
Memory, Cron Jobs, Skills, and Settings use the Hermes dashboard API (default port 9119).
Open dashboard (no login):
hermes dashboard --insecure --host 0.0.0.0 --tui --port 9119Password-protected dashboard (recommended on shared networks) — start it with a
basic-auth provider instead of --insecure, then enter the username/password in
the app's Dashboard / Proxy Settings dialog (see Dashboard access).
--host 0.0.0.0is required when connecting from another device. A localhost-only dashboard cannot be reached from Android.
-
Put the Android device and Hermes host on the same Wi-Fi/LAN (or connect via Tailscale — see below).
-
Find the Hermes host IP:
# macOS ipconfig getifaddr en0 # Linux hostname -I | awk '{print $1}'
-
Open the Hermes Android app.
-
Tap + to add a connection.
-
Enter:
- Label: any name, e.g.
Home - Host: the host IP, e.g.
192.168.1.50 - Port:
8642 - API Key:
API_SERVER_KEYfrom the Hermes machine
- Label: any name, e.g.
-
If your deployment is behind a reverse proxy path, expand Custom proxy and dashboard details and set the gateway/dashboard prefixes there. Do not put URL paths in the Host field; the Host field is just the scheme, hostname, and optional port.
-
Tap the saved connection to browse sessions.
-
Tap a session to start chatting, or create a new one.
The drawer screens (Memory, Cron Jobs, Skills, Settings) talk to the Hermes dashboard, which can run on a different port from the Gateway API Server and may be password-protected. Configure it per connection — either while adding the connection (expand Custom proxy and dashboard details in the Add Connection dialog) or afterwards:
- On the connections list, tap the ⋮ menu on a connection → Dashboard / Proxy Settings.
- Fill in:
- Gateway path prefix — optional reverse-proxy path before gateway
/apiand/v1routes, e.g./profile/peter. - Dashboard path prefix — optional reverse-proxy path before dashboard
/apiroutes, e.g./dashboard. - Dashboard behind proxy — enable this when the proxy injects dashboard authentication and the app should not fetch a dashboard SPA token or log in with username/password.
- Dashboard Port — leave blank to use the default (
9119for HTTP, or the same external port for HTTPS deployments), or set an explicit port if your dashboard is exposed elsewhere. - Username / Password — only for a password-protected dashboard. Leave
both blank for an open (
--insecure) dashboard.
- Gateway path prefix — optional reverse-proxy path before gateway
- Tap Save. The app validates the settings against the dashboard before storing them.
When credentials are set, the app authenticates via the dashboard's
/auth/password-login flow and reuses the returned session cookie — the same
mechanism the Hermes desktop client uses.
Tailscale gives your phone and Hermes machine a private encrypted network, so you do not need to expose Hermes directly to the public internet.
Tailscale website: https://tailscale.com/
- Install Tailscale for Android: https://tailscale.com/download/android
- Sign in with the same Tailscale account/tailnet used by your Hermes machine.
- Leave Tailscale connected while using the Hermes app.
Install Tailscale for your OS: https://tailscale.com/download
Examples:
# macOS with Homebrew
brew install --cask tailscale
# Debian/Ubuntu
curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale upAfter the Hermes machine is connected, get its Tailscale address:
tailscale ip -4You can also enable MagicDNS and use the machine name instead of the 100.x.y.z IP:
- MagicDNS docs: https://tailscale.com/kb/1081/magicdns
In the Android app connection dialog:
- Host: the Hermes machine Tailscale IP, e.g.
100.64.12.34, or its MagicDNS name - Port:
8642 - API Key:
API_SERVER_KEY
If using Memory/Cron/Skills/Settings remotely, keep the dashboard reachable on the same Tailscale host at port 9119.
For hosted/reverse-proxy deployments (e.g., Hugging Face Spaces, VPS with nginx/Caddy), enter the full HTTPS URL in the Host field:
https://your-hermes-host.example.com
If no port is included, the app uses port 443. If your HTTPS service uses a custom port, either include it in the URL (https://host.example.com:8443) or set the Port field to that value before connecting.
For HTTPS connections, dashboard drawer screens use the same external HTTPS port. For local HTTP/LAN connections, chat uses port 8642 and dashboard screens use port 9119.
If your proxy exposes Hermes under URL paths, keep the Host field to the origin only and put paths in Custom proxy and dashboard details:
Host: https://your-hermes-host.example.com
Port: 443
Gateway path prefix: /profile/peter
Dashboard path prefix: /dashboard
Dashboard behind proxy: on, if the proxy injects dashboard auth
With that setup, the app calls gateway routes such as
https://your-hermes-host.example.com/profile/peter/v1/chat/completions and
dashboard routes such as
https://your-hermes-host.example.com/dashboard/api/model/info.
- Prefer Tailscale/VPN for remote use.
- Do not port-forward the Gateway API Server or dashboard directly to the public internet.
- Rotate
API_SERVER_KEYif it is shared or exposed. - Local/Tailscale examples use HTTP, so the private network boundary matters. Use HTTPS for public or hosted endpoints.
Android app (Flutter)
├─ Gateway API Server, port 8642 or HTTPS proxy prefix
│ ├─ GET /api/sessions
│ ├─ GET /api/sessions/{id}/messages
│ └─ POST /v1/chat/completions (SSE streaming)
└─ Hermes dashboard, port 9119 or HTTPS proxy prefix
├─ /api/memory
├─ /api/cron/jobs
├─ /api/skills
└─ /api/model/*
- Send messages — Type in the input field and tap the send button or press Enter.
- Streaming responses — The agent's response appears token-by-token in real-time. The chat auto-scrolls to the bottom as new tokens arrive.
- Tool progress — When the agent uses tools, inline progress messages show the tool name, status, and progress.
- Verbose mode — Toggle in the app settings to show raw message metadata (role, tool call IDs, timestamps).
- Markdown rendering — Assistant messages render markdown (code blocks, tables, lists, links).
- Relative timestamps — Messages show "2m ago", "3h ago", etc.
The chat input bar has two voice controls:
| Button | Icon | What it does |
|---|---|---|
| Mic | 🎤 / 🎤🔴 | Tap to start voice dictation. Speak your message — it appears in the input field and sends automatically when you pause. Tap again (or the red stop icon) to cancel. |
| Voice reply toggle | 🔊 / 🔇 | Toggles whether Hermes reads its response aloud after a voice-input message. On = 🔊 (volume up), Off = 🔇 (volume off). |
How voice replies work:
- Tap the mic, speak your question, and wait for the recognition to finish (the text appears and auto-sends).
- Hermes streams its response as text in the chat as usual.
- After the full response arrives, if the voice reply toggle is on (🔊), the app reads the response aloud using text-to-speech.
Voice replies only trigger when you send a message via the mic button. Typed messages produce text responses only.
Spoken replies require Google Text-to-Speech to be installed and configured on your device. The app uses the device's built-in TTS engine — it does not bundle its own voices.
Step-by-step:
- Install Google Text-to-Speech — If not already on your device, install from the Play Store: Google Text-to-Speech
- Set as default engine — Settings → Accessibility → Text-to-speech output → Preferred engine → Google Text-to-Speech
- Download voice data — In the same TTS settings screen, tap the gear icon ⚙️ next to Google Text-to-Speech → Install voice data → select English (Australia) or your preferred English voice → download
- Check media volume — TTS uses the media audio stream, not the ringer. Turn up media volume and make sure your phone isn't in silent/vibrate-only mode.
- Test TTS — In the TTS settings screen, tap "Play" to hear a test phrase. If you hear it, the app should work.
Troubleshooting voice:
- Mic button does nothing — Speech recognition may be unavailable on your device. Ensure Google app is installed and has microphone permission.
- Voice reply toggle is on (🔊) but Hermes doesn't speak — Google TTS is likely not installed or has no voice data downloaded. Follow the TTS setup steps above.
- Hermes speaks quietly or too fast — Adjust speech rate and volume in Settings → Accessibility → Text-to-speech output.
- Recognition is inaccurate — Speak clearly, reduce background noise, and check that the device's system language includes English.
- Browse all Hermes sessions.
- Tap a session to open its chat.
- Pull to refresh the session list.
- Create a new session from the session list header.
Access these dashboard-powered screens:
- Memory — View conversation memory across sessions. Shows stored facts, preferences, and project context.
- Cron Jobs — List all scheduled cron jobs. Trigger, pause/resume, create, edit, or delete jobs.
- Skills — Browse available Hermes skills with descriptions and trigger conditions.
- Settings — View and change the configured Hermes model, theme preference, and verbose mode.
- Three-way toggle: Dark / Light / System default.
- Gold Hermes accent (
#D4AF37) on dark mode; adapted for light mode.
The Cron Jobs screen supports full CRUD:
- List — See all jobs with status (enabled/disabled), next run, and schedule.
- Create — Tap + to add a new job with schedule (cron expression or interval), prompt, and optional skills.
- Edit — Tap a job to modify its schedule, prompt, skills, or status.
- Trigger — Manually run a job immediately.
- Pause/Resume — Toggle job enabled state.
- Delete — Remove a job (with confirmation).
cd hermes-android
flutter pub get
flutter analyze
flutter test
flutter run -d androidflutter clean
flutter pub get
flutter build apk --release --split-per-abi
mkdir -p release-apks
cp build/app/outputs/flutter-apk/app-*-release.apk release-apks/Output files:
build/app/outputs/flutter-apk/app-arm64-v8a-release.apk
build/app/outputs/flutter-apk/app-armeabi-v7a-release.apk
build/app/outputs/flutter-apk/app-x86_64-release.apk
Every release PR must complete CODE_QUALITY_CHECKLIST.md before tagging or publishing APKs. The checklist covers analysis, architecture, UX, security, release, and manual smoke-test checks.
Minimum release flow:
- Update
pubspec.yamlversion. - Complete
CODE_QUALITY_CHECKLIST.mdand record any exceptions in the release PR. - Build split release APKs.
- Tag the release, e.g.
v1.0.0. - Create a GitHub Release with all APK assets.
- Confirm the repository visibility and release assets on GitHub.
Chat/session features use port 8642. Memory, Cron Jobs, Skills, and Settings use the dashboard on port 9119. Start the dashboard with --host 0.0.0.0 and make sure port 9119 is reachable over Wi-Fi or Tailscale.
Check that the Android connection's API key matches API_SERVER_KEY from the Hermes machine (~/.hermes/.env).
- Verify phone and host are on the same Wi-Fi or same Tailscale tailnet.
- Try the raw IP before a hostname.
- Check local firewall rules for ports
8642and9119. - On Android, ensure the app has network permission (granted by default).
- The SSE connection may have timed out. Pull to refresh the session list and re-enter the chat.
- Check that the Gateway API Server is running and responsive:
curl http://<host>:8642/api/sessions. - If using a reverse proxy, ensure it supports long-lived SSE connections (no aggressive timeouts).
- Verify the dashboard is running with
--host 0.0.0.0(an open dashboard also needs--insecure). - If the dashboard is password-protected, set the username/password under ⋮ → Dashboard / Proxy Settings (or Custom proxy and dashboard details when adding the connection). A 401 here means the credentials are wrong.
- If the dashboard sits behind a reverse-proxy path, set Dashboard path prefix. If the proxy injects dashboard auth, enable Dashboard behind proxy so the app sends clean requests.
- Check the dashboard port matches the connection (default
9119for local/Tailscale, same HTTPS port for hosted; override it in Dashboard / Proxy Settings if needed). - The dashboard must be on the same host as the Gateway API Server for the app's drawer to reach it.
- Spoken replies not working — Install Google Text-to-Speech, set it as the default engine, and download English voice data. See Setting up text-to-speech above for step-by-step instructions.
- Speech recognition not working — Ensure the Google app is installed and has microphone permission (Settings → Apps → Hermes → Permissions → Microphone).
- Voice reply toggle is off — Check the speaker icon in the chat input bar: 🔊 = on, 🔇 = off. Tap it to enable spoken replies.
- Media volume is zero — TTS uses the media audio stream, not the ringer. Turn up media volume with the physical volume buttons while on the home screen.
- Hermes speaks but audio is quiet or fast — Adjust speech rate and volume in Settings → Accessibility → Text-to-speech output.
The app accepts any of these forms and normalizes them when saving:
192.168.1.50
192.168.1.50:8642
http://192.168.1.50:8642
100.64.12.34
hermes-machine.tailnet-name.ts.net
https://your-hermes-host.example.com
https://your-hermes-host.example.com:8443
For hosted paths such as https://your-hermes-host.example.com/profile/peter, enter https://your-hermes-host.example.com as the host and /profile/peter as the Gateway path prefix.
lib/
├── main.dart # App shell, saved connections, navigation drawer
├── core/
│ ├── models/
│ │ ├── connection.dart # SavedConnection model and host normalization
│ │ └── session.dart # Session model
│ ├── screens/
│ │ ├── session_list_screen.dart # Session browser
│ │ ├── chat_screen.dart # Chat with SSE streaming
│ │ ├── settings_screen.dart # Model/theme/app settings
│ │ ├── memory_screen.dart # Memory viewer
│ │ ├── skills_screen.dart # Skills browser
│ │ └── cron_screen.dart # Cron job manager
│ ├── services/
│ │ ├── connection_manager.dart # Saved connections, Gateway API, Dashboard API
│ │ └── ws_client.dart # JSON-RPC WebSocket client for future dashboard/TUI use
│ └── utils/
│ └── responsive.dart # Phone/tablet breakpoints
└── assets/
└── icon/
└── icon.png # App icon source
- grunjol — contributed PR #68: reverse-proxy path prefix and proxied dashboard support.
- sternbergm — contributed PR #67: password-protected dashboards and configurable dashboard port.
MIT






