Environment
- Deployment: Docker (
nousresearch/hermes-agent:latest)
HERMES_UID=1000, HERMES_GID=911 set in compose
- Profiles in use (charles profile active for kanban dispatch)
- Version: v0.13.0
Behavior
When the kanban dispatcher spawns workers for profile-namespaced tasks (e.g. hermes -p charles ... kanban task <id>), the worker process calls ensure_hermes_home() on startup (config.py:428), which creates missing subdirectories including logs/curator. These directories land as root:root on the host volume mount despite the gateway itself running as uid 1000 via gosu.
Subsequent worker invocations running as uid 1000 fail immediately with:
PermissionError: [Errno 13] Permission denied: '/opt/data/profiles/charles/logs/curator'
and:
Failed to initialize agent: [Errno 13] Permission denied: '/opt/data/profiles/charles/logs/agent.log'
Root Cause
The entrypoint correctly drops privileges via gosu hermes before the main gateway process. However, kanban workers are spawned as child processes of the dispatcher — if any code path in the dispatcher forks before the privilege drop is complete, or if the dispatcher itself runs in a context where uid hasn't dropped, ensure_hermes_home() creates directories as root. These then block uid-1000 workers.
The needs_chown condition in the entrypoint (HERMES_UID != "10000") ensures a chown -R runs on /opt/data (the root hermes home) at startup — but this does not cover profiles/<name>/ subdirectories created at runtime after the container starts.
Reproduction
- Run hermes in Docker with
HERMES_UID=1000 and a named profile (e.g. -p charles)
- Have the dispatcher claim and spawn a kanban task worker for that profile
- Observe
logs/curator and agent.log created as root:root in the profile dir
- Subsequent workers for the same profile fail with
Permission denied
Expected behavior
All directories created by ensure_hermes_home() for any profile should be owned by the hermes user (uid=HERMES_UID), regardless of which process triggers their creation.
Workaround
chown -R user:nasusers /root/.hermes/profiles/charles/ after each container restart. Not suitable for production.
Environment
nousresearch/hermes-agent:latest)HERMES_UID=1000,HERMES_GID=911set in composeBehavior
When the kanban dispatcher spawns workers for profile-namespaced tasks (e.g.
hermes -p charles ... kanban task <id>), the worker process callsensure_hermes_home()on startup (config.py:428), which creates missing subdirectories includinglogs/curator. These directories land asroot:rooton the host volume mount despite the gateway itself running as uid 1000 via gosu.Subsequent worker invocations running as uid 1000 fail immediately with:
and:
Root Cause
The entrypoint correctly drops privileges via
gosu hermesbefore the main gateway process. However, kanban workers are spawned as child processes of the dispatcher — if any code path in the dispatcher forks before the privilege drop is complete, or if the dispatcher itself runs in a context where uid hasn't dropped,ensure_hermes_home()creates directories as root. These then block uid-1000 workers.The
needs_chowncondition in the entrypoint (HERMES_UID != "10000") ensures achown -Rruns on/opt/data(the root hermes home) at startup — but this does not coverprofiles/<name>/subdirectories created at runtime after the container starts.Reproduction
HERMES_UID=1000and a named profile (e.g.-p charles)logs/curatorandagent.logcreated asroot:rootin the profile dirPermission deniedExpected behavior
All directories created by
ensure_hermes_home()for any profile should be owned by the hermes user (uid=HERMES_UID), regardless of which process triggers their creation.Workaround
chown -R user:nasusers /root/.hermes/profiles/charles/after each container restart. Not suitable for production.