nesquena/hermes-webui

Docker-sandbox artifacts fail to open in file browser (container path not mapped to host sandbox mirror)

Open

#7,097 opened on Aug 16, 2026

 (1 comment) (0 reactions) (0 assignees)Python (2,399 forks)github user discovery
bugdockerhelp wantedprioritysprint-candidate

Repository metrics

Stars
 (17,426 stars)
PR merge metrics
 (Avg merge 14h 31m) (314 merged PRs in 30d)

Description

Summary

When the Hermes terminal backend is docker with filesystem persistence enabled (the default, container_persistent: true), agent-created artifacts written to container paths under /root/… cannot be opened from the WebUI file browser — clicking them fails with "Could not open file" (HTTP 404) even though the file exists on the host.

Environment

  • hermes-webui on master
  • Hermes Agent terminal backend: docker, persistent container (container_persistent: true)
  • Reproducible independent of host OS

Root cause

With docker persistence, Hermes bind-mounts the container's home and workspace from the host sandbox dir:

  • container /root<sandbox_dir>/docker/<task_id>/home/
  • container /workspace<sandbox_dir>/docker/<task_id>/workspace/

where <sandbox_dir> defaults to ~/.hermes/sandboxes (overridable via TERMINAL_SANDBOX_DIR). For the default shared persistent container, <task_id> is default.

So a file the agent creates at container path /root/subdir/file.py physically lives on the host at:

<sandbox_dir>/docker/default/home/subdir/file.py

However, the artifact records the container path (/root/subdir/file.py). The file-browser handlers — _handle_list_dir (/api/list) and the /api/file read handler — resolve the requested path relative to the session's host workspace (e.g. a plain host directory) via list_dir() / safe_resolve_ws(), which enforce containment under that workspace. The container path is neither under the session workspace nor present on the host at that literal location, so resolution 404s. The leading slash is stripped client-side, producing a request like:

GET /api/list?session_id=<id>&path=root/subdir   ->  404

Steps to reproduce

  1. Run Hermes with terminal.backend: docker (default container_persistent: true).
  2. Open a WebUI session whose workspace is an ordinary host directory.
  3. Have the agent create a file at a container path outside that workspace, e.g. /root/subdir/file.py.
  4. Click the resulting artifact in the WebUI.
  5. Observed: /api/list?...&path=root/subdir returns 404; the UI shows "Could not open file". The file is present on the host at <sandbox_dir>/docker/default/home/subdir/file.py.

Expected

The artifact opens. For a docker-sandbox session, when a requested path isn't resolvable under the session workspace, the browser should map container paths to their host bind-mount mirror:

  • /root/X<sandbox_dir>/docker/<task_id>/home/X
  • /workspace/X<sandbox_dir>/docker/<task_id>/workspace/X

Notes / suggested fix

  • The mapping is deterministic (see above); <sandbox_dir> comes from TERMINAL_SANDBOX_DIR (default ~/.hermes/sandboxes), and the shared persistent container uses task id default.
  • Containment/security must be preserved: apply the existing safe_resolve_ws / O_NOFOLLOW anchored-walk containment against the sandbox mirror root so symlink escapes remain blocked.
  • Both the directory-listing (/api/list) and file-read (/api/file, /api/file/raw) paths need the mapping.

Contributor guide