Skip to content

RFC: Make WebUI a thin observability/control client over Hermes Agent runtime #1925

@Michaelyklam

Description

@Michaelyklam

Summary

Hermes WebUI currently gives a polished browser experience, but browser-originated chat runs are executed inside the WebUI server process. That means WebUI is more than an interface layer: it creates in-memory streams, starts background agent threads, instantiates/reuses AIAgent, and owns live cancellation/streaming state.

This RFC proposes shifting WebUI toward the thinnest possible client that still gives full parity features:

Hermes Agent owns execution, sessions, active runs, slash-command semantics, approvals, clarify, tools, models, and durable state. WebUI owns presentation, browser UX, and control/observability surfaces over Hermes.

The goal is not to reduce WebUI capability. The goal is to prevent WebUI from becoming a parallel Hermes runtime.

Current behavior / motivation

Today, the WebUI chat path roughly does this:

  1. Browser calls POST /api/chat/start.
  2. WebUI creates a stream_id and StreamChannel.
  3. WebUI stores the stream in process-global STREAMS.
  4. WebUI starts a daemon thread running _run_agent_streaming.
  5. _run_agent_streaming constructs/reuses AIAgent and calls agent.run_conversation(...).
  6. Agent callbacks push token/tool/reasoning/approval/clarify events back into WebUI-owned in-memory queues.

This has some nice properties: direct low-latency SSE, simple local deployment, and direct access to the live agent object. But it also creates real costs:

  • WebUI restarts/updates can kill active browser-originated runs.
  • Browser refresh/reconnect semantics depend on WebUI process memory.
  • WebUI has to maintain runtime shims for Hermes behavior.
  • Features such as slash commands, /goal, model/provider routing, approvals, clarify, queue/interrupt/steer, etc. risk being reimplemented in WebUI instead of inherited from Hermes.
  • Active WebUI streams can block safe WebUI updates.
  • WebUI cannot be treated as a disposable observability/control layer.

Design principle

For every feature, ask:

Is this Hermes behavior, or WebUI presentation?

Hermes behavior should be exposed from Hermes and consumed by WebUI. WebUI should own only browser-specific presentation and interaction.

Hermes should own

  • agent execution
  • sessions and transcript persistence
  • active run lifecycle
  • model/provider/toolset routing
  • memory and skills
  • slash command semantics/capabilities
  • approvals and clarify lifecycle
  • cancel/interrupt/queue/steer semantics
  • background and goal continuation
  • token/tool/reasoning events
  • cron/gateway/session state

WebUI should own

  • layout and navigation
  • chat rendering
  • stream visualization
  • tool-call cards
  • approval/clarify widgets
  • session browser UX
  • settings panels
  • workspace picker UX
  • themes/mobile/PWA/native-wrapper behavior
  • adapting Hermes events into a great browser experience

Proposed direction

Move browser-originated execution out of WebUI-owned AIAgent threads and into Hermes Agent’s native runtime/API surface.

Hermes Agent already has an API server with run-like endpoints:

POST /v1/runs
GET  /v1/runs/{run_id}
GET  /v1/runs/{run_id}/events
POST /v1/runs/{run_id}/stop

WebUI should use Hermes-owned runtime APIs as the execution boundary rather than importing/instantiating AIAgent directly.

Target architecture:

Browser
  ↓
WebUI: UI, auth/session presentation, SSE/WebSocket adapter, controls
  ↓
Hermes Agent runtime/API: sessions, active runs, events, commands, approvals, tools
  ↓
AIAgent / tools / gateway / cron / state.db

Proposed phases

Phase 1: Document the boundary and current coupling

  • Document the current WebUI-owned execution path.
  • Document which runtime features WebUI currently reimplements or owns directly.
  • Define the desired owner for each feature: Hermes vs WebUI.

Acceptance criteria:

  • Maintainers agree on the boundary: WebUI should be a thin client over Hermes runtime, not a second runtime.

