github →

New request

#272: Real-time bidirectional sync between Gateway sessions and WebUI

We'll provision a sandbox, run an agent against the issue, and open a draft PR. You can pull the branch and iterate from there.

Issue
holdupstream-change

Real-time bidirectional sync between Gateway sessions and WebUI

Problem

When Hermes Agent runs with a gateway (Telegram, Discord, etc.), the WebUI currently offers read-only snapshot access to gateway sessions via the CLI session bridge. There is no real-time synchronization between the two:

  • Messages sent via Telegram don't appear live in the WebUI
  • Replying from the WebUI to a gateway session is not possible
  • The CLI bridge imports a static snapshot that never refreshes

This means users who primarily interact via messaging platforms can't use the WebUI as a full interface to participate in those same conversations.

Current Architecture

Gateway side (hermes-agent):

  • Dual-layer storage: in-memory SessionStore + SQLite state.db (WAL mode)
  • state.db has sessions and messages tables with FTS5
  • Gateway API server on port 8642 (aiohttp)
  • Sessions tagged with source field: 'telegram', 'discord', 'cli', etc.
  • Session keys: agent:main:telegram:dm:<chat_id>

WebUI side (hermes-webui):

  • Own session store: JSON files in ~/.hermes/webui/sessions/
  • CLI bridge in api/models.py: get_cli_sessions() reads metadata from state.db, get_cli_session_messages() reads messages
  • api/state_sync.py: WebUI → agent direction only (for /insights cost tracking)
  • SSE streaming for agent responses (per-stream queue, not persistent)

Proposed Approach

Phase 1: Gateway → WebUI (read-only live view)

  1. Add a background watcher in the WebUI (api/session_watcher.py) that polls state.db every 2-3 seconds for new messages/sessions
  2. Push detected changes to the browser via a persistent SSE endpoint (/api/gateway/stream)
  3. Gateway sessions appear live in the sidebar with real-time message updates (similar to how Telegram works in the WebUI)

This requires no changes to hermes-agent — the WebUI already has read access to state.db and the gateway uses WAL mode so reads are non-blocking.

Phase 2: WebUI → Gateway (bidirectional)

  1. WebUI connects to the gateway's API (port 8642) as a client
  2. When replying to a gateway session in the WebUI, the message is forwarded to the gateway for processing
  3. The gateway streams the response back to the WebUI via the existing API
  4. Gateway sessions become fully interactive in the WebUI — not just viewable, but usable

This requires gateway API changes to support an external client sending messages to existing sessions.

Benefits

  • Full parity: the WebUI becomes a true universal interface for all Hermes conversations
  • Phone users on Telegram and desktop users on WebUI can participate in the same session
  • No duplicate sessions — one conversation, multiple interfaces
  • Leverages the existing shared ~/.hermes/ filesystem

Complexity Estimate

  • Phase 1: ~200-300 lines of Python in the WebUI, low risk, can be done in one sprint
  • Phase 2: ~150-200 lines in both WebUI and gateway, medium risk, requires coordination with hermes-agent

Open Questions

  • Should gateway sessions be editable (rename, delete, archive) from the WebUI?
  • How to handle concurrent access (reply from Telegram + WebUI at the same time)?
  • Should the gateway expose an SSE/WebSocket events endpoint instead of having the WebUI poll state.db?

Happy to discuss the approach and contribute implementation. I've explored both codebases in detail and can submit a PR for Phase 1 if there's interest.

Assessmentadvisory
feature●●● hard80% confidence

Architectural overhaul to enable persistent bidirectional synchronization between gateway runtimes and the WebUI session store.

Likely files
  • api/state_sync.py
  • api/models.py
  • api/streaming.py
  • api/gateway_client.py
  • static/js/sidebar/sync.js
  • api/routes/sessions.py
  • tests/test_gateway_sync.py
Create the request

This opens a fresh agent run and a draft PR for issue #272.

Cancel