Skip to content

[Bug]: terminal tool passes invalid workdir to Docker exec and overrides configured terminal.cwd #4669

@jbeausoleil

Description

@jbeausoleil

Bug Description

When using the Docker terminal backend with a valid configured session working directory (for example terminal.cwd: /workspace), Hermes can still fail terminal commands if a terminal tool call provides an invalid workdir.

Instead of validating the per-call workdir or falling back to the configured session cwd, Hermes forwards the invalid path directly to docker exec -w ..., which causes the command to fail.

This makes it look like Docker is ignoring terminal.cwd, but the real problem is that an invalid per-call workdir overrides it without validation.

Steps to Reproduce

  1. Configure a profile with a Docker terminal backend like:

    terminal:
      backend: docker
      cwd: /workspace
      docker_image: nikolaik/python-nodejs:python3.11-nodejs20
      docker_volumes:
        - /path/to/host/workspace:/workspace
      docker_mount_cwd_to_workspace: false
      container_persistent: false
      persistent_shell: false
  2. Confirm /workspace exists and is writable inside the container.

  3. Run Hermes with that profile explicitly.

  4. Trigger a terminal tool call that includes an invalid workdir (for example a malformed path such as /workspace/..???).

  5. Observe that Hermes runs docker exec -w <invalid-path> ... and the command fails.

Expected Behavior

If terminal.cwd is configured as /workspace, that should remain the effective default session cwd.

If a terminal tool call includes an invalid workdir, Hermes should either:

  • reject it before execution with a clear validation error, or
  • ignore it and fall back to the configured session cwd (/workspace)

It should not pass an invalid path straight through to docker exec -w.

Actual Behavior

Hermes lets the per-call workdir override the configured session cwd and forwards it directly to Docker.

Example failure:

OCI runtime exec failed: exec failed: unable to start container process: chdir to cwd ("/workspace/..???") set in config.json failed: no such file or directory

Affected Component

Tools (terminal, file ops, web, code execution, etc.)

Messaging Platform (if gateway-related)

N/A (CLI only)

Operating System

macOS

Python Version

3.11.x

Hermes Version

Hermes Agent v0.6.0 (2026.3.30)

Relevant Logs / Traceback

Observed terminal tool call:

   
   {
     "name": "terminal",
     "arguments": {
       "command": "pwd && <command omitted> && pwd",
       "background": false,
       "timeout": 300,
       "workdir": "/workspace/..???",
       "check_interval": 30,
       "pty": false
     }
   }
   

   Result:

   
   {
     "output": "OCI runtime exec failed: exec failed: unable to start container process: chdir to cwd (\"/workspace/..???\") set in config.json failed: no such file or directory",
     "exit_code": 127,
     "error": null
   }

Root Cause Analysis (optional)

The Docker backend itself appears to honor terminal.cwd correctly.

The actual code path looks like:

  • tools/terminal_tool.py:_get_env_config() reads TERMINAL_CWD
  • _create_environment(..., cwd=cwd, ...) creates the Docker environment with /workspace
  • tools/environments/docker.py starts the container with docker run -w /workspace
  • but later, tools/terminal_tool.py passes workdir directly to env.execute(...) if present
  • tools/environments/docker.py then does docker exec -w <workdir> ...

So terminal.cwd is only acting as a default, and invalid per-call workdir values are not validated before overriding it.

Proposed Fix (optional)

In tools/terminal_tool.py, validate/sanitize workdir before passing it to env.execute(...).

If workdir is invalid or does not exist in the active backend, Hermes should:

  • either return a clear validation error before calling Docker, or
  • fall back to env.cwd / configured terminal.cwd

Minimal fix area:

  • tools/terminal_tool.py where execute_kwargs["cwd"] = workdir is set before env.execute(...)

Are you willing to submit a PR for this?

  • I'd like to fix this myself and submit a PR

Metadata

Metadata

Assignees

No one assigned

    Labels

    sweeper:implemented-on-mainSweeper: behavior already present on current maintype/bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions