A native iOS app for managing AI agents powered by Hermes Agent. Create persistent agents, chat with them via Hermes LLM, manage agent servers, and monitor sessions — all from your phone.
- Agent Server Management — Add, edit, and remove Hermes agent servers with custom names and URLs
- Persistent Agents — Create AI agents with custom icons, names, and descriptions. Each agent maintains conversation context via Hermes sessions
- Real LLM Chat — Messages route through Hermes API server (OpenAI-compatible endpoint), with session continuity via
X-Hermes-Session-Id - Session Timeline — View Hermes session execution timelines with tool calls, thinking blocks, and results
- Inbox — Active tasks (running Hermes sessions) and pending approvals
- Cron Jobs — View scheduled tasks from Hermes
- Markdown Rendering — Full markdown support in chat: headings, bold, italic, inline code, code blocks with syntax highlighting, ordered/unordered lists, blockquotes, dividers
- Code Highlighting — Syntax highlighting for code blocks (Swift, Python, Rust, Go, C/C++, Bash) with copy button and horizontal scroll
- Toast Notifications — Success/error feedback for all operations
- Secure Storage — Device tokens stored in iOS Keychain
- Auto-Reconnect — Automatically re-pairs with gateway on token expiration
- iOS 16.0+
- Xcode 15+ or Swift 5.9+
- Python 3.11+
- Hermes Agent with API server platform enabled
┌──────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ Nexus iOS │────▶│ Mobile Gateway │────▶│ Hermes API │
│ (SwiftUI) │HTTP │ (FastAPI:8765) │HTTP │ Server (8642) │
└──────────────┘ └──────────────────┘ └─────────────────┘
│ │
▼ ▼
┌──────────────┐ ┌──────────────┐
│ state.db │ │ LLM (Ollama │
│ (SQLite) │ │ Cloud/API) │
└──────────────┘ └──────────────┘
- iOS App (SwiftUI): Connect view, agent server list, agent chat, session timeline, inbox
- Mobile Gateway (FastAPI, port 8765): Pairing, device auth, CRUD for agents/sessions/cron/approvals. Reads/writes Hermes
state.dbdirectly - Hermes API Server (port 8642): OpenAI-compatible
/v1/chat/completionsendpoint with session continuity. Part of Hermes Agent core
Nexus needs two backend services running: the Mobile Gateway (this repo) and the Hermes API Server (part of Hermes Agent).
# Using pipx (recommended)
pipx install hermes-agent
# Or if already installed, ensure it's up to date
pipx upgrade hermes-agentVerify installation:
hermes --versionThe API server is what Nexus calls to get LLM responses. It runs on port 8642 by default.
# Enable the API server platform
hermes config set gateway.platforms.api_server.enabled true
# Set the API server key (used for authentication)
echo 'API_SERVER_KEY=your-secret-key-here' >> ~/.hermes/.env
# Restart Hermes gateway to apply
hermes gateway restartVerify the API server is running:
# Should return 401 (auth required = server is up)
curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:8642/v1/models
# With auth — should return model list
curl http://127.0.0.1:8642/v1/models \
-H "Authorization: Bearer your-secret-key-here"The Mobile Gateway is a standalone FastAPI server included in this repo. It handles device pairing, agent CRUD, and proxies chat messages to the Hermes API server.
cd /path/to/hermes-mobile
# Create venv (Python 3.11+)
python3.11 -m venv /tmp/hermes-mobile-venv311
# Activate and install dependencies
source /tmp/hermes-mobile-venv311/bin/activate
pip install fastapi uvicorn httpx pydantic pyyamlDependencies:
| Package | Purpose |
|---|---|
fastapi |
Web framework for the gateway API |
uvicorn |
ASGI server |
httpx |
HTTP client to call Hermes API server |
pydantic |
Data validation / models |
pyyaml |
Config parsing (optional, for future use) |
cd /path/to/hermes-mobile
HERMES_MOBILE_USE_STATE_DB=1 \
/tmp/hermes-mobile-venv311/bin/python -m uvicorn \
backend_plugin.hermes_mobile.server:app \
--host 0.0.0.0 \
--port 8765Environment variables:
| Variable | Required | Default | Description |
|---|---|---|---|
HERMES_MOBILE_USE_STATE_DB |
Yes | — | Set to 1 to use Hermes state.db (real data). Without this, the gateway falls back to a mock store with no persistence |
HERMES_MOBILE_STATE_DB |
No | ~/.hermes/state.db |
Override path to the Hermes state database |
HERMES_MOBILE_USE_LIVE_APPROVALS |
No | — | Set to 1 to enable live approval forwarding |
Verify the gateway is running:
curl http://127.0.0.1:8765/mobile/v1/status | python3 -m json.toolExpected output:
{
"node_id": "your-machine",
"node_name": "your-machine",
"status": "online",
"gateway_ready": true,
"hermes_version": "0.x.x",
"api_version": "1.0",
...
}To keep the gateway running after terminal close, use a process manager or launchd:
HERMES_MOBILE_USE_STATE_DB=1 \
nohup /tmp/hermes-mobile-venv311/bin/python -m uvicorn \
backend_plugin.hermes_mobile.server:app \
--host 0.0.0.0 --port 8765 \
> /tmp/mobile-gateway.log 2>&1 &Create ~/Library/LaunchAgents/com.rayjun.nexus.plist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.rayjun.nexus</string>
<key>ProgramArguments</key>
<array>
<string>/tmp/hermes-mobile-venv311/bin/python</string>
<string>-m</string>
<string>uvicorn</string>
<string>backend_plugin.hermes_mobile.server:app</string>
<string>--host</string>
<string>0.0.0.0</string>
<string>--port</string>
<string>8765</string>
</array>
<key>WorkingDirectory</key>
<string>/path/to/hermes-mobile</string>
<key>EnvironmentVariables</key>
<dict>
<key>HERMES_MOBILE_USE_STATE_DB</key>
<string>1</string>
</dict>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<key>StandardOutPath</key>
<string>/tmp/mobile-gateway.log</string>
<key>StandardErrorPath</key>
<string>/tmp/mobile-gateway.log</string>
</dict>
</plist>launchctl load ~/Library/LaunchAgents/com.rayjun.nexus.plistThe iOS app connects to the gateway over HTTP. Choose your setup:
| Setup | Gateway URL | Use case |
|---|---|---|
| Simulator (local) | http://127.0.0.1:8765 |
Development on same Mac |
| Tailscale | http://100.x.x.x:8765 |
Remote access, no port forwarding needed |
| LAN IP | http://192.168.x.x:8765 |
Same Wi-Fi network |
Tip: Tailscale is the simplest remote option — it provides authentication through network access alone, no extra password or VPN needed.
cd apps/iosApp
open iosApp.xcodeproj
# In Xcode: select iosApp scheme, choose simulator, Run (⌘R)cd /path/to/hermes-mobile
# Build
xcodebuild -project apps/iosApp/iosApp.xcodeproj \
-scheme iosApp \
-sdk iphonesimulator \
-destination 'platform=iOS Simulator,name=iPhone 17 Pro' \
build
# Install and launch
APP_PATH=$(find ~/Library/Developer/Xcode/DerivedData/iosApp-*/Build/Products/Debug-iphonesimulator/iosApp.app -maxdepth 0 | head -1)
# Get simulator ID
SIM_ID=$(xcrun simctl list devices booted | grep "iPhone" | grep -oE '[0-9A-F-]{36}')
xcrun simctl install "$SIM_ID" "$APP_PATH"
xcrun simctl launch "$SIM_ID" com.rayjun.nexusThe mobile gateway process may be stale. Restart it:
# Find and kill old process
ps aux | grep 'hermes_mobile.server' | grep -v grep | awk '{print $2}' | xargs kill
# Restart with latest code
cd /path/to/hermes-mobile
HERMES_MOBILE_USE_STATE_DB=1 \
/tmp/hermes-mobile-venv311/bin/python -m uvicorn \
backend_plugin.hermes_mobile.server:app \
--host 0.0.0.0 --port 8765The Hermes API server requires a key. Set it and restart:
echo 'API_SERVER_KEY=your-secret-key' >> ~/.hermes/.env
hermes gateway restartThe API server on port 8642 is down. Start Hermes:
hermes gateway restart
# Verify
curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:8642/v1/modelsThe iOS Simulator shares the Mac's network, so 127.0.0.1:8765 works for local development. For a physical device, use Tailscale or your Mac's LAN IP.
cd /path/to/hermes-mobile
python -m pytest tests/ -q- iOS: SwiftUI, URLSession, Keychain (Security framework)
- Backend: Python 3.11, FastAPI, SQLite (state.db), httpx
- LLM: Hermes API server → any OpenAI-compatible model
MIT © rayjun