Hermes Android · 2026

A phone app for a self-hosted agent

In progressIndependent engineer

A self-hosted AI agent is only as useful as the client used to reach it. A browser tab on a phone is a weak compromise: limited session security, no proper terminal, and two data streams competing on one page.

The constraint

The agent stays on infrastructure you operate. The phone is a client, not a place to park keys in a web origin. Interface captures will wait until they exist.

Built with

  • Kotlin
  • Jetpack Compose
  • WebSocket

How it works

The phone holds a Compose client. Two WebSockets reach the self-hosted agent: one for chat, one for the terminal. Unlock is Keystore.

  1. Compose UI
  2. JSON-RPC socket
  3. Agent
  1. Keystore lock
  2. PTY socket
  3. Host
The phone holds a Compose client. Two WebSockets reach the self-hosted agent: one for chat, one for the terminal. Unlock is Keystore.

The calls that shaped it

Each decision with the pressure that forced it and the price it keeps costing.

  1. Kotlin and Compose

    Native Material 3, built for a phone rather than a squeezed desktop layout.

  2. Two WebSockets, one process

    JSON-RPC chat on one socket, a PTY on the other, without racing the UI. MVVM, Hilt, six Gradle modules.

  3. Keystore for the lock

    PIN or biometric unlock through Android Keystore. The session is not "remember me" in a cookie.

This is a native Android client for an agent you host yourself: a locked session, a real terminal, and two streams that stay in sync. The phone carries the keys; the host runs the agent.

Where it stands

In progress. Pairs with the autonomous agent operations case when you need both the runtime and a phone client.

What was handed over

  1. Module map and how the two sockets are owned
  2. How the client is pointed at a host
  3. What the Keystore lock does and does not protect
Next project PwnLink A phone app for a Pi in the field