hermes - 💡(How to fix) Fix `docker_run_as_host_user: true` breaks bundled skills: Hermes home is mounted into `/root/.hermes` but the container runs as a non-root user (`HOME=/home/pn`)

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

When the docker terminal backend is used together with terminal.docker_run_as_host_user: true, bundled skills that resolve the Hermes home via get_hermes_home() (default ~/.hermes) cannot find their data, because Hermes mounts the home content into /root/.hermes/ (root-home assumption) while the container process runs as uid 1000 (pn, HOME=/home/pn). The mounted files land at a path the running user never looks at.

Concretely, the bundled google-workspace skill fails with:

NOT_AUTHENTICATED: No token at /home/pn/.hermes/google_token.json

even though the token exists and Hermes did mount it — at /root/.hermes/google_token.json.

Root Cause

When the docker terminal backend is used together with terminal.docker_run_as_host_user: true, bundled skills that resolve the Hermes home via get_hermes_home() (default ~/.hermes) cannot find their data, because Hermes mounts the home content into /root/.hermes/ (root-home assumption) while the container process runs as uid 1000 (pn, HOME=/home/pn). The mounted files land at a path the running user never looks at.

Fix Action

Workaround

Set HERMES_HOME to the in-container mount of the Hermes home via docker_env:

terminal:
  backend: docker
  docker_run_as_host_user: true
  docker_env:
    HERMES_HOME: /workspace/hermes   # = the in-container mount of ~/.hermes

Code Example

NOT_AUTHENTICATED: No token at /home/pn/.hermes/google_token.json

---

$ docker inspect <hermes-container> --format 'User=[{{.Config.User}}]'
User=[1000:1000]            # uid 1000 = pn, HOME=/home/pn

---

$ docker inspect <hermes-container> --format '{{range .Mounts}}{{.Source}} -> {{.Destination}}{{println}}{{end}}'
~/.hermes/google_token.json         -> /root/.hermes/google_token.json
~/.hermes/google_client_secret.json -> /root/.hermes/google_client_secret.json
~/.hermes/skills                    -> /root/.hermes/skills
~/.hermes/sandboxes/.../home        -> /root
~/.hermes                           -> /workspace/hermes

---

# skills/productivity/google-workspace/scripts/_hermes_home.py
def get_hermes_home() -> Path:
    val = os.environ.get("HERMES_HOME", "").strip()
    return Path(val) if val else Path.home() / ".hermes"   # -> /home/pn/.hermes

---

terminal:
  backend: docker
  docker_run_as_host_user: true
  docker_env:
    HERMES_HOME: /workspace/hermes   # = the in-container mount of ~/.hermes
RAW_BUFFERClick to expand / collapse

Summary

When the docker terminal backend is used together with terminal.docker_run_as_host_user: true, bundled skills that resolve the Hermes home via get_hermes_home() (default ~/.hermes) cannot find their data, because Hermes mounts the home content into /root/.hermes/ (root-home assumption) while the container process runs as uid 1000 (pn, HOME=/home/pn). The mounted files land at a path the running user never looks at.

Concretely, the bundled google-workspace skill fails with:

NOT_AUTHENTICATED: No token at /home/pn/.hermes/google_token.json

even though the token exists and Hermes did mount it — at /root/.hermes/google_token.json.

Environment

  • Hermes Agent v0.14.0 (not re-verified against latest main)
  • terminal.backend: docker
  • terminal.docker_run_as_host_user: true
  • Base image: nikolaik/python-nodejs:python3.11-nodejs20 (default non-root user pn, uid 1000, HOME=/home/pn)
  • Host user hermes is uid 1000 (so --user 1000:1000 maps to pn in the container)

Steps to reproduce

  1. Configure the docker backend with docker_run_as_host_user: true.
  2. Authenticate the bundled google-workspace skill (token written to ~/.hermes/google_token.json on the host).
  3. From any session/Telegram, ask the agent to use Gmail/Calendar.
  4. The skill reports NOT_AUTHENTICATED: No token at /home/pn/.hermes/google_token.json.

Evidence

The container is created with --user 1000:1000:

$ docker inspect <hermes-container> --format 'User=[{{.Config.User}}]'
User=[1000:1000]            # uid 1000 = pn, HOME=/home/pn

…but Hermes mounts the home content into /root/.hermes/ (root-home assumption):

$ docker inspect <hermes-container> --format '{{range .Mounts}}{{.Source}} -> {{.Destination}}{{println}}{{end}}'
~/.hermes/google_token.json         -> /root/.hermes/google_token.json
~/.hermes/google_client_secret.json -> /root/.hermes/google_client_secret.json
~/.hermes/skills                    -> /root/.hermes/skills
~/.hermes/sandboxes/.../home        -> /root
~/.hermes                           -> /workspace/hermes

The skill resolves the token path from HERMES_HOME, which is unset in the container, so it falls back to Path.home()/.hermes:

# skills/productivity/google-workspace/scripts/_hermes_home.py
def get_hermes_home() -> Path:
    val = os.environ.get("HERMES_HOME", "").strip()
    return Path(val) if val else Path.home() / ".hermes"   # -> /home/pn/.hermes

So the skill looks in /home/pn/.hermes/ while the files are mounted in /root/.hermes/. Hermes sets neither a mount at the running user's $HOME/.hermes nor a HERMES_HOME env to reconcile.

(Same divergence applies to skills/: the agent searches /home/pn/.hermes/skills — not found — while the skills are mounted at /root/.hermes/skills.)

Expected behavior

With docker_run_as_host_user: true, bundled skills should resolve the Hermes home correctly. Either:

  • mount the home content into the actual container user's $HOME/.hermes (derived from the uid's passwd home, e.g. /home/pn/.hermes) instead of the hardcoded /root/.hermes, or
  • set HERMES_HOME in the container environment to the mounted home path, so get_hermes_home() resolves correctly regardless of the container user.

Actual behavior

Mount destinations are hardcoded to /root/.hermes and HERMES_HOME is not set, so any non-root container user (as produced by docker_run_as_host_user: true) breaks bundled skills that rely on get_hermes_home().

Notes

  • The failure is silent and looks intermittent: it "works" in the session where the skill was set up (ephemeral in-container state), then breaks on the next container (the persistent container is recreated on gateway restart / idle sweep), which makes it hard to diagnose.
  • The docs for docker_run_as_host_user mention losing apt install / writes to root-owned paths, but do not mention this consequence for bundled skills.

Workaround

Set HERMES_HOME to the in-container mount of the Hermes home via docker_env:

terminal:
  backend: docker
  docker_run_as_host_user: true
  docker_env:
    HERMES_HOME: /workspace/hermes   # = the in-container mount of ~/.hermes

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

Expected behavior

With docker_run_as_host_user: true, bundled skills should resolve the Hermes home correctly. Either:

  • mount the home content into the actual container user's $HOME/.hermes (derived from the uid's passwd home, e.g. /home/pn/.hermes) instead of the hardcoded /root/.hermes, or
  • set HERMES_HOME in the container environment to the mounted home path, so get_hermes_home() resolves correctly regardless of the container user.

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING