Upstream issue draft — Hermes Chat tab EACCES
File this against NousResearch/hermes-agent once reviewed. Run from this directory:
gh issue create --repo NousResearch/hermes-agent \
--title "Dashboard Chat tab fails with EACCES in Docker image — /opt/hermes/ui-tui is root-owned but dashboard runs as hermes" \
--body-file docs/upstream-issue-chat-tab-eacces.md
Summary
In the official nousresearch/hermes-agent:latest Docker image (verified on v0.12.0 (2026.4.30)), the dashboard's embedded Chat tab (enabled by hermes dashboard --tui) fails with the banner "Chat unavailable: 1" on first connection.
Root cause: the dashboard runs as the unprivileged hermes user (after the entrypoint drops privileges via gosu), but /opt/hermes/ui-tui/ and its dist/ directories are baked into the image as root:root. When _make_tui_argv() tries to rebuild the TUI bundle on first run, esbuild fails to write to /opt/hermes/ui-tui/packages/hermes-ink/dist/entry-exports.js with EACCES, the build aborts, _make_tui_argv calls sys.exit(1), and web_server.pty_ws reports Chat unavailable: {SystemExit(1)} over the WebSocket.
Reproduction
- Pull and run the official image with the dashboard in
--tui mode:
services:
hermes:
image: nousresearch/hermes-agent:latest
command: ["/bin/bash", "-c", "hermes dashboard --host 0.0.0.0 --port 9119 --no-open --insecure --tui & exec hermes gateway run --accept-hooks"]
ports: ["127.0.0.1:18789:9119"]
environment:
HERMES_INFERENCE_PROVIDER: openrouter
HERMES_INFERENCE_MODEL: deepseek/deepseek-v4-flash
OPENROUTER_API_KEY: <key>
- Open
http://localhost:18789 → Chat tab.
- Banner shows: Chat unavailable: 1
Confirmed root cause
Run _make_tui_argv directly as the hermes user:
docker exec -u hermes <container> bash -c '\
export HOME=/opt/data && \
/opt/hermes/.venv/bin/python3 -c \
"from hermes_cli.main import _make_tui_argv, PROJECT_ROOT; \
print(_make_tui_argv(PROJECT_ROOT / \"ui-tui\", tui_dev=False))"'
Output (abridged):
TUI build failed.
> hermes-tui@0.0.1 build
> npm run build --prefix packages/hermes-ink && tsc -p tsconfig.build.json && ...
✘ [ERROR] Failed to write to output file:
open /opt/hermes/ui-tui/packages/hermes-ink/dist/entry-exports.js: permission denied
ls -la /opt/hermes/ui-tui/dist /opt/hermes/ui-tui/packages/hermes-ink/dist shows both directories owned by root:root in the shipped image, while the running process is uid=hermes.
Workaround
Chown the directory inside the running container:
docker exec -u root <container> chown -R hermes:hermes /opt/hermes/ui-tui
After that the build succeeds ((['/usr/bin/node', '/opt/hermes/ui-tui/dist/entry.js'], ...)), and the Chat tab works on next connect.
This survives docker compose restart but not image rebuild / pull, so users hit it again after every update.
Suggested fixes (any one is sufficient)
- Dockerfile:
RUN chown -R hermes:hermes /opt/hermes/ui-tui after the build stage that produces dist/.
- Entrypoint (
/opt/hermes/docker/entrypoint.sh): chown /opt/hermes/ui-tui alongside the existing $HERMES_HOME chown (it already runs as root before the gosu drop).
- Skip rebuild when dist is current: tighten
_tui_need_npm_install / _tui_build_needed so a fresh image with a complete prebuilt dist/ doesn't trigger a rebuild attempt at all. The entry.js is already present and runnable; the rebuild is only needed in dev mode.
Bonus: better error surfacing
pty_ws in hermes_cli/web_server.py catches SystemExit and renders Chat unavailable: {exc} — which becomes the unhelpful Chat unavailable: 1. Surfacing the underlying npm/esbuild stderr (or at least a hint like "TUI build failed; see container logs") would have shaved hours off debugging.
Environment
- Image:
nousresearch/hermes-agent:latest (v0.12.0 (2026.4.30))
- Host: Debian 12 / Docker 26.x on a DigitalOcean droplet
- Compose: docker compose v2
- Started via
hermes dashboard --tui in foreground+background pattern (dashboard bg, hermes gateway run fg)
Related code paths
_DASHBOARD_EMBEDDED_CHAT_ENABLED gates /api/pty (works correctly)
_make_tui_argv in hermes_cli/main.py (the failing path)
pty_ws in hermes_cli/web_server.py (catches SystemExit and returns the unhelpful : 1 banner)
Upstream issue draft — Hermes Chat tab EACCES
File this against
NousResearch/hermes-agentonce reviewed. Run from this directory:gh issue create --repo NousResearch/hermes-agent \ --title "Dashboard Chat tab fails with EACCES in Docker image — /opt/hermes/ui-tui is root-owned but dashboard runs as hermes" \ --body-file docs/upstream-issue-chat-tab-eacces.mdSummary
In the official
nousresearch/hermes-agent:latestDocker image (verified onv0.12.0 (2026.4.30)), the dashboard's embedded Chat tab (enabled byhermes dashboard --tui) fails with the banner "Chat unavailable: 1" on first connection.Root cause: the dashboard runs as the unprivileged
hermesuser (after the entrypoint drops privileges viagosu), but/opt/hermes/ui-tui/and itsdist/directories are baked into the image asroot:root. When_make_tui_argv()tries to rebuild the TUI bundle on first run, esbuild fails to write to/opt/hermes/ui-tui/packages/hermes-ink/dist/entry-exports.jswith EACCES, the build aborts,_make_tui_argvcallssys.exit(1), andweb_server.pty_wsreportsChat unavailable: {SystemExit(1)}over the WebSocket.Reproduction
--tuimode:http://localhost:18789→ Chat tab.Confirmed root cause
Run
_make_tui_argvdirectly as thehermesuser:Output (abridged):
ls -la /opt/hermes/ui-tui/dist /opt/hermes/ui-tui/packages/hermes-ink/distshows both directories owned byroot:rootin the shipped image, while the running process isuid=hermes.Workaround
Chown the directory inside the running container:
After that the build succeeds (
(['/usr/bin/node', '/opt/hermes/ui-tui/dist/entry.js'], ...)), and the Chat tab works on next connect.This survives
docker compose restartbut not image rebuild / pull, so users hit it again after every update.Suggested fixes (any one is sufficient)
RUN chown -R hermes:hermes /opt/hermes/ui-tuiafter the build stage that producesdist/./opt/hermes/docker/entrypoint.sh): chown/opt/hermes/ui-tuialongside the existing$HERMES_HOMEchown (it already runs as root before the gosu drop)._tui_need_npm_install/_tui_build_neededso a fresh image with a complete prebuiltdist/doesn't trigger a rebuild attempt at all. Theentry.jsis already present and runnable; the rebuild is only needed in dev mode.Bonus: better error surfacing
pty_wsinhermes_cli/web_server.pycatchesSystemExitand rendersChat unavailable: {exc}— which becomes the unhelpfulChat unavailable: 1. Surfacing the underlying npm/esbuild stderr (or at least a hint like "TUI build failed; see container logs") would have shaved hours off debugging.Environment
nousresearch/hermes-agent:latest(v0.12.0 (2026.4.30))hermes dashboard --tuiin foreground+background pattern (dashboard bg,hermes gateway runfg)Related code paths
_DASHBOARD_EMBEDDED_CHAT_ENABLEDgates/api/pty(works correctly)_make_tui_argvinhermes_cli/main.py(the failing path)pty_wsinhermes_cli/web_server.py(catchesSystemExitand returns the unhelpful: 1banner)