github →

New request

#2491: Audit and replace WebUI's direct dependence on the hermes-agent source tree (slice 2 of #2453)

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
enhancementdockertracking

Issue: Define the WebUI ↔ Agent API contract so the WebUI no longer requires direct access to the agent's source tree

Background

#2453 (RustyLopez) raised that the WebUI's multi-container setup requires mounting the agent's source tree (/opt/hermes) into the WebUI container, which creates implementation coupling and removes any meaningful trust boundary between the two containers.

Two short-term remediations have already shipped in v0.51.84 (PR #2470):

  1. The hermes-agent-src volume is now mounted read-only on the WebUI service. The WebUI never writes to it; the kernel now enforces that.
  2. docs/docker.md gained an explicit "What the multi-container setup isolates (and what it doesn't)" section calibrating expectations: process / network / resource isolation, not filesystem isolation.

@Michaelyklam and @RustyLopez both pointed out (rightly) that the durable fix is to eliminate the source mount entirely by routing whatever the WebUI currently does at the source-tree level through an explicit, stable agent API.

What this issue tracks

The durable second slice: define the specific API surface the WebUI needs from hermes-agent, then thread WebUI code over those endpoints so the source mount can be removed.

Why the WebUI currently needs source access (audit)

Three concrete consumers in the current WebUI codebase:

  1. docker_init.bash:381-403 — at container startup, runs uv pip install "$_agent_src[all]" against the agent source tree to get the agent's Python dependencies into the WebUI's virtualenv. This is the biggest reason the source mount exists today.

  2. api/startup.py:_agent_dir() / _trusted_agent_dir() / auto_install_agent_deps() (lines 58-128) — non-Docker startup path that locates the agent checkout via HERMES_WEBUI_AGENT_DIR or $HERMES_HOME/hermes-agent, validates ownership/permissions, then pip installs the agent on demand. Same shape as the docker_init path but for native installs.

  3. api/streaming.py:429 and the broader streaming layer — imports modules from the agent package at runtime (gateway client, session DB, cron scheduler internals). This is the trickier one: it's not a startup-only dependency, it's the runtime API surface.

Proposed slice 2 (this issue)

Replace each of the above with an explicit agent-side API call:

WebUI consumerReplace with
uv pip install from source at container startupWebUI image bundles its own minimum agent client lib (a pip-installable hermes-agent-client), so it never needs the agent's full source tree. The agent project would publish that client lib to PyPI on every release.
auto_install_agent_deps() (native installs)Same client lib. HERMES_WEBUI_AGENT_DIR becomes a contract path (only the API endpoint URL + auth token live there), not a source path.
Direct module imports in api/streaming.py and friendsEnumerate the actual imports, classify each as (a) trivially replaceable by a documented REST/IPC endpoint, (b) needs a new agent endpoint, or (c) genuinely WebUI-internal and can stay in this repo.

Acceptance criteria

  1. A complete enumeration of agent-source imports the WebUI does today (one PR's worth of audit work — pure investigation, no code change).
  2. A documented hermes-agent API surface that covers every (a) and (b) above.
  3. A new hermes-agent-client PyPI package (or equivalent) that wraps the above.
  4. WebUI changes to consume the client library exclusively.
  5. The hermes-agent-src named volume can be removed from docker-compose.two-container.yml and docker-compose.three-container.yml.
  6. docker_init.bash no longer runs uv pip install against a shared volume at startup.
  7. api/startup.py's auto_install_agent_deps() deletes its source-tree dependency.

What this issue does NOT cover (intentionally)

  • Single-container setup: the WebUI runs the agent in-process there. That's by design and doesn't have the coupling problem (one process boundary, one trust boundary). No change needed.
  • The runtime-hardening half of #2453: already shipped in PR #2470 (read-only mount + docs framing).
  • Defining the actual API endpoints: this issue tracks the work in nesquena/hermes-webui. The agent-side endpoint design lives in the NousResearch/hermes-agent repo and will need a companion issue there once we have the audit from criterion 1.

Related

  • #2453 (parent — runtime-hardening half done, API-contract half tracked here)
  • #1416 (named-volume staleness — also addressed by removing the source mount)
  • PR #2470 (the runtime-hardening half)
  • PR #2490 (Docker runtime smoke gate — closes the test-coverage gap that let the #2470-class regression nearly ship)
Assessmentadvisory
feature●●● hard90% confidence

Cross-cutting architectural refactor to replace direct filesystem coupling with a stable, container-spanning API contract.

Likely files
  • api/routes/agent.py
  • api/routes/sessions.py
  • api/services/agent_proxy.py
  • static/js/workspace/browser.js
  • docker-compose.yml
  • docs/docker.md
  • api/bootstrap.py
Create the request

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

Cancel