A native Android control plane for your self-hosted Hermes agent.
Built for phones, tablets, foldables, and the Samsung Galaxy Trifold.
Android guide · Upstream iOS project · Hermes WebUI · Type-J issues
Hermex-Type-J is a native Kotlin + Jetpack Compose client for a self-hosted hermes-webui server. It lets you start work, watch an agent run, steer it, approve actions, inspect files, manage scheduled jobs, and recover context without sitting at the machine hosting the agent.
The server remains the compute plane. The Android device is the control, review, and continuity surface.
This is deliberately not:
- a WebView around the browser UI;
- a hosted relay or cloud account;
- a copy of the Hermes Python runtime inside Android;
- a phone-only layout stretched across a tablet.
The app talks directly to the server you configure over REST and Server-Sent Events. There is no analytics SDK, ad SDK, third-party relay, or subscription.
Upstream Hermex is an iPhone app. Same server, same wire contract — but Type-J is a substantially bigger client:
| Upstream Hermex (iOS) | Hermex-Type-J (Android) | |
|---|---|---|
| Platform | SwiftUI, iPhone | Kotlin + Compose, phones / tablets / foldables / trifold |
| Layout | Single-column portrait/landscape | Hinge-aware 1/2/3-pane with state continuity across every posture change |
| Kanban boards | — | Boards, cards, comments, dependencies, bulk actions, dispatcher, worker logs, live events |
| Git workspaces | — | Status, branches, diffs, stage/commit, guarded remotes, generated commit messages |
| Share target | iOS share extension | Durable ACTION_SEND inbox — survives process death; text + up to 10 files |
| Deep links | hermes-agent:// |
hermex-type-j:// + legacy, launcher shortcuts, notification intents, onboarding-safe |
| Background runs | Background URLSession | Foreground service with private progress/completion notifications + cancel action |
| Proxy headers | Static list | Keystore-encrypted, per-origin, validated editor, redirect-safe |
| Voice | Dictation + TTS | Dictation + native voice notes with server transcription + assistant Listen (server TTS, device fallback) |
| Quality gates | XCTest suite | 608 tests across 63 suites incl. Robolectric + deterministic fuzz · Android Lint 0 · Kotlin LSP clean · 2,500-event monkey 0 crashes |
| Distribution | App Store / TestFlight | Source build, signed local APK, CI artifact on every push |
Everything the iOS app does — streaming chat with reasoning and tools, stop and
steer, approvals, sessions and projects, models and profiles, tasks, skills,
files, memory, insights, settings, offline cache — is here too, tested against
the same pinned server contract (UPSTREAM_TESTED_SHA).
The upstream project's API contract, product thinking, and iOS implementation are the foundation of this repository. But Android needed more than a mechanical port: foldables and large screens change how an agent client should work — the session list stays visible, the transcript keeps its place, the composer doesn't cover the work, and a third panel carries real context instead of empty padding. And Android's platform services (share sheet, deep links, foreground services, Keystore) allow capabilities no iOS build can offer.
This fork keeps the original iOS project intact in HermesMobile/ and adds a
separate native android/ application:
- Native Android interaction. Compose UI, Android file and camera pickers, Android Keystore, DataStore, predictive back, proper lifecycle handling.
- First-class adaptive layouts. Compact cover displays, phones, tablets, dual-fold and triple-fold devices each get a layout shaped for their space.
- Operational parity — and then beyond. Every iOS surface works, plus Kanban, Git, sharing, notifications, and voice features listed above.
- Upstream-compatible wire behavior. Tolerant decoding of the same models; no invented server APIs.
The layout is selected from the actual window and hinge state, not from a hard-coded portrait/landscape switch.
| Form factor | Navigation | Working layout |
|---|---|---|
| Cover / compact phone | Bottom navigation | One focused surface; system back returns from chat to sessions |
| Standard phone | Bottom navigation | Full-screen list or detail with native transitions |
| Tablet / opened fold | Navigation rail | Persistent list + detail |
| Galaxy Trifold | Navigation rail | Hinge-aligned list + detail + context/composer |
| Half-open / flex posture | Rail or compact navigation | Controls avoid hinge occlusion; session/draft state remains live |
| Multi-window | Width-driven | Reflows without restarting the active task |
Selection, draft text, staged attachments, scroll position, active session, and
stream recovery survive cover-to-inner-display transitions. App-level
navigation uses a SavedStateHandle; feature state lives in ViewModels rather
than in a disposable layout branch.
On a trifold, the app does not merely widen two columns:
- Chat: sessions | transcript | composer and run controls
- Tasks: task list | task detail and actions | recent output
- Skills: skill list | rendered skill | linked file
- Files: workspaces | directory contents | file preview
Pane boundaries are derived from androidx.window folding features and aligned
with physical hinge centers. On devices without reported hinges, the same
system falls back to measured window width.
- Kotlin 2.4 and Jetpack Compose with Material 3 Adaptive behavior
- Android 8 / API 26 minimum; target and compile SDK 37
- edge-to-edge system UI, predictive back, resizable activity, and multi-window
- Android Keystore encryption for the saved server password
- persistent cookie jar for hermes-webui authentication
- DataStore-backed settings, model favorites, and recents
- file-backed offline session and transcript cache
- tolerant
kotlinx.serializationmodels matching the iOS wire behavior - OkHttp REST client plus a native SSE stream client
- no WebView and no embedded browser runtime
- token-by-token streaming with replay-aware reconnect
- reasoning blocks, tool calls, tool results, status, title, and metering events
- markdown, code blocks, copy actions, and monospace math fallback
- stop and steer while a run is active
- approval and clarification sheets with expiry handling
- optimistic sending with rollback when a request fails
- active-run status and context-window indicator
- transcript pagination and offline cache fallback
- response speed, timestamps, RTL chat layout, code wrapping, and card display settings
- model picker grouped by provider
- model favorites and recent selections
- reasoning effort and reasoning visibility
- profile switching and workspace selection
- slash-command autocomplete from local, server, and skill commands
- persistent goal controls
- Android document picker with multiple file types
- camera capture through the native activity-result API
- attachment previews, removal, upload state, and a 20 MB client-side limit
- Android speech recognition for voice dictation
- layout that separates from the transcript on a trifold
- local title/model/workspace search plus debounced server content search
- pinned, recent, scheduled, archived, CLI-imported, and delegated-session visibility
- rename, pin, archive, restore, duplicate/branch, move, delete, and export
- project create, rename, delete, color, filtering, and session counts
- swipe actions on compact screens and contextual actions on larger screens
- cached read-only recovery when the server is unreachable
- scheduled task list, detail, status, timing, delivery, model/profile metadata, and output
- create, edit, run now, pause, resume, and delete cron jobs
- delivery options, toast behavior, validation, and server-rejection handling
- skill grouping, search, tags, enable/disable, markdown content, and linked files
- optimistic skill toggles with rollback on failure
- boards with columns, counts, active-board switching, create/edit/archive
- cards with status, priority, assignee, tenant, skills, workspace, and staleness badges
- card detail with comments, activity events, dependency links, and run history
- create/edit/move/block/unblock, bulk actions, and dispatcher dry-run/execute
- worker-log tailing and lifecycle-bound live event reconciliation (monotonic cursor)
- three-pane boards | columns | detail on a trifold
- session-scoped workspace status, branch, ahead/behind, and conflict badges
- per-file staged/unstaged unified diffs with binary and size-cap handling
- stage, unstage, and explicitly confirmed discard
- fetch, pull, push, checkout, and stash-checkout with dirty-guard semantics
- generated commit messages and staged or selected-path commits
- no force-push and no unconfirmed destructive action anywhere
- ACTION_SEND / SEND_MULTIPLE / PROCESS_TEXT share target with a durable app-private inbox (survives process death; acknowledged only after staging)
- deep links (
hermex-type-j://and legacyhermes-agent://) to new chat, sessions, Kanban boards/cards, and Git workspaces, persisted through onboarding - static launcher shortcuts for New Chat, Kanban, and Git Workspaces
- opt-in foreground monitoring of active runs with private ongoing and completion notifications, cancel action, and status/replay recovery
- encrypted per-origin custom request headers for authenticated reverse proxies (masked editor, duplicate/injection/protected-header validation, cross-origin redirect stripping, never logged, Keystore-encrypted at rest)
- Android Keystore, DataStore, predictive back, edge-to-edge, and multi-window
- native AAC voice notes with mic permission, timer, and duration/size guards
- server transcription with audio preserved when STT is unavailable
- assistant Listen action: server neural TTS for ≤5,000 characters with silent Android TextToSpeech fallback and markdown-safe text normalization
- workspace roots, breadcrumbs, directory navigation, search, and back stack
- text/markdown preview, line numbers, wrapping, copy, image loading, and binary detection
- cookie-authenticated raw file previews through the shared OkHttp client
- memory, user profile, agent soul, and project-context sections
- usage timeframes, token totals, estimated cost, daily usage chart, model share, and top sessions
- connection test, health probe, auth-status detection, password and passwordless servers
- Tailscale-focused setup guidance
- system/light/dark theme and selectable accent colors
- chat, haptics, section visibility, default model/profile, providers, server info, and logout
- one shared authentication state machine across shell, onboarding, and settings
All screenshots below are real Android 16 emulator captures running the Compose application against a disposable local hermes-webui-compatible fixture.
| Compact cover — active chat | Standard phone — sessions |
|---|---|
![]() |
![]() |
| Opened fold — list + chat | Standard tablet — list + detail |
|---|---|
![]() |
![]() |
| Surface | Android implementation |
|---|---|
| Connect | URL normalization, health/auth probes, password and passwordless login |
| Chat | REST start + native SSE stream, reconnect, stop, steer, reasoning, tools |
| Attachments | Android file picker, camera, previews, upload, transcript rendering |
| Voice | Android SpeechRecognizer dictation with graceful capability fallback |
| Sessions | Browse, content search, cache, pin/archive/branch/move/delete/export |
| Projects | Create, rename, delete, filter, colors, session counts |
| Models | Provider groups, search, custom models, favorites, recents |
| Profiles | Active/default profile, switching, model/workspace inheritance |
| Tasks | Full cron lifecycle plus detail, delivery options, output |
| Kanban | Boards, columns, card detail, bulk actions, dispatcher, live events |
| Git | Status, diffs, stage/commit, guarded remotes, stash-checkout |
| Share target | Durable text/file inbox routed into a new-chat composer |
| Voice | Voice notes, server transcription, Listen with device TTS fallback |
| Background | Foreground run monitor with private progress/completion notifications |
| Deep links | Type-J + legacy schemes to chat, sessions, Kanban, Git; launcher shortcuts |
| Custom headers | Encrypted per-origin proxy headers with redirect stripping |
| Skills | Browse, search, render, linked files, enable/disable |
| Files | Workspace roots, directories, text/markdown/image previews |
| Memory | Memory, user, soul, and project context |
| Insights | Tokens, cost, timeframes, models, daily chart, top sessions |
| Settings | Appearance, chat behavior, providers, defaults, visibility, logout |
| Offline | Cached session list and transcripts with connectivity-aware fallback |
| Foldables | Width + hinge-aware one/two/three-pane layouts and state continuity |
flowchart LR
A[Hermex-Type-J<br/>Compose UI] -->|HTTPS REST| B[hermes-webui]
B -->|Server-Sent Events| A
B --> C[Hermes agent + tools]
A --> D[Android Keystore<br/>encrypted password]
A --> E[DataStore<br/>settings + selections]
A --> F[JSON cache<br/>sessions + transcript]
G[WindowManager<br/>fold + hinge state] --> A
The Android project is intentionally a single application module. Features are organized by product surface; shared wire models and networking stay separate from Compose UI.
android/app/src/main/java/io/github/jcartu/hermex/
├── core/ # crypto, prefs, cookies, logging
├── data/ # offline cache
├── model/ # tolerant server models
├── net/ # endpoints, REST, SSE, errors
├── ui/adaptive/ # fold state and hinge-aligned panes
└── ui/feature/ # chat, sessions, tasks, skills, files, memory, insights…
- The app connects only to the server URL you enter.
- The server password is encrypted by a key held in Android Keystore.
- Session cookies persist locally; logout clears the local session.
- Native requests deliberately omit browser
OriginandRefererheaders, matching hermes-webui's supported non-browser CSRF path. - Unknown JSON fields are ignored; malformed optional fields degrade instead of crashing the UI.
- Redirected custom headers are stripped when the redirect crosses origin.
- Signing keys, passwords, local SDK paths, APKs, and build output are ignored by Git.
You remain responsible for securing and updating your self-hosted server. HTTPS through Tailscale Serve, Cloudflare Tunnel, or a reverse proxy is the recommended transport.
Install and start hermes-webui on a
machine you control. Configure a strong HERMES_WEBUI_PASSWORD whenever the
server is reachable beyond loopback.
Use real HTTPS through Tailscale Serve, Cloudflare Tunnel, or your reverse proxy. Plain HTTP remains useful for a trusted LAN or emulator development.
Requirements: JDK 21 and Android SDK platform 37.
git clone https://github.com/jcartu/Hermex-Type-J.git
cd Hermex-Type-J/android
./gradlew testDebugUnitTest
./gradlew assembleDebug
adb install -r app/build/outputs/apk/debug/app-debug.apkFor a signed local release:
./gradlew assembleReleaseSigning credentials live in a gitignored android/keystore.properties; see
android/README.md for the exact format and toolchain.
The Android delivery is checked at three levels:
| Gate | Evidence |
|---|---|
| JVM behavior | 608 unit, contract, fuzz, and framework tests across 63 suites |
| Static analysis | Android Lint: 0 issues; JetBrains Kotlin LSP: 0 diagnostics |
| Release | assembleRelease succeeds; local APK verified with Signature Scheme v2 |
| Surface | Android 16 Pixel Fold emulator: CLOSED, HALF_OPENED, OPENED, standard phone/tablet widths, simulated 3600×2208 trifold, and 1.3× font scale |
| Abuse | 2,500-event UI monkey sweep with zero crashes/ANRs; deterministic fuzz invariants for hinge geometry, path encoding, deep links, tolerant decoding, and stream reducers |
| Native flows | Auth restore, session continuity, share target, deep links, notifications, document picker, Kanban, Git, task detail/output, file preview, memory/insights/settings |
| Cloud | Android CI runs tests and uploads an unsigned release APK |
Run the same local gate:
cd android
./gradlew testDebugUnitTest assembleReleaseThe Android app does not currently port an Android share-extension process model beyond the share target described above, push notifications via a remote relay, TTS engine voice pickers, or iOS-specific Live Activities and App Intents. They are intentionally omitted, not represented by non-functional placeholders.
This repository is a proper fork of
uzairansaruzi/hermex, created by
Uzair Ansar. The upstream SwiftUI app,
product specification, test approach, artwork, and API-contract research made
this Android work possible.
- Upstream website: hermexapp.com
- Upstream iOS app: App Store
- Upstream contributing guide:
CONTRIBUTING.md - Android implementation guide:
android/README.md - Tested server pin:
UPSTREAM_TESTED_SHA
Android-specific issues and pull requests belong in this fork. Changes to the iOS product should be proposed upstream.
MIT — see LICENSE.
Hermex is an independent client and is not affiliated with the upstream hermes-webui project. Apple, the Apple logo, and App Store are trademarks of Apple Inc. Android, Jetpack, and Google Play are trademarks of Google LLC.












