commit 2cd473032456beb78c10c6e7cf7ff1729b5bddc3 Author: Hermes Agent Date: Thu Jul 9 03:45:48 2026 +0000 docs: initial Hermes Mobile planning scaffold diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..1014ba7 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +indent_style = space +indent_size = 2 +trim_trailing_whitespace = true + +[*.md] +trim_trailing_whitespace = false diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5135740 --- /dev/null +++ b/.gitignore @@ -0,0 +1,37 @@ +# dependencies +node_modules/ +.pnpm-store/ + +# builds +dist/ +build/ +.out/ +.next/ +coverage/ + +# env/secrets +.env +.env.* +!.env.example +*.pem +*.key + +# runtime data +data/ +uploads/ +*.db +*.db-shm +*.db-wal +logs/ + +# OS/editor +.DS_Store +.vscode/ +.idea/ +*.swp + +# python bridge +__pycache__/ +*.pyc +.venv/ +venv/ diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..a2ede7b --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Bonzi + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/PROJECT_STRUCTURE.md b/PROJECT_STRUCTURE.md new file mode 100644 index 0000000..21f541b --- /dev/null +++ b/PROJECT_STRUCTURE.md @@ -0,0 +1,166 @@ +# Proposed Project Structure + +```text +hermes-mobile/ + README.md + PROJECT_STRUCTURE.md + LICENSE + .gitignore + .editorconfig + package.json # pnpm workspace root, later + pnpm-workspace.yaml + tsconfig.base.json + install.sh # one-liner installer entrypoint, later + docs/ + PRODUCT_PLAN.md + ARCHITECTURE.md + DESIGN_SYSTEM.md + COMPANION_SERVER.md + MOBILE_APP.md + INSTALL.md + TESTING.md + ROADMAP.md + apps/ + mobile/ # Android-first PWA + package.json + vite.config.ts + index.html + public/ + manifest.webmanifest + icons/ + src/ + app/ + App.tsx + router.tsx + providers.tsx + screens/ + AskScreen/ + ActivityScreen/ + CronScreen/ + FilesScreen/ + SettingsScreen/ + components/ + agent-status-orb/ + composer/ + tool-card/ + event-timeline/ + upload-tray/ + voice-recorder/ + cron-job-card/ + approval-card/ + bottom-nav/ + app-shell/ + features/ + tasks/ + sessions/ + cron/ + files/ + approvals/ + notifications/ + pairing/ + settings/ + lib/ + api-client.ts + realtime.ts + push.ts + audio.ts + file-utils.ts + format.ts + styles/ + globals.css + tokens.css + main.tsx + companion/ # local server installed beside Hermes Agent + package.json + src/ + app.ts + config/ + index.ts + schema.ts + auth/ + pairing.ts + sessions.ts + middleware.ts + db/ + client.ts + migrations/ + repositories/ + events/ + bus.ts + types.ts + websocket.ts + sse.ts + hermes/ + HermesAdapter.ts + CliHermesAdapter.ts + ApiHermesAdapter.ts + PythonHermesAdapter.ts + promptFormatting.ts + tasks/ + TaskManager.ts + TaskQueue.ts + taskTypes.ts + uploads/ + uploadRoutes.ts + UploadStore.ts + fileValidation.ts + notifications/ + NotificationProvider.ts + WebPushProvider.ts + NtfyProvider.ts + GotifyProvider.ts + NoopProvider.ts + cron/ + CronService.ts + HermesCronAdapter.ts + approvals/ + ApprovalService.ts + routes/ + health.ts + tasks.ts + uploads.ts + sessions.ts + cron.ts + approvals.ts + settings.ts + system/ + hermesHealth.ts + logs.ts + index.ts + scripts/ + hermes_worker.py # direct Python bridge later + packages/ + shared/ # shared TS types/schemas + package.json + src/ + events.ts + api.ts + tasks.ts + cron.ts + files.ts + notifications.ts + ui/ # optional shared UI primitives later + package.json + src/ + scripts/ + install.sh + uninstall.sh + dev-hermes-smoke.sh + build-release.sh + deploy/ + systemd/ + hermes-mobile-companion.service + nginx/ + hermes-mobile.conf + caddy/ + Caddyfile.example +``` + +## Modularity Notes + +- `apps/mobile` should never import Hermes-specific server internals directly. It uses `packages/shared` schemas and API client only. +- `apps/companion/src/hermes` is the only layer that knows how to talk to Hermes Agent. +- `apps/companion/src/notifications` is provider-swappable. +- `apps/companion/src/cron` wraps Hermes cron rather than replacing it. +- `packages/shared` defines stable event types used by both app and server. +- `scripts/` and `deploy/` stay boring and auditable. diff --git a/README.md b/README.md new file mode 100644 index 0000000..457423f --- /dev/null +++ b/README.md @@ -0,0 +1,153 @@ +# Hermes Mobile + +Native-feeling Android-first PWA and companion server for [Hermes Agent](https://github.com/NousResearch/hermes-agent). + +Hermes Mobile is not a generic LLM chat UI. It is a self-hosted, Hermes-native control surface designed for phone use: prompt by text or voice, upload files, watch tool calls live, approve actions, manage cron jobs, and get notified when long-running agent work is done. + +Repo: https://git.molberg.cloud/bonzi/hermes-mobile + +## Status + +Planning scaffold only. No production code yet. + +## Product Goals + +- Feel like a real Android app, not a web page pretending to be chat. +- Run privately on the same Linux machine as Hermes Agent. +- Keep Hermes Agent untouched where possible; operate as a companion layer above/alongside it. +- Expose Hermes-specific concepts: tool calls, sessions, jobs, generated files, approvals, background tasks. +- Make installation one-liner simple for a homelab machine. +- Stay modular enough that the app, companion server, Hermes integration, notification providers, and install scripts can evolve independently. + +## Planned Components + +```text +Android / mobile browser + | + | HTTPS + WebSocket/SSE + Web Push + v +Hermes Mobile App (PWA / later Capacitor) + | + v +Hermes Companion Server + | + +-- Hermes CLI / Python AIAgent bridge + +-- Hermes API server bridge + +-- Hermes session DB reader + +-- Hermes cron manager + +-- Upload/file store + +-- Push notification provider +``` + +## MVP Feature Set + +1. Mobile-first app shell + - Installable PWA + - Android-style bottom navigation + - Offline-friendly shell + - Dark, playful visual system inspired by happy.engineering / Happy app + +2. Chat / prompt screen + - Text prompts + - Voice note recording + - File uploads: zip, png, jpg, pdf, txt, logs, folders later + - Streaming responses + - “Agent is working” state + - Completion notification + +3. Hermes-native activity timeline + - Tool call started / finished + - Terminal commands + - File reads/writes + - Browser actions + - Home Assistant actions + - Cron changes + - Subagent delegation + - Expand/collapse raw output + +4. Sessions + - Recent sessions + - Resume session + - Rename / pin / archive + - Per-session attachments and generated files + +5. Cron + - List cron jobs + - Run now + - Pause/resume/remove + - View last output + - Delivery target: app notification / in-app inbox + +6. Approvals + - Push approval to phone for dangerous commands + - Approve / deny with short audit log + +7. Companion settings + - Connect to a companion server URL + - Pair using one-time code or passkey + - Configure notification backend + - View Hermes health/status + +## Docs + +- [Product Plan](docs/PRODUCT_PLAN.md) +- [Architecture](docs/ARCHITECTURE.md) +- [Design System](docs/DESIGN_SYSTEM.md) +- [Companion Server](docs/COMPANION_SERVER.md) +- [Mobile App Structure](docs/MOBILE_APP.md) +- [Install Strategy](docs/INSTALL.md) +- [Testing Strategy](docs/TESTING.md) +- [Roadmap](docs/ROADMAP.md) + +## Proposed Stack + +Frontend: +- TypeScript +- React + Vite or Next.js static/PWA mode +- Tailwind CSS +- Zustand or TanStack Query for client state +- Service Worker + Web Push +- Capacitor later, only if PWA limitations matter + +Companion server: +- TypeScript Node.js initially, because file uploads, WebSocket/SSE, install scripts, and PM2/systemd are straightforward +- Fastify or Hono +- SQLite for app metadata +- Local filesystem upload store +- Python bridge subprocess or direct Hermes module calls where safe + +Why not Open WebUI/LibreChat: +- They are model chat UIs. +- Hermes needs agent-native events, cron, approvals, file artifacts, process logs, sessions, and tool timelines. +- Forking a generic app would probably become more work than a clean, small purpose-built app. + +## One-liner install target + +Final goal: + +```bash +curl -fsSL https://git.molberg.cloud/bonzi/hermes-mobile/raw/branch/main/install.sh | bash +``` + +or, for local/self-hosted raw auth limitations, a release artifact URL: + +```bash +curl -fsSL https://hermes-mobile.molberg.cloud/install.sh | bash +``` + +The installer should: +- Detect Hermes Agent install and config path +- Create a system user or use current user depending mode +- Install Node runtime if missing +- Download release bundle +- Create config at `/etc/hermes-mobile/config.yaml` or `~/.config/hermes-mobile/config.yaml` +- Configure systemd service `hermes-mobile-companion` +- Print pairing URL / one-time setup code + +## Development Philosophy + +- Companion server owns mobile UX state, not Hermes core. +- Hermes remains the agent runtime/source of truth for actual work. +- Every Hermes integration goes through an adapter interface so we can switch between CLI, API server, direct Python, or future Hermes-native event APIs. +- Tool-call UI should prefer structured events, but gracefully degrade to parsed CLI/API logs during early versions. +- Keep secrets out of repo. Use environment/config files and future vault integration. diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md new file mode 100644 index 0000000..87626a5 --- /dev/null +++ b/docs/ARCHITECTURE.md @@ -0,0 +1,311 @@ +# Architecture + +## Overview + +Hermes Mobile is split into two deployable parts: + +1. Mobile app + - Installable PWA designed for Android. + - Talks only to the companion server. + - Does not need direct access to Hermes files or credentials. + +2. Companion server + - Runs on the same Linux machine as Hermes Agent. + - Bridges mobile UI actions to Hermes Agent. + - Owns upload storage, push notifications, pairing/auth, app metadata, and realtime event fanout. + +```text ++---------------------------+ +| Android PWA | +| - Chat | +| - Tool timeline | +| - Cron UI | +| - Files | +| - Approvals | ++-------------+-------------+ + | + | HTTPS REST + WebSocket/SSE + Web Push + v ++---------------------------+ +| Hermes Companion Server | +| - Auth/pairing | +| - Task orchestrator | +| - Hermes adapters | +| - Event bus | +| - Upload store | +| - Cron wrapper | +| - Notification providers | ++------+------+-------------+ + | | + | +--------------------+ + | | + v v ++-------------+ +--------------+ +| Hermes CLI | | Hermes files | +| Hermes API | | sessions/db | +| AIAgent | | cron jobs | ++-------------+ +--------------+ +``` + +## Key Architectural Rule + +The companion server should depend on stable Hermes surfaces first, but isolate every integration behind interfaces. + +```ts +interface HermesAdapter { + health(): Promise + startTask(input: StartTaskInput): AsyncIterable + continueSession(sessionId: string, input: StartTaskInput): AsyncIterable + stopTask(taskId: string): Promise +} +``` + +Possible implementations: +- `CliHermesAdapter`: spawns `hermes chat -q` or interactive process. Easiest baseline, weakest event detail. +- `ApiHermesAdapter`: calls Hermes API server. Good for compatibility, but generic OpenAI API hides some tool events. +- `PythonHermesAdapter`: imports Hermes Agent modules and uses callbacks for stream/tool progress. Best long-term event fidelity. +- `GatewayHermesAdapter`: uses existing gateway/session machinery if exposed. + +## Companion Server Modules + +```text +companion/ + src/ + app.ts # server bootstrap + config/ # env/yaml config loading + auth/ # pairing, sessions, tokens, passkeys later + db/ # SQLite schema/migrations/repositories + events/ # event bus + SSE/WebSocket fanout + hermes/ # adapter interface + implementations + tasks/ # task lifecycle/orchestration + uploads/ # multipart upload handling + retention + notifications/ # webpush/ntfy/gotify providers + cron/ # Hermes cron wrapper + approvals/ # approval queue + Hermes callbacks later + routes/ # REST API routes + ws/ # realtime endpoints + system/ # service health, logs, install info +``` + +## Event Bus + +Everything that happens in the companion becomes an event. + +Core event shape: + +```ts +type CompanionEvent = { + id: string + type: string + taskId?: string + sessionId?: string + ts: string + level?: 'debug' | 'info' | 'warn' | 'error' + payload: unknown +} +``` + +Important event types: + +```text +task.created +task.started +task.status +task.finished +task.failed +task.cancelled + +assistant.delta +assistant.message +assistant.final + +tool_call.started +tool_call.output +tool_call.finished +tool_call.failed + +file.uploaded +file.generated + +approval.required +approval.resolved + +cron.job.listed +cron.job.updated +cron.job.finished + +notification.sent +notification.failed +``` + +The mobile app subscribes by: +- WebSocket for active app foreground. +- SSE fallback. +- Push notifications when app is background/closed. + +## Data Storage + +### SQLite + +Companion-owned metadata: +- paired devices +- auth sessions +- tasks +- task events +- uploaded files metadata +- notification subscriptions +- user settings/cache + +Do not duplicate full Hermes session content unless needed for mobile indexing. Hermes session DB remains source of truth. + +### Filesystem + +Default paths: + +```text +/var/lib/hermes-mobile/ + hermes-mobile.db + uploads/ + / + generated/ + cache/ + logs/ +``` + +User-mode install paths: + +```text +~/.local/share/hermes-mobile/ +~/.config/hermes-mobile/config.yaml +``` + +## API Surface + +### Auth / Pairing + +```http +POST /api/pair/start +POST /api/pair/confirm +POST /api/auth/login +POST /api/auth/logout +GET /api/me +``` + +Pairing flow: +1. Installer prints `https://host/pair?code=123-456`. +2. User opens on phone. +3. Server binds device and issues token. +4. Future sessions use secure cookie or bearer token. + +### Tasks + +```http +POST /api/tasks +GET /api/tasks +GET /api/tasks/:id +POST /api/tasks/:id/stop +GET /api/tasks/:id/events +WS /api/tasks/:id/stream +``` + +### Uploads + +```http +POST /api/uploads +GET /api/files +GET /api/files/:id/download +DELETE /api/files/:id +``` + +### Sessions + +```http +GET /api/sessions +GET /api/sessions/:id +POST /api/sessions/:id/continue +PATCH /api/sessions/:id +``` + +### Cron + +```http +GET /api/cron/jobs +POST /api/cron/jobs/:id/run +POST /api/cron/jobs/:id/pause +POST /api/cron/jobs/:id/resume +DELETE /api/cron/jobs/:id +``` + +### System + +```http +GET /api/health +GET /api/hermes/health +POST /api/hermes/test +GET /api/logs +``` + +## Hermes Integration Notes + +Existing useful surfaces observed: +- Hermes API server exposes `/v1/chat/completions`, `/v1/responses`, `/v1/models`, `/health`. +- `AIAgent` supports `stream_delta_callback` and `tool_progress_callback` constructor params. +- Cron jobs are manageable through Hermes CLI/tooling and stored under Hermes home. +- Gateway platforms already handle STT/media patterns, but mobile should not depend on Telegram. + +Long-term ideal: +- Add/consume a Hermes-native event stream from AIAgent that emits structured tool events. +- Companion server can either import Hermes modules or call a local IPC endpoint. + +## Security Model + +Default deployments: +1. LAN/Tailscale only, simple pairing token. +2. Public HTTPS, pairing token + device token + optional passkey. + +Security requirements: +- No unauthenticated access to prompt endpoints. +- Upload size limits. +- File paths normalized; no arbitrary file read from upload endpoints. +- CSRF protection if cookie auth used. +- Audit log for approvals. +- Secrets remain in Hermes config/vault, not in mobile app. + +## Notification Architecture + +Provider interface: + +```ts +interface NotificationProvider { + send(device: Device, message: NotificationMessage): Promise + test(device: Device): Promise +} +``` + +Providers: +- `WebPushProvider` +- `NtfyProvider` +- `GotifyProvider` +- `NoopProvider` + +## Deployment Modes + +### User mode + +- Runs as current user. +- Uses `~/.config/hermes-mobile` and `~/.local/share/hermes-mobile`. +- Good for dev/single-user boxes. + +### System mode + +- Creates `hermes-mobile` system user or runs under Hermes user. +- Uses `/etc/hermes-mobile` and `/var/lib/hermes-mobile`. +- systemd service. +- Better production posture. + +## Future Native Wrapper + +If Android PWA is insufficient: +- Add Capacitor app under `apps/android-shell`. +- Reuse same web app. +- Gain native share target, richer push, microphone/file APIs. diff --git a/docs/COMPANION_SERVER.md b/docs/COMPANION_SERVER.md new file mode 100644 index 0000000..114de9b --- /dev/null +++ b/docs/COMPANION_SERVER.md @@ -0,0 +1,254 @@ +# Companion Server Plan + +## Purpose + +The companion server is the local service installed beside Hermes Agent. It turns Hermes into a phone-friendly app backend without forcing Hermes core to become a mobile backend. + +Responsibilities: +- Authenticate/pair phones +- Accept prompts, voice recordings, and files +- Start/continue Hermes tasks +- Stream Hermes activity to the app +- Store app metadata +- Send push notifications +- Expose cron/job/session/file APIs +- Provide health checks and install/update status + +## Runtime + +Preferred MVP runtime: Node.js + TypeScript. + +Reasons: +- Great fit for HTTP/WebSocket/SSE/file uploads. +- Easy bundling for one-liner installs. +- PM2/systemd deployment is straightforward in Zeb's environment. +- Frontend and backend can share TypeScript event schemas. + +Potential framework: +- Fastify: mature, fast, good plugins. +- Hono: simple, edge-like API, also good. + +Initial pick: Fastify unless we want ultra-minimal. + +## Config + +Config locations: + +System mode: +```text +/etc/hermes-mobile/config.yaml +/var/lib/hermes-mobile/ +``` + +User mode: +```text +~/.config/hermes-mobile/config.yaml +~/.local/share/hermes-mobile/ +``` + +Example: + +```yaml +server: + host: 0.0.0.0 + port: 8787 + public_url: https://hermes-mobile.molberg.cloud + +auth: + pairing_enabled: true + token_ttl_days: 90 + passkeys_enabled: false + +hermes: + home: /root/.hermes + mode: python # python | api | cli + cli_bin: /root/.local/bin/hermes + api_base_url: http://127.0.0.1:18793/v1 + api_key: "" + +storage: + data_dir: /var/lib/hermes-mobile + max_upload_mb: 512 + retention_days: 30 + +notifications: + provider: webpush # webpush | ntfy | gotify | none + ntfy_url: https://ntfy.example.com/hermes +``` + +## Hermes Adapter Strategy + +### Phase 1: CLI/API hybrid + +- Use Hermes CLI for health tests and simple prompts. +- Use Hermes API server if available for OpenAI-compatible chat. +- Parse coarse progress where possible. + +Pros: +- Requires few/no Hermes changes. +- Easy to prove app UX. + +Cons: +- Tool-call visibility limited. + +### Phase 2: Direct Python adapter + +Run a Python worker process that imports Hermes `AIAgent` and communicates with Node over stdio or local socket. + +Benefits: +- Can pass `stream_delta_callback` and `tool_progress_callback`. +- More structured event stream. +- Better session control. + +Potential shape: + +```text +Node companion <-- JSON lines --> Python hermes_worker.py <-- imports --> AIAgent +``` + +Worker commands: +- `health` +- `start_task` +- `continue_session` +- `cancel_task` +- `list_sessions` +- `cron_action` + +Worker emits events: +- `assistant.delta` +- `tool_call.started` +- `tool_call.output` +- `tool_call.finished` +- `assistant.final` + +### Phase 3: Hermes-native plugin/API + +If Hermes Agent grows a stable event API, switch adapter implementation without rewriting app/server. + +## Task Lifecycle + +```text +created -> queued -> running -> finished + -> failed + -> cancelled + -> waiting_approval +``` + +Task record: + +```ts +type Task = { + id: string + sessionId?: string + title?: string + status: TaskStatus + inputText: string + attachmentIds: string[] + createdAt: string + startedAt?: string + finishedAt?: string + error?: string +} +``` + +## Upload Handling + +Use multipart upload endpoint. + +Pipeline: +1. Validate file count/size/type. +2. Store under `uploads//original-name`. +3. Record metadata in SQLite. +4. Include absolute file paths in Hermes prompt. + +Prompt augmentation example: + +```text +The user uploaded these files: +- screenshot.png: /var/lib/hermes-mobile/uploads/abc/screenshot.png (image/png, 320 KB) +- source.zip: /var/lib/hermes-mobile/uploads/abc/source.zip (application/zip, 12 MB) + +User prompt: + +``` + +## Voice Handling + +MVP options: + +1. Client records `.webm`/`.ogg`, server stores it, then sends file path to Hermes with instruction to transcribe/analyze. +2. Server transcribes with local faster-whisper and sends text prompt. + +Recommended MVP: +- Server-side transcription using local faster-whisper if available. +- Fallback: pass audio file to Hermes as attachment. + +## Notifications + +Events that trigger notifications: +- task completed after app backgrounded +- task failed +- approval required +- cron job finished/failed + +Use provider abstraction: + +```ts +interface NotificationProvider { + sendCompletion(task: Task): Promise + sendFailure(task: Task): Promise + sendApproval(approval: Approval): Promise + sendCron(job: CronEvent): Promise +} +``` + +## Pairing/Auth + +MVP pairing: +1. Installer/server logs one-time code. +2. Phone opens `/pair` and enters code or uses link. +3. Server stores device and creates token. +4. Token stored in secure-ish PWA storage. Later use passkeys. + +For public exposure, add: +- Rate limiting +- Token rotation +- Session revoke UI +- Optional Tailscale-only mode + +## Cron Integration + +Initial implementation can shell out to Hermes CLI: + +```bash +hermes cron list --json +hermes cron run +hermes cron pause +hermes cron resume +``` + +If CLI JSON is not available, import cron modules from Hermes Python or parse job files carefully. + +## System Health + +Health endpoint should check: +- companion server up +- DB writable +- upload dir writable +- Hermes CLI exists +- Hermes config exists +- Hermes API server reachable if configured +- Python worker reachable if configured +- notification provider configured + +## Logging + +- Structured JSON logs for service. +- Human-readable recent logs in UI. +- Do not log secrets, bearer tokens, or full uploaded file content. + +## Open Questions + +- Should companion run as same user as Hermes Agent for direct module/file access? +- Should public access be Cloudflare Access/Tailscale-first instead of app auth-first? +- How much Hermes core should be extended for better event streaming? diff --git a/docs/DESIGN_SYSTEM.md b/docs/DESIGN_SYSTEM.md new file mode 100644 index 0000000..5943b17 --- /dev/null +++ b/docs/DESIGN_SYSTEM.md @@ -0,0 +1,222 @@ +# Design System + +## Visual Direction + +Target: visually inspired by `happy.engineering` and the Happy app: polished, playful, soft, modern, high-motion, emotionally warm, and app-like. + +Not a terminal dashboard. Not a generic ChatGPT clone. It should feel like a friendly command center for a personal agent. + +## Keywords + +- Native Android feel +- Playful but competent +- Soft cards +- Friendly gradients +- Rounded app surfaces +- Large touch targets +- Motion-rich microinteractions +- Calm dark mode +- “Agent is alive” status cues + +## Initial Theme Direction + +Because Zeb likes both stark terminal aesthetics and polished UIs, Hermes Mobile should combine: + +- Happy-style colorful/soft app surfaces +- Hermes identity through icons, agent activity, and subtle terminal/tool-call details +- Dark-first interface for phone use +- Optional light mode later + +## Color Palette Draft + +```text +Background: #080A0F +Surface: #10141D +Elevated surface: #171D29 +Card border: rgba(255,255,255,0.08) +Text primary: #F7F8FC +Text secondary: #AAB2C5 +Muted: #687085 + +Hermes gold: #F2C14E +Happy blue: #6EA8FF +Happy purple: #A78BFA +Happy green: #63E6BE +Danger coral: #FF6B6B +Warning amber: #FFD166 +``` + +Gradients: + +```css +--gradient-orb: radial-gradient(circle at 30% 20%, #6EA8FF 0%, #A78BFA 45%, #080A0F 100%); +--gradient-action: linear-gradient(135deg, #6EA8FF, #A78BFA, #63E6BE); +--gradient-hermes: linear-gradient(135deg, #F2C14E, #FF8A65); +``` + +## Typography + +Primary UI: +- Inter, Geist, or system Android sans. + +Mono/details: +- JetBrains Mono for tool outputs, command snippets, paths, logs. + +Type scale: +- Screen title: 28-34px, 700 +- Section title: 18-20px, 650 +- Body: 15-16px +- Metadata: 12-13px +- Tool output: 12-13px mono + +## Layout + +### Mobile shell + +- Full-screen app layout. +- Safe-area aware. +- Bottom navigation with 4-5 tabs: + - Ask + - Activity + - Cron + - Files + - Settings + +### Ask screen + +```text +┌─────────────────────────┐ +│ Hermes status orb │ +│ │ +│ Recent / current task │ +│ ┌───────────────────┐ │ +│ │ assistant answer │ │ +│ └───────────────────┘ │ +│ ┌───────────────────┐ │ +│ │ tool timeline │ │ +│ └───────────────────┘ │ +│ │ +│ [ + ] [ hold voice ] │ +│ [ prompt input ↑ ] │ +└─────────────────────────┘ +``` + +Input should be thumb-first: +- Attachment left +- Voice pill / mic +- Send button right +- Input grows to 4-6 lines max + +## Components + +### Agent Status Orb + +A small animated orb/avatar indicating: +- idle +- thinking +- using tools +- waiting for approval +- done +- error + +This gives the app life without pretending to be a person. + +### Tool Card + +States: +- queued +- running +- success +- failed +- cancelled + +Collapsed view: +```text +[terminal icon] terminal • 2.4s • success +npm test +``` + +Expanded view: +- Arguments summary +- Output preview +- Copy button +- Open file if applicable +- Error highlighting + +### Timeline + +Vertical event feed with icons and subtle connecting line. + +Events: +- Prompt received +- Tool started +- Tool output +- File generated +- Notification sent +- Final answer + +### Approval Card + +Should feel serious but not scary. + +```text +Approval required +Hermes wants to run: +rm -rf /tmp/build-cache + +Risk: destructive file operation +[ Deny ] [ Approve once ] +``` + +### Cron Job Card + +```text +Homelab health check +Every day 09:00 +Last run: success · 2h ago +[Run now] [Pause] +``` + +### Upload Tray + +Shows selected files before sending: +- thumbnail for images +- file icon for zip/pdf/log +- remove button +- total size + +## Motion + +Use motion sparingly but meaningfully: +- status orb breathing while thinking +- tool card expands smoothly +- file upload progress liquid/soft bar +- send button morphs to spinner +- completion haptic-like visual pulse + +Prefer CSS transitions and Framer Motion if bundle size acceptable. + +## Android-native Feeling + +- Installable PWA manifest with proper icons. +- Standalone display mode. +- No browser chrome when installed. +- Bottom nav like native Material apps. +- Pull-to-refresh disabled; in-app refresh buttons where needed. +- Back gesture should close panels before navigating away. +- Use Android share target later so user can share files/text to Hermes. + +## Accessibility + +- Minimum 44px tap targets. +- Color is not the only status indicator. +- Reduced motion support. +- Good contrast in dark mode. +- Voice actions have text alternatives. + +## Design TODO + +- Capture screenshots/references from happy.engineering and Happy app. +- Build a visual moodboard. +- Design first mockups for Ask, Tool Timeline, Cron, Settings. +- Decide exact logo/avatar direction. diff --git a/docs/INSTALL.md b/docs/INSTALL.md new file mode 100644 index 0000000..7149ce9 --- /dev/null +++ b/docs/INSTALL.md @@ -0,0 +1,224 @@ +# Install Strategy + +## Goal + +A one-liner installer that sets up the companion server beside an existing Hermes Agent install. + +Target UX: + +```bash +curl -fsSL https://hermes-mobile.molberg.cloud/install.sh | bash +``` + +or from Gitea release/raw if accessible without auth: + +```bash +curl -fsSL https://git.molberg.cloud/bonzi/hermes-mobile/raw/branch/main/install.sh | bash +``` + +Because Zeb's Gitea raw URLs may require auth, release assets or a mirrored static install URL are safer for the public one-liner. + +## Installer Responsibilities + +1. Detect OS/package manager. +2. Detect Hermes Agent: + - `command -v hermes` + - `~/.hermes/config.yaml` + - optional `HERMES_HOME` +3. Check Node.js version or install bundled binary/runtime. +4. Download latest Hermes Mobile companion release. +5. Create config. +6. Create data directories. +7. Install systemd service. +8. Start service. +9. Print pairing URL and one-time code. + +## Installation Modes + +### System mode (default for servers) + +Paths: + +```text +/opt/hermes-mobile/ app bundle +/etc/hermes-mobile/config.yaml config +/var/lib/hermes-mobile/ DB/uploads/cache +/var/log/hermes-mobile/ logs if not journald-only +``` + +Service: + +```text +hermes-mobile-companion.service +``` + +Run user: +- Option A: current user/root if Hermes is root-installed. +- Option B: `hermes-mobile` user with group/read permissions to Hermes paths. + +For Zeb's box, same user/root is simplest initially because Hermes files live under `/root/.hermes`. + +### User mode + +```bash +curl ... | bash -s -- --user +``` + +Paths: + +```text +~/.local/opt/hermes-mobile/ +~/.config/hermes-mobile/config.yaml +~/.local/share/hermes-mobile/ +~/.config/systemd/user/hermes-mobile-companion.service +``` + +## Service Unit Draft + +```ini +[Unit] +Description=Hermes Mobile Companion Server +After=network-online.target +Wants=network-online.target + +[Service] +Type=simple +User=root +WorkingDirectory=/opt/hermes-mobile +Environment=NODE_ENV=production +Environment=HERMES_MOBILE_CONFIG=/etc/hermes-mobile/config.yaml +ExecStart=/usr/bin/node /opt/hermes-mobile/server/index.js +Restart=always +RestartSec=3 + +[Install] +WantedBy=multi-user.target +``` + +## Config Generation + +Installer should write: + +```yaml +server: + host: 0.0.0.0 + port: 8787 + public_url: "" + +hermes: + home: /root/.hermes + cli_bin: /root/.local/bin/hermes + mode: python + api_base_url: http://127.0.0.1:18793/v1 + +storage: + data_dir: /var/lib/hermes-mobile + max_upload_mb: 512 + +auth: + pairing_enabled: true + +notifications: + provider: webpush +``` + +## Pairing Output + +After start: + +```text +Hermes Mobile installed. + +Open this on your phone: + http://SERVER-IP:8787/pair?code=123-456 + +Pairing code: + 123-456 + +Service: + systemctl status hermes-mobile-companion + +Logs: + journalctl -u hermes-mobile-companion -f +``` + +## Update + +```bash +curl -fsSL https://hermes-mobile.molberg.cloud/install.sh | bash -s -- --update +``` + +Should: +- Download latest release. +- Preserve config and data. +- Restart service. +- Run DB migrations. + +## Uninstall + +```bash +curl -fsSL https://hermes-mobile.molberg.cloud/install.sh | bash -s -- --uninstall +``` + +Should ask/flag whether to keep data: +- `--keep-data` +- `--purge` + +## Release Layout + +Build artifact: + +```text +hermes-mobile-linux-x64.tar.gz + server/ + index.js + package.json + node_modules/ or bundled single executable + public/ + PWA assets + scripts/ + hermes_worker.py + migrations/ +``` + +Better later: +- single static binary via Bun/Node SEA if stable enough. +- Docker image optional but not the primary install path. + +## One-liner Safety + +Installer should: +- Show what it will do. +- Avoid deleting data unless explicitly asked. +- Not overwrite existing config without backup. +- Use `set -euo pipefail`. +- Log to temp file. +- Verify download checksum if release metadata supports it. + +## Development Install + +From cloned repo: + +```bash +pnpm install +pnpm dev +``` + +Companion dev server: + +```bash +pnpm --filter companion dev +``` + +Mobile dev server: + +```bash +pnpm --filter mobile dev --host 0.0.0.0 +``` + +## Future Cloudflare/Tailscale + +Expose options: +- Tailscale only: bind to `100.x` IP or localhost behind `tailscale serve`. +- Cloudflare Tunnel: companion prints local port and expected reverse proxy config. +- Nginx/Caddy snippets generated by installer. diff --git a/docs/MOBILE_APP.md b/docs/MOBILE_APP.md new file mode 100644 index 0000000..0b2290b --- /dev/null +++ b/docs/MOBILE_APP.md @@ -0,0 +1,221 @@ +# Mobile App Plan + +## App Type + +Start as a PWA optimized for Android Chrome. + +Why PWA first: +- Fast iteration. +- Easy self-hosting. +- No app store. +- Installable to home screen. +- Web Push support on Android is good. +- Same frontend can later be wrapped with Capacitor. + +Potential later native shell: +- Capacitor Android for native share target, richer notifications, and better file/mic APIs. + +## Frontend Stack + +Recommended: +- Vite + React + TypeScript +- Tailwind CSS +- TanStack Query for server data +- Zustand for local UI/session state +- Framer Motion for motion where useful +- Workbox or Vite PWA plugin +- Zod for API schema validation + +Alternative: +- Next.js if SSR/server components become useful, but for a companion-served app Vite is simpler. + +## App Package Structure + +```text +apps/mobile/ + src/ + app/ + App.tsx + router.tsx + providers.tsx + screens/ + AskScreen/ + ActivityScreen/ + SessionsScreen/ + CronScreen/ + FilesScreen/ + SettingsScreen/ + components/ + agent-status-orb/ + composer/ + tool-card/ + event-timeline/ + upload-tray/ + voice-recorder/ + cron-job-card/ + approval-card/ + bottom-nav/ + app-shell/ + features/ + tasks/ + sessions/ + cron/ + files/ + approvals/ + notifications/ + pairing/ + settings/ + lib/ + api-client.ts + realtime.ts + push.ts + audio.ts + file-utils.ts + format.ts + styles/ + globals.css + tokens.css + assets/ + icons/ + splash/ + main.tsx + public/ + manifest.webmanifest + service-worker.ts +``` + +## Navigation + +Bottom tabs: +- Ask +- Activity +- Cron +- Files +- Settings + +Sessions can be either: +- a sub-screen from Ask, or +- included in Activity initially. + +## Ask Screen Behavior + +States: +- idle +- composing +- uploading +- sending +- running +- waiting_approval +- finished +- failed + +Composer: +- Text input +- Attach file button +- Hold/tap voice recording button +- Send button +- Optional mode chips: New / Continue / Background + +When task starts: +- Input collapses to bottom. +- Task timeline appears. +- Assistant response streams. +- Tool cards appear in chronological order. + +## Realtime + +Use WebSocket first: +- `/api/realtime?token=...` +- Subscribe to task/session events. + +Fallback: +- SSE `/api/tasks/:id/events/stream` +- Polling last resort. + +Frontend event store should append events idempotently by event ID. + +## Push Notifications + +PWA flow: +1. User enables notifications in Settings. +2. App registers service worker. +3. App subscribes to PushManager. +4. Subscription sent to companion server. +5. Server sends Web Push on completion/approval/cron events. + +Fallback if Web Push fails: +- Configure ntfy link in Settings. + +## Voice Recording + +Use MediaRecorder. + +Preferred mime order: +- `audio/webm;codecs=opus` +- `audio/ogg;codecs=opus` +- browser default fallback + +UI: +- Press/tap mic to start. +- Big recording sheet with timer/waveform. +- Cancel / send. +- Upload progress. + +## File Upload UX + +- Android file picker through ``. +- Share Target API later for “Share to Hermes”. +- Preview thumbnails for images. +- File chips for archives/docs. +- Upload before task send or as part of task multipart. + +## Offline/Background Behavior + +- App shell should load offline. +- Draft prompt persists locally. +- Running task state reloads from server after reconnect. +- No attempt to run Hermes offline. + +## Settings UX + +First launch: +1. Enter companion URL or scan QR/pairing link. +2. Pair device. +3. Test connection. +4. Enable notifications. +5. Land on Ask. + +Settings fields: +- Companion URL +- Device name +- Notification status/test +- Theme +- Default task mode +- Upload retention display +- Hermes health + +## Android Polish Checklist + +- `display: standalone` manifest. +- Proper app icon masks/adaptive icon assets. +- Theme color matching dark background. +- Avoid viewport resize bugs with keyboard. +- Safe-area padding. +- Disable browser pull-to-refresh where possible and add in-app refresh. +- Haptics via Vibration API where appropriate. +- Back button behavior for modals/sheets. + +## Accessibility + +- Visible focus states. +- Reduced motion mode. +- ARIA labels for icon buttons. +- Captions/transcript for voice notes. + +## Future Capacitor Features + +- Native push via FCM. +- Native share target. +- Background upload reliability. +- Local biometric unlock. +- Better notification actions: Approve/Deny from notification. diff --git a/docs/PRODUCT_PLAN.md b/docs/PRODUCT_PLAN.md new file mode 100644 index 0000000..85a4194 --- /dev/null +++ b/docs/PRODUCT_PLAN.md @@ -0,0 +1,250 @@ +# Product Plan + +## Working Name + +Hermes Mobile + +## One-line Pitch + +A private Android-first app for talking to Hermes Agent with voice, files, live tool calls, approvals, cron controls, and completion notifications. + +## Target User + +Primary: Zeb / homelab power user who already runs Hermes Agent on a Linux machine and wants a better phone interface than Telegram. + +Secondary later: +- Developers running Hermes locally/remotely +- Homelab admins +- People who want an agent command center rather than a chatbot + +## Non-goals + +- Not a generic OpenAI chat frontend. +- Not a multi-provider model playground. +- Not a public SaaS. +- Not a replacement for Hermes Agent internals. +- Not a Matrix/Discord/Telegram clone. + +## Design Principles + +1. Agent-first, not chat-first + - The UI should show what Hermes is doing, not just the final response. + - Tool calls are first-class objects. + +2. Phone-native ergonomics + - Thumb-reachable controls. + - Large tap targets. + - Voice and upload actions always nearby. + - Background task status survives app close/reopen. + +3. Private by default + - Self-hosted companion server. + - Local uploads. + - Optional LAN/Tailscale-only mode. + - No third-party notification requirement unless chosen. + +4. Modular integrations + - Hermes CLI bridge now. + - Hermes API bridge where useful. + - Direct Python/event bridge later. + - Notification providers swappable. + +5. Install should feel boring + - One command. + - Clear service status. + - Easy update/uninstall. + +## Core Screens + +### 1. Home / Ask + +Purpose: send a prompt fast. + +Features: +- Text box with multiline support +- Hold-to-record voice note +- Attach button +- Model/session selector compact chip +- “New task” vs “continue session” toggle +- Streaming answer +- Activity timeline under/alongside answer +- Completion toast/push + +### 2. Activity + +Purpose: see active and recent agent runs. + +Features: +- Running tasks +- Tool-call cards +- Logs/output previews +- Generated files +- Error states +- Stop/cancel if supported + +### 3. Sessions + +Purpose: browse/resume history. + +Features: +- Recent conversations +- Search +- Rename/pin/archive +- Session metadata: platform, started, last active, tool count, attachments + +### 4. Cron + +Purpose: manage scheduled Hermes tasks from phone. + +Features: +- Job list grouped by active/paused/completed +- Run now +- Pause/resume/remove +- Edit prompt/schedule later +- Last output viewer +- Delivery target setting: in-app inbox, push, Matrix/Telegram/etc. + +### 5. Files + +Purpose: manage uploaded/generated artifacts. + +Features: +- Upload inbox +- Generated media/files from responses +- Download/share +- Link file into a new prompt +- Retention controls later + +### 6. Approvals + +Purpose: approve dangerous actions safely. + +Features: +- Pending approvals queue +- Command/action preview +- Risk label +- Approve once / deny +- Expiry countdown +- Audit log + +### 7. Settings + +Purpose: connect to companion server and configure app. + +Features: +- Server URL +- Pairing code / passkey login +- Notification test +- Theme +- Hermes health +- Storage/retention +- STT/TTS preferences + +## Feature Details + +### Text Prompting + +Modes: +- Quick ask: starts new task/session. +- Continue: appends to selected session. +- Background task: app can be closed, push when finished. + +### Voice Notes + +MVP flow: +1. Browser MediaRecorder captures audio. +2. Upload audio file to companion. +3. Companion either: + - passes audio path to Hermes gateway/STT path, or + - transcribes with configured local Whisper/faster-whisper, then sends text prompt. +4. UI shows transcript for confirmation if desired. + +Later: +- Voice-to-voice replies using Hermes TTS. +- Streaming partial transcript. + +### File Uploads + +Supported MVP: +- png/jpg/webp/gif +- zip/tar/gz +- pdf +- txt/log/md/json/csv +- arbitrary binary as attachment + +Prompt format to Hermes: +- Store file locally in companion upload store. +- Send prompt with absolute paths and metadata. +- Example: `User uploaded files: /var/lib/hermes-mobile/uploads/.../archive.zip` + +### Tool Calls + +Event model: +- `tool_call.started` +- `tool_call.delta` +- `tool_call.finished` +- `tool_call.failed` + +Tool cards show: +- Icon/name +- Arguments summary +- Status +- Duration +- Expandable result +- Copy/open file actions where relevant + +### Notifications + +MVP notification events: +- task finished +- task failed +- approval required +- cron job completed/failed + +Providers: +- Web Push for installed PWA +- ntfy fallback +- Gotify fallback +- Home Assistant persistent notification optional + +### Cron Triggers + +The app should not reimplement Hermes cron. It should wrap Hermes cronjob functions/CLI: +- list jobs +- run job +- pause/resume/remove +- create/edit later + +### “Prompting itself” / Hermes test harness + +Because Hermes Mobile runs next to Hermes Agent, the companion can test connectivity by sending a harmless prompt through: +- Hermes CLI: `hermes chat -q "ping"` +- API server: `/v1/chat/completions` +- Direct Python bridge later + +The Settings health page should include a `Test Hermes` button. + +## MVP Acceptance Criteria + +- Install companion server on same Linux machine as Hermes. +- Open mobile PWA on Android, pair to companion. +- Send text prompt to Hermes and receive answer. +- Upload a PNG or ZIP and include it in prompt context. +- Record a voice note and turn it into a prompt. +- See at least coarse tool activity while Hermes runs. +- Receive push/ntfy notification when task completes. +- View cron jobs and trigger one manually. + +## Risks + +1. Hermes API server may not expose enough event detail. + - Mitigation: start with CLI/direct Python bridge and add event callbacks. + +2. PWA push notification quirks. + - Mitigation: support ntfy/Gotify fallback. + +3. Mobile browser audio quirks. + - Mitigation: test Android Chrome first; Capacitor later if needed. + +4. Tool-call streaming requires Hermes integration changes. + - Mitigation: companion adapter interface; use available callbacks in AIAgent where possible. diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md new file mode 100644 index 0000000..287d147 --- /dev/null +++ b/docs/ROADMAP.md @@ -0,0 +1,132 @@ +# Roadmap + +## Phase 0 — Planning Scaffold + +Status: current. + +Deliverables: +- Repo created +- Product plan +- Architecture plan +- Design direction +- Install strategy +- Project structure + +## Phase 1 — Skeleton + +Goal: empty but runnable monorepo. + +Deliverables: +- pnpm workspace +- `apps/mobile` Vite React PWA +- `apps/companion` Fastify server +- shared TypeScript package for event/API schemas +- basic app shell with bottom nav +- `/api/health` +- local dev scripts + +## Phase 2 — Basic Hermes Prompting + +Goal: phone can send text prompt and receive final answer. + +Deliverables: +- pairing/auth MVP +- Settings connect flow +- task creation endpoint +- Hermes CLI/API adapter MVP +- Ask screen sends prompt +- response display +- task history in SQLite + +## Phase 3 — Realtime Activity + Tool Timeline + +Goal: see Hermes work live. + +Deliverables: +- event bus +- WebSocket/SSE stream +- tool timeline UI +- Python worker adapter using AIAgent callbacks if needed +- coarse/fine tool event mapping + +## Phase 4 — Uploads + Voice + +Goal: prompt with files and voice notes. + +Deliverables: +- multipart upload endpoint +- upload tray UI +- image/archive/pdf metadata +- voice recorder UI +- local STT or Hermes STT bridge +- attach files to task prompt + +## Phase 5 — Notifications + +Goal: close phone and get told when done. + +Deliverables: +- PWA service worker +- Web Push subscription management +- notification provider abstraction +- ntfy fallback +- completion/failure/approval notifications + +## Phase 6 — Cron + Approvals + +Goal: mobile control plane. + +Deliverables: +- cron list/run/pause/resume/remove +- cron output viewer +- approval queue UI +- companion approval API +- Hermes approval integration strategy + +## Phase 7 — Installer + Release + +Goal: one-liner install. + +Deliverables: +- production build +- install.sh +- systemd service +- update/uninstall modes +- release artifact +- pairing URL output + +## Phase 8 — Android Polish + +Goal: feels native. + +Deliverables: +- refined Happy-inspired UI +- animations/microinteractions +- adaptive icons/splash +- share target +- haptics +- offline shell polish +- optional Capacitor wrapper evaluation + +## Phase 9 — Deep Hermes Integration + +Goal: full Hermes-native experience. + +Deliverables: +- structured event stream from Hermes core or stable Python adapter +- richer session browsing +- generated file detection +- background process control +- subagent visualization +- memory/skills dashboards possibly + +## Open Feature Ideas + +- Quick action tiles: “Check homelab”, “Run DV status”, “Start coding task”. +- Voice-to-voice mode. +- Per-task model/toolset selection. +- “Watch mode” for long-running coding tasks. +- Home Assistant widgets/actions. +- Secure notification actions: approve/deny from notification. +- Android native share target. +- QR pairing from terminal output. diff --git a/docs/TESTING.md b/docs/TESTING.md new file mode 100644 index 0000000..9a2969b --- /dev/null +++ b/docs/TESTING.md @@ -0,0 +1,119 @@ +# Testing Strategy + +## Philosophy + +Hermes Mobile must be tested as an app plus a local service plus a Hermes integration. Generic unit tests are not enough; the important thing is whether a phone can send work to Hermes, see activity, close the app, and get notified when done. + +## Test Layers + +### 1. Unit Tests + +Frontend: +- event reducer/idempotency +- upload tray state +- voice recorder state machine +- API client error handling +- cron job card states + +Companion: +- config loading +- auth pairing tokens +- notification provider interface +- upload path normalization +- event bus fanout +- task state transitions + +### 2. Integration Tests + +Companion server with fake Hermes adapter: +- create task +- stream events +- upload file + attach to task +- completion notification queued +- cron list/run mocks + +Hermes adapter contract tests: +- CLI adapter health +- API adapter health +- Python worker JSONL protocol + +### 3. End-to-End Tests + +Use Playwright against local dev server. + +Scenarios: +- first-time pairing +- send text prompt +- upload PNG and send prompt +- record/upload fake audio blob +- watch tool timeline update +- cron run button +- notification permission flow mocked + +### 4. Real Hermes Smoke Tests + +On a machine with Hermes installed: + +```bash +hermes chat -q "Reply with exactly: hermes-mobile-ok" +``` + +Companion health test should do the equivalent and verify response. + +More advanced smoke: +- Ask Hermes to run a harmless terminal command: `pwd`. +- Verify a tool-call event appears. +- Upload a small text file and ask Hermes to summarize it. + +## Manual Android QA + +Test on Android Chrome installed PWA: +- Install app to home screen. +- Launch standalone mode. +- Keyboard does not break composer layout. +- Back button closes sheets/modals first. +- Voice recording works. +- File picker works for image/zip/pdf. +- Push notification arrives after app is backgrounded. +- App reconnects to running task after being killed/reopened. + +## Compatibility Targets + +- Android Chrome latest +- Android Firefox optional +- Desktop Chrome for dev +- iOS Safari later, not MVP priority + +## Observability for Testing + +Companion should expose: + +```http +GET /api/health +GET /api/debug/events/recent +GET /api/debug/config/redacted +POST /api/hermes/test +POST /api/notifications/test +``` + +Only expose debug endpoints in dev mode or authenticated admin mode. + +## CI Plan + +Later: +- pnpm lint +- pnpm typecheck +- pnpm test +- pnpm e2e with fake adapter +- build release artifact + +## Dogfooding Plan + +The app should be used to prompt Hermes about its own repo. + +Example dogfood tasks: +- “Run the test suite for Hermes Mobile and summarize failures.” +- “Inspect the companion logs and fix the upload bug.” +- “Create a cron job that reminds me if companion is down.” + +This is important because Hermes is both the target agent and the tool used to build the app. diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..ce0fc25 --- /dev/null +++ b/install.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Placeholder installer. Real implementation will arrive after the skeleton server exists. +# Target UX: +# curl -fsSL https://hermes-mobile.molberg.cloud/install.sh | bash + +echo "Hermes Mobile installer placeholder" +echo "This repo is currently a planning scaffold; no companion server is installed yet." +echo +if command -v hermes >/dev/null 2>&1; then + echo "Detected Hermes CLI: $(command -v hermes)" +else + echo "Hermes CLI not found in PATH." +fi + +echo "Planned install docs: docs/INSTALL.md"