terminal.docker_extra_args from config.yaml silently dropped
Affected: Hermes Agent v0.14.0 (tag v2026.5.16). Confirmed still present in main HEAD as of 2026-05-19 (hermes update pulled 27 new commits since v2026.5.16; the bug is unchanged).
Summary
The _terminal_env_map dict in gateway/run.py (the bridge of yaml.terminal.* keys → TERMINAL_* env vars at gateway startup) omits docker_extra_args. As a result, anything set via hermes config set terminal.docker_extra_args [...] or written directly to config.yaml is silently ignored by terminal_tool, which reads only from the TERMINAL_DOCKER_EXTRA_ARGS env var.
This makes the documented Docker hardening config path non-functional.
Reproduction
- Configure the Docker backend and add hardening flags via the documented yaml path. Because
hermes config set doesn't accept list values cleanly (a separate issue), edit ~/.hermes/config.yaml directly:
terminal:
backend: docker
docker_extra_args:
- "--read-only"
- "--tmpfs"
- "/root:rw,exec,size=1g,mode=1777"
- Restart gateway:
hermes gateway restart --system.
- Have the agent invoke any terminal command (or trigger one via
hermes chat -q "выполни id").
- Inspect the resulting
docker run invocation in ~/.hermes/logs/agent.log:
grep 'Docker run_args' ~/.hermes/logs/agent.log | tail -1
Expected: --read-only and the custom --tmpfs flags appear at the end of the run_args list (extra_args is appended last per tools/environments/docker.py).
Actual: They are absent. The container starts without --read-only and with the default Hermes /root tmpfs (no mode=1777 override). If the image's /root inherits mode 0700 and the container runs as a non-root user, every command then fails with:
bash: line N: cd: /root: Permission denied
The agent reports this back to the user as an unrelated "permission denied" error and the silent-drop is invisible without inspecting the run_args log line.
Root cause
gateway/run.py defines _terminal_env_map (around the _terminal_cfg = _cfg.get("terminal", {}) block). It includes most terminal.* keys (e.g. docker_image, docker_volumes, docker_env, docker_run_as_host_user, docker_mount_cwd_to_workspace, container_cpu/memory/disk/persistent) but not docker_extra_args.
tools/terminal_tool.py _get_env_config() then reads:
"docker_extra_args": _parse_env_var("TERMINAL_DOCKER_EXTRA_ARGS", "[]", json.loads, "valid JSON"),
Since the env var is never set by the bridge, the function returns [], and the user's hardening config is dropped without any warning.
docker_forward_env appears to have the same gap.
Fix (1–2 lines)
Add to _terminal_env_map in gateway/run.py:
"docker_extra_args": "TERMINAL_DOCKER_EXTRA_ARGS",
"docker_forward_env": "TERMINAL_DOCKER_FORWARD_ENV",
hermes_cli/config.py _config_to_env_sync (used by hermes config set) should match.
Why this matters
docker_extra_args is the only documented escape hatch for additional docker run flags: runtime hardening (--read-only, --security-opt, custom --tmpfs overrides), per-image quirks, anything Hermes doesn't model directly. Silently dropping it forces operators to bypass the documented path entirely (manually exporting env vars in .env), and the lack of any warning makes the failure hide behind unrelated downstream errors (container permission denials at runtime).
Workaround
Set the env var directly in ~/.hermes/.env:
TERMINAL_DOCKER_EXTRA_ARGS=["--read-only","--tmpfs","/root:rw,exec,size=1g,mode=1777"]
terminal_tool picks it up. Restart gateway. To verify it actually reached docker run, grep Docker run_args: in agent.log — the extra flags should appear at the end of the list.
terminal.docker_extra_argsfromconfig.yamlsilently droppedAffected: Hermes Agent v0.14.0 (tag
v2026.5.16). Confirmed still present inmainHEAD as of 2026-05-19 (hermes updatepulled 27 new commits since v2026.5.16; the bug is unchanged).Summary
The
_terminal_env_mapdict ingateway/run.py(the bridge ofyaml.terminal.*keys →TERMINAL_*env vars at gateway startup) omitsdocker_extra_args. As a result, anything set viahermes config set terminal.docker_extra_args [...]or written directly toconfig.yamlis silently ignored byterminal_tool, which reads only from theTERMINAL_DOCKER_EXTRA_ARGSenv var.This makes the documented Docker hardening config path non-functional.
Reproduction
hermes config setdoesn't accept list values cleanly (a separate issue), edit~/.hermes/config.yamldirectly:hermes gateway restart --system.hermes chat -q "выполни id").docker runinvocation in~/.hermes/logs/agent.log:Expected:
--read-onlyand the custom--tmpfsflags appear at the end of the run_args list (extra_args is appended last pertools/environments/docker.py).Actual: They are absent. The container starts without
--read-onlyand with the default Hermes/roottmpfs (nomode=1777override). If the image's/rootinherits mode0700and the container runs as a non-root user, every command then fails with:The agent reports this back to the user as an unrelated "permission denied" error and the silent-drop is invisible without inspecting the run_args log line.
Root cause
gateway/run.pydefines_terminal_env_map(around the_terminal_cfg = _cfg.get("terminal", {})block). It includes mostterminal.*keys (e.g.docker_image,docker_volumes,docker_env,docker_run_as_host_user,docker_mount_cwd_to_workspace,container_cpu/memory/disk/persistent) but notdocker_extra_args.tools/terminal_tool.py_get_env_config()then reads:Since the env var is never set by the bridge, the function returns
[], and the user's hardening config is dropped without any warning.docker_forward_envappears to have the same gap.Fix (1–2 lines)
Add to
_terminal_env_mapingateway/run.py:hermes_cli/config.py_config_to_env_sync(used byhermes config set) should match.Why this matters
docker_extra_argsis the only documented escape hatch for additionaldocker runflags: runtime hardening (--read-only,--security-opt, custom--tmpfsoverrides), per-image quirks, anything Hermes doesn't model directly. Silently dropping it forces operators to bypass the documented path entirely (manually exporting env vars in.env), and the lack of any warning makes the failure hide behind unrelated downstream errors (container permission denials at runtime).Workaround
Set the env var directly in
~/.hermes/.env:terminal_toolpicks it up. Restart gateway. To verify it actually reacheddocker run, grepDocker run_args:inagent.log— the extra flags should appear at the end of the list.