docs: inventory agent source boundary
This commit is contained in:
1 parent
f1d399b437
commit
310d69bed8
6 files changed
+158
No files matched your search
@@ -2,6 +2,14 @@
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
|
||||
- **PR #2482** by @Michaelyklam (refs #2453) — Add a durable source/API boundary inventory for the WebUI's remaining Hermes Agent source dependencies: chat execution, runtime events, profiles, goals, slash/plugin commands, provider/auth/model catalogs, redaction parity, and imported Agent/Gateway sessions. The new RFC tracks replacement API contracts before the source mount can be removed.
|
||||
|
||||
### Changed
|
||||
|
||||
- **PR #2482** by @Michaelyklam (refs #2453) — Make the multi-container source boundary more explicit: Docker docs and README now link the boundary inventory, and `docker_init.bash` emits a startup warning when the WebUI sees a writable agent-source mount instead of the default read-only `hermes-agent-src` mount.
|
||||
|
||||
## [v0.51.85] — 2026-05-17 — Release BI (stage-378 — 3-PR batch — workspace-prefix display leakage fix + release-tag update banner + Slice 3a cancel-control gate RFC)
|
||||
|
||||
### Fixed
|
||||
|
||||
@@ -208,6 +208,8 @@ docker compose -f docker-compose.three-container.yml up -d
|
||||
Both compose files use **named Docker volumes** by default, which solves the UID/GID problem by construction. If you need bind mounts to share an existing host directory, see [`docs/docker.md`](docs/docker.md) for the full migration recipe.
|
||||
|
||||
> **Known limitation (#681)**: in the two-container setup, tools triggered from the WebUI run in the **WebUI container**, not the agent container. If you need git/node/etc. on the WebUI's filesystem, either use the single-container setup, extend the WebUI Dockerfile, or use the community [all-in-one image](https://github.com/sunnysktsang/hermes-suite).
|
||||
>
|
||||
> **Source boundary note (#2453)**: the multi-container setup mounts `hermes-agent-src` read-only into the WebUI by default. This prevents WebUI-side source rewrites but is still an implementation-coupling bridge, not a stable Agent API boundary. See [`docs/rfcs/agent-source-boundary.md`](docs/rfcs/agent-source-boundary.md) for the current source/API decoupling inventory.
|
||||
|
||||
### Common failure modes
|
||||
|
||||
|
||||
@@ -391,6 +391,15 @@ else
|
||||
fi
|
||||
done
|
||||
if [ -n "$_agent_src" ]; then
|
||||
if [ -w "$_agent_src" ]; then
|
||||
echo ""
|
||||
echo "!! WARNING: hermes-agent source mount is writable from the WebUI container."
|
||||
echo "!! Path: $_agent_src"
|
||||
echo "!! The multi-container compose defaults use a read-only mount for defence-in-depth."
|
||||
echo "!! If this is not an intentional local development checkout, switch the WebUI"
|
||||
echo "!! agent source volume/bind mount to read-only. See docs/rfcs/agent-source-boundary.md."
|
||||
echo ""
|
||||
fi
|
||||
uv pip install "$_agent_src[all]" --trusted-host pypi.org --trusted-host files.pythonhosted.org || error_exit "Failed to install hermes-agent's requirements"
|
||||
else
|
||||
echo ""
|
||||
|
||||
@@ -211,6 +211,8 @@ What multi-container does **not** isolate:
|
||||
|
||||
If you need **filesystem isolation** between the chat UI and the agent (e.g. you don't trust the WebUI to read agent state), the multi-container setup is not enough — run the agent on a separate host and connect the WebUI to it via the gateway HTTP API. If you don't need any boundary, the single-container setup is simpler.
|
||||
|
||||
The direct source mount is a compatibility bridge, not the long-term API contract. The current source/API boundary inventory and decoupling task list live in [`docs/rfcs/agent-source-boundary.md`](rfcs/agent-source-boundary.md) for [#2453](https://github.com/nesquena/hermes-webui/issues/2453). If you customize the compose files with bind mounts, keep the WebUI-side agent source mount read-only unless you are intentionally doing local development; `docker_init.bash` warns at startup when that path is writable.
|
||||
|
||||
## Bind-mount migration (advanced)
|
||||
|
||||
If you really need to bind-mount an existing host `~/.hermes` (e.g. you're keeping config in dotfiles, sharing with a non-Docker `hermes` install, etc.):
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
# Agent Source Boundary and API Decoupling Inventory
|
||||
|
||||
- **Status:** Proposed
|
||||
- **Created:** 2026-05-17
|
||||
- **Tracking issue:** [#2453](https://github.com/nesquena/hermes-webui/issues/2453)
|
||||
|
||||
## Problem
|
||||
|
||||
The WebUI currently depends on Hermes Agent Python source being importable at
|
||||
runtime. In local installs this usually means a neighboring checkout; in the
|
||||
multi-container Docker setup it means the WebUI reads the `hermes-agent-src`
|
||||
volume that the agent container also uses.
|
||||
|
||||
That source mount is a compatibility bridge, not the desired long-term contract.
|
||||
Even when mounted read-only on the WebUI side, it couples WebUI releases to
|
||||
Hermes Agent internal module layout and makes the multi-container setup look more
|
||||
isolated than it really is.
|
||||
|
||||
## Current safety posture
|
||||
|
||||
- The multi-container compose files mount `hermes-agent-src` read-only into the
|
||||
WebUI service by default.
|
||||
- `docker_init.bash` prunes the agent source subtree from `chown` so read-only
|
||||
mounts do not break startup.
|
||||
- If an operator overrides the compose files with a mutable agent-source mount,
|
||||
startup now emits a notable warning. The WebUI still starts because local dev
|
||||
checkouts and custom deployments may intentionally be writable, but the warning
|
||||
makes the reduced boundary explicit.
|
||||
|
||||
## Source-access inventory
|
||||
|
||||
These are the current WebUI capabilities that still rely on Agent source or
|
||||
`hermes_cli`/`agent` modules being importable. Each item should eventually move
|
||||
behind an explicit, versioned Agent API or a packaged library contract that does
|
||||
not require mounting the live source checkout.
|
||||
|
||||
| WebUI capability | Current dependency | Desired API / contract | Notes |
|
||||
|---|---|---|---|
|
||||
| Browser chat execution | `run_agent.AIAgent` imported by `api/streaming.py` | Run lifecycle API: start, observe, status, cancel, approval, clarify, final usage | Covered by the runtime-adapter migration in [#1925](https://github.com/nesquena/hermes-webui/issues/1925), but still source-backed today. |
|
||||
| Runtime event rendering | WebUI callbacks around Agent token/reasoning/tool events | Stable event envelope for tokens, reasoning, progress, tool lifecycle, approvals, clarify, errors, and final usage | The existing run-adapter RFC describes the browser-facing shape; Agent still needs a durable producer contract. |
|
||||
| Profile list/create/delete/seed | `hermes_cli.profiles` from `api/profiles.py` | Profile management API with profile metadata, env/runtime context, seed/delete operations, and validation errors | WebUI has fallback filesystem handling for some operations, but feature parity follows Hermes CLI internals. |
|
||||
| Goal command state | `hermes_cli.goals` from `api/goals.py` | Goal CRUD/control API: get, save, pause/resume/clear, and status | Should preserve current `/goal` WebUI behavior without direct module import. |
|
||||
| Slash command registry and plugin commands | `hermes_cli.commands` and `hermes_cli.plugins` from `api/commands.py` | Command/plugin capability discovery API scoped by active profile | WebUI should render command help from a stable capability response. |
|
||||
| Provider/auth/model catalogs | `hermes_cli.models`, `hermes_cli.auth`, and `agent.credential_pool` from `api/config.py` | Provider registry, model catalog, auth status, OAuth/credential-pool status APIs | WebUI has static fallbacks, but exact parity and custom provider state come from Agent internals. |
|
||||
| Redaction helper parity | `agent.redact.redact_sensitive_text` from `api/helpers.py` | Redaction service/library contract with signature/version compatibility | WebUI keeps a fallback redactor because this import has changed before. |
|
||||
| CLI/Gateway session bridge | Agent `state.db` schema and gateway metadata read by sidebar/session helpers | Session listing/transcript/metadata API for non-WebUI-originated sessions | Direct SQLite/schema coupling should narrow over time, especially for messaging/email/gateway sessions. |
|
||||
|
||||
## Decoupling task list
|
||||
|
||||
1. Keep the Docker default safe: WebUI-side `hermes-agent-src` stays read-only in
|
||||
two- and three-container compose files.
|
||||
2. Keep documenting the boundary honestly: multi-container isolates process,
|
||||
network, and resources, not filesystem/source compatibility.
|
||||
3. Warn loudly when the WebUI container sees a writable agent-source mount in
|
||||
Docker, because that weakens the defense-in-depth posture.
|
||||
4. Convert runtime execution first through the #1925 RuntimeAdapter path instead
|
||||
of adding new direct imports.
|
||||
5. For each inventory row, file or link a follow-up that defines the Agent API
|
||||
response shape before replacing the import.
|
||||
6. Do not claim the source mount can be removed until chat execution, provider
|
||||
catalogs/auth status, profiles, goals, commands/plugins, redaction, and
|
||||
imported Agent/Gateway sessions all have stable replacement contracts.
|
||||
|
||||
## Non-goals for this slice
|
||||
|
||||
- Do not remove `HERMES_WEBUI_AGENT_DIR`.
|
||||
- Do not break local source-checkout development.
|
||||
- Do not fail startup solely because the agent source is writable.
|
||||
- Do not replace the runtime adapter or Hermes Agent API in this document-only
|
||||
inventory slice.
|
||||
@@ -0,0 +1,67 @@
|
||||
"""Regression coverage for issue #2453 agent-source boundary docs/warnings."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
REPO = Path(__file__).resolve().parents[1]
|
||||
|
||||
|
||||
def test_agent_source_boundary_rfc_inventories_import_coupling():
|
||||
"""The #2453 source-boundary work must keep a concrete import inventory.
|
||||
|
||||
The risk in #2453 is not just a Docker mount mode; it is that WebUI behavior
|
||||
still relies on Hermes Agent internals. Pinning these rows prevents the docs
|
||||
from degrading into a vague security note without the follow-up task list.
|
||||
"""
|
||||
doc = REPO / "docs" / "rfcs" / "agent-source-boundary.md"
|
||||
assert doc.exists(), "#2453 needs a durable source/API boundary RFC"
|
||||
src = doc.read_text(encoding="utf-8")
|
||||
|
||||
required_terms = [
|
||||
"run_agent.AIAgent",
|
||||
"hermes_cli.profiles",
|
||||
"hermes_cli.goals",
|
||||
"hermes_cli.commands",
|
||||
"hermes_cli.plugins",
|
||||
"hermes_cli.models",
|
||||
"hermes_cli.auth",
|
||||
"agent.credential_pool",
|
||||
"agent.redact.redact_sensitive_text",
|
||||
"state.db",
|
||||
]
|
||||
for term in required_terms:
|
||||
assert term in src, f"agent source-boundary RFC must inventory {term}"
|
||||
|
||||
for api_phrase in (
|
||||
"Run lifecycle API",
|
||||
"Profile management API",
|
||||
"Command/plugin capability discovery API",
|
||||
"Provider registry, model catalog, auth status",
|
||||
"Session listing/transcript/metadata API",
|
||||
):
|
||||
assert api_phrase in src, f"RFC must name replacement contract: {api_phrase}"
|
||||
|
||||
|
||||
def test_docker_startup_warns_when_agent_source_mount_is_writable():
|
||||
"""Mutable WebUI-side agent source mounts should be visibly discouraged.
|
||||
|
||||
The compose default is read-only, but custom bind mounts can still make the
|
||||
WebUI's agent source path writable. The entrypoint should warn instead of
|
||||
silently accepting a weakened boundary.
|
||||
"""
|
||||
src = (REPO / "docker_init.bash").read_text(encoding="utf-8")
|
||||
|
||||
assert "agent source mount is writable" in src
|
||||
assert "read-only mount" in src
|
||||
assert "$_agent_src" in src
|
||||
assert "-w \"$_agent_src\"" in src
|
||||
|
||||
|
||||
def test_docker_docs_link_source_boundary_inventory():
|
||||
"""Docker docs should link the #2453 inventory from the boundary section."""
|
||||
src = (REPO / "docs" / "docker.md").read_text(encoding="utf-8")
|
||||
|
||||
assert "agent-source-boundary.md" in src
|
||||
assert "source/API boundary inventory" in src
|
||||
assert "#2453" in src
|
||||
Reference in new issue
Block a user