Phase 2: Adapter spike against Hermes /v1/runs

  • Add a feature flag, e.g. HERMES_WEBUI_USE_HERMES_RUNS=1.
  • Keep existing WebUI frontend event format initially.
  • Internally route WebUI chat start to Hermes /v1/runs.
  • Subscribe to /v1/runs/{run_id}/events and adapt Hermes events to current WebUI SSE events.
  • Use Hermes /v1/runs/{run_id}/stop for cancellation.

Acceptance criteria:

  • A browser-originated chat can run without WebUI instantiating AIAgent.
  • Existing WebUI rendering continues working through an adapter.
  • WebUI restart no longer kills a Hermes-owned run, assuming Hermes remains up.

Phase 3: Identify missing Hermes runtime API capabilities

While building the adapter, record missing pieces that force WebUI to keep private runtime state.

Likely needs:

  • list active runs
  • map session → active run(s)
  • replay events from a cursor / Last-Event-ID
  • approval request/response API
  • clarify request/response API
  • queue/interrupt/steer API
  • command metadata with WebUI support/capability flags
  • session/run status fields sufficient for reconnect UI

Acceptance criteria:

  • Missing capabilities are tracked upstream in Hermes Agent rather than patched as WebUI-only runtime logic.

Phase 4: Delegate Hermes-native slash/control commands

  • Continue using Hermes command metadata.
  • Add capability metadata so WebUI can know which commands are supported on the WebUI surface.
  • Delegate Hermes-owned commands to Hermes instead of reimplementing them in WebUI.
  • Keep WebUI-local commands local, e.g. theme/layout/browser UI commands.

Examples:

Command / behavior Desired owner
/goal Hermes
/model / provider routing Hermes
/reasoning Hermes
/compress Hermes
/status runtime status Hermes
/theme WebUI
workspace picker UX WebUI presentation over Hermes/workspace config
terminal drawer UI WebUI presentation

Acceptance criteria:

  • WebUI no longer has to chase parity for Hermes-native behavior one command at a time.

Phase 5: Make WebUI restart/update safe by default

  • WebUI restart should only drop the browser connection.
  • Browser reconnect should discover the active Hermes run and resume event rendering.
  • WebUI updates should not need to block on active Hermes-owned runs.
  • Legacy WebUI-owned streams can remain blocked/drained during transition.

Acceptance criteria:

  • Start a long-running run from WebUI.
  • Restart hermes-webui.service.
  • Reopen browser.
  • The run is still active or completed in Hermes.
  • WebUI catches up to current run/session state.

Non-goals

  • Not a rewrite of the frontend.
  • Not a new sidecar service by default.
  • Not a requirement for Redis/Kafka/NATS.
  • Not horizontal scaling in the first pass.
  • Not removing rich WebUI features.
  • Not exposing CLI-only or unsafe gateway-only commands blindly.

Open questions

  1. Should WebUI talk to Hermes Agent API server directly, or through a small local adapter inside WebUI?
  2. Which current WebUI behaviors must remain WebUI-local because they are presentation-only?
  3. What is the minimal Hermes API surface needed for feature parity?
  4. How should browser reconnect discover an active run for the currently viewed session?
  5. Should Hermes event replay be durable immediately, or can phase 1 start with live Hermes SSE and add replay later?
  6. How should Hermes Agent updates behave while a Hermes-owned run is active?
  7. What command capability metadata is needed so WebUI can safely inherit Hermes-native slash commands?

Success criteria

This is successful when:

  • WebUI does not import or instantiate AIAgent for normal chat.
  • WebUI can be restarted without killing active Hermes-owned runs.
  • Browser refresh/reconnect does not duplicate or lose runs.
  • WebUI renders live token/tool/reasoning/approval/clarify state from Hermes events.
  • WebUI sends control actions to Hermes rather than mutating live agent objects.
  • Hermes-native slash command behavior is inherited where possible.
  • WebUI remains rich, but its codebase becomes mostly UI/adapters instead of agent orchestration.

One-line north star

Build WebUI as the first-class Hermes client, not a second Hermes runtime.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requesttrackingTracking issue for follow-up workupstream-changeRequires an upstream change before it can be resolved.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions