8.5 KiB
17 — Future Control Surface (post-M7)
Status: research / backlog — not scheduled. M0–M7 cover the chat surface (messages, streaming, tools, media, push, channels, search). This doc records what the app could additionally control through the gateway, based on a survey of the hermes-agent source (2026-08-21). Nothing here is locked; it is a menu of options, each with the hermes backend that already implements it.
The key insight
Hermes already ships a complete REST API — hermes_cli/web_server.py plus
hermes_cli/web_routers/ — which is the backend of the desktop/dashboard UI.
Our gateway plugin runs inside the same hermes gateway process, so every
capability below is reachable by importing and calling the same functions the
web server calls. Exposing one from the app = a new request/response frame pair
in our protocol (protocol.py → Protocol.kt → frames.schema.json, the
usual three-way mirror).
The constraint is never "can hermes do it?" (it can — all of it) — it is how many frame pairs we want to add and the security review each one needs.
Implementation paths
- Direct function calls (preferred). The plugin imports the hermes
modules (
cron.jobs,hermes_cli.kanban_db, config loaders, …) and calls them. No extra process, no extra port, zero new deps. - Proxy to the web server's REST API. Only works if
hermes web/hermes dashboardis running — it is not by default. Rejected for v1.
Capability menu
Cron jobs — fully controllable
| App action | Hermes backend |
|---|---|
| List jobs (incl. disabled) | cron/jobs.py list_jobs() |
| Create job | cron/jobs.py create_job() (schedules: 30m, every monday 9am, 5-field cron, ISO one-shot) |
| Edit job | cron/jobs.py update_job(job_id, updates) |
| Pause / resume | cron/jobs.py pause_job() / resume_job() |
| Trigger now | cron/jobs.py trigger_job() |
| Delete job | web router web_routers/cron.py DELETE /api/cron/jobs/{id} |
| Run history | web_routers/cron.py GET /api/cron/jobs/{id}/runs; hermes_state_portability.py list_cron_job_runs() |
| Delivery targets | web_routers/cron.py GET /api/cron/delivery-targets |
| One-tap suggestions | cron/suggestions.py — ready-to-run job specs the user accepts/dismisses; accept_suggestion() calls create_job directly. Designed for a UI; ideal first feature. |
| Blueprints | cron/blueprint_catalog.py, web_routers/cron.py GET /api/cron/blueprints + POST /api/cron/blueprints/instantiate |
Per-job fields worth surfacing: model/provider overrides, skills,
script, context_from (chain job A's output into job B), workdir,
multi-platform delivery.
Kanban board — fully controllable
| App action | Hermes backend |
|---|---|
| Boards: list / create / rename / delete / switch | hermes_cli/kanban_db.py create_board() / list_boards(); REST plugins/kanban/dashboard/plugin_api.py /boards* |
| Tasks: create / list / show / update / delete | kanban_db.py create_task() / list_tasks() / complete_task(); REST /tasks* |
| Comments / links / attachments | REST /tasks/{id}/comments, /links, /tasks/{id}/attachments |
| Bulk operations | REST POST /tasks/bulk |
| Dispatch / reassign / reclaim / estimate | REST /dispatch, /tasks/{id}/reassign, /tasks/{id}/reclaim, /estimate |
| Runs: inspect / terminate | REST /runs/{run_id}, /runs/{run_id}/terminate |
| Stats / diagnostics / active workers | REST /stats, /diagnostics, /workers/active |
| Per-task model options | REST /model-options |
Bonus: the kanban dispatcher already runs inside the gateway by default
(kanban.dispatch_in_gateway: true), so a phone app would see dispatch
activity live. The full REST surface (~30 endpoints) is in
plugins/kanban/dashboard/plugin_api.py.
Model / provider registry — fully controllable
| App action | Hermes backend |
|---|---|
| Set active model | web_server.py POST /api/model/set |
| List model options / info / recommended default | GET /api/model/options, /api/model/info, /api/model/recommended-default |
| Auxiliary (side-LLM) models | GET/PUT /api/model/auxiliary |
| MoA config | GET/PUT /api/model/moa |
| Per-profile model | web_routers/profiles.py PUT /api/profiles/{name}/model |
| Per-toolset model / provider / env | web_routers/tools.py PUT /api/tools/toolsets/{name}/model / /provider / /env |
| Custom endpoints: CRUD + validate + activate | web_server.py /api/providers/custom-endpoints* |
| Provider validation / OAuth flows | POST /api/providers/validate, /api/providers/oauth* |
API keys (.env): set / reveal / delete |
web_server.py GET/PUT/DELETE /api/env, POST /api/env/reveal |
config.yaml: read / write / schema |
GET/PUT /api/config, GET /api/config/schema |
Webhooks
| App action | Hermes backend |
|---|---|
| Subscribe / list / remove / test inbound webhook routes | hermes_cli/webhook.py (hermes webhook CLI: _cmd_subscribe, _cmd_list, _cmd_remove, _cmd_test); subscriptions stored in ~/.hermes/webhooks/subscriptions.json |
Sessions
List, FTS search, rename, delete, bulk-delete, export (md/html), prune —
web_routers/sessions.py (/api/sessions*). Overlaps with what the app
already shows from its own chat; useful for browsing other platforms'
sessions (Telegram, CLI, cron runs).
Profiles
CRUD, switch active profile, edit soul/description, per-profile model,
export/import — web_routers/profiles.py (/api/profiles*).
Skills
List, toggle, create/edit content, hub search/install/uninstall/update —
web_routers/skills.py (/api/skills*, /api/skills/hub/*).
Tools / toolsets
Enable/disable per platform, per-toolset config/model/provider/env —
web_routers/tools.py (/api/tools/toolsets*).
MCP servers
CRUD, test, auth/OAuth flows, catalog browse + install —
web_routers/mcp.py (/api/mcp/*).
Git
Status, branches, worktrees, and a full review flow (stage/unstage/revert/
commit/push/create-PR) — web_routers/git.py (/api/git/*).
Files
Upload/download/read/write, fs list/mkdir — web_server.py /api/files*,
/api/fs/*. (Complements the existing media frames in 07-media.md.)
Messaging platforms
List/configure/test other platforms (Telegram, WhatsApp onboarding) —
web_server.py /api/messaging/*.
Memory providers
Config + setup per provider — web_server.py /api/memory/providers/*.
Ops / system
| App action | Hermes backend |
|---|---|
| Gateway restart / drain | web_server.py POST /api/gateway/restart, /api/gateway/drain |
| Hermes update check / install | POST /api/hermes/update, GET /api/hermes/update/check |
| Curator (skill maintenance) status / pause / run | GET /api/curator, PUT /api/curator/paused, POST /api/curator/run |
| Audio: transcribe / TTS / voices | POST /api/audio/transcribe, POST /api/audio/speak, GET /api/audio/elevenlabs/voices |
| System stats / status / health | GET /api/system/stats, /api/status, /api/health |
| Learning graph node CRUD | GET/PUT/DELETE /api/learning/node* |
Design notes
- Protocol cost is low. The existing frame model (
type+ payload, request/response correlated byid) already fits; we would add pairs likecron.list/cron.create,kanban.task.create,model.set, following the standard three-way mirror (gateway-plugin/protocol.py→app/shared/.../protocol/Protocol.kt→docs/protocol/frames.schema.json). - Security is the real gate. The single-user model in
09-pairing-security.mdstill holds, but control frames widen the blast radius of a leakedIRIS_TOKEN. Sensitive operations (env/secrets, config writes, gateway restart, profile deletion) should get either an in-app confirmation step or a capability flag negotiated at pairing. - Read-heavy first. Most of the value is in list/view frames (cheap, low-risk); write frames can follow per domain.
- Broadcast routing applies. Frames broadcast to all connected devices
(locked decision,
16-open-questions.md); a control response should be routed to the requesting device only, like other request/response pairs.
Natural first picks (suggested order)
- Cron — list / create / pause / trigger + one-tap suggestions (the suggestion flow was literally designed for a UI).
- Kanban — view board, add task, complete task.
- Model switch —
model.set+model.options(small, high value). - Sessions — list/search across platforms.
All four are read-heavy with cheap writes and low security risk.