This page documents the environment abstraction layer that enables Hermes Agent to execute commands and manipulate files across multiple execution backends (local, Docker, Modal, SSH, Singularity, and Daytona) through a unified interface. This abstraction allows tools like terminal, read_file, write_file, patch, and search_files to work identically regardless of where the code runs.
The abstraction provides:
BaseEnvironment abstract base class tools/environments/base.py19-21Sources: tools/environments/base.py1-21 tools/terminal_tool.py530-631 tools/environments/local.py148-173 tools/code_execution_tool.py135-173
All execution environments implement a minimal interface consisting of core methods defined in the BaseEnvironment class.
| Method | Signature | Purpose |
|---|---|---|
execute() | execute(command: str, cwd: str = None, timeout: int = None, stdin_data: str = None) -> dict | Execute a shell command and return a dictionary containing output and returncode tools/environments/base.py214-219 |
cleanup() | cleanup() -> None | Release resources, such as stopping containers, closing SSH ControlMaster sockets, or terminating sandboxes tools/environments/base.py216 |
ProcessHandle Protocol: Backends return a ProcessHandle (like subprocess.Popen) or a _ThreadedProcessHandle for SDK-based backends (Modal, Daytona) to provide a consistent polling and wait interface tools/environments/base.py187-200DaytonaEnvironment and ModalEnvironment use a _stdin_mode = "heredoc" for stdin_data to pass multi-line strings into cloud sandboxes efficiently tools/environments/base.py102-133touch_activity_if_due function allows long-running executions to report liveness to the gateway via a thread-local activity callback, preventing session timeouts during heavy computation tools/environments/base.py156-181_pipe_stdin which writes through the underlying byte buffer on a daemon thread tools/environments/base.py102-133mv -f operation to prevent concurrent command execution from reading torn/corrupted state files tests/tools/test_base_environment.py139-153Sources: tools/environments/base.py44-219 tests/tools/test_base_environment.py139-182
The _create_environment() function in terminal_tool.py serves as the central factory. It resolves the backend type from the TERMINAL_ENV variable and instantiates the specific implementation class tools/terminal_tool.py406-454
Sources: tools/terminal_tool.py406-454
Configuration follows a strict hierarchy:
register_task_env_overrides(), used for specific tasks or benchmarks tools/terminal_tool.py378-395TERMINAL_ENV, TERMINAL_DOCKER_IMAGE, TERMINAL_SSH_HOST, etc. tools/terminal_tool.py9-12local backend) tools/terminal_tool.py10Sources: tools/terminal_tool.py8-12 tools/terminal_tool.py378-454
Environments are created on-demand and stored in a global _active_environments registry, keyed by task_id. To prevent race conditions where multiple tool calls attempt to spawn the same sandbox simultaneously, a _creation_locks dictionary provides per-task synchronization tools/terminal_tool.py359-365
A background thread, _cleanup_thread_worker, periodically scans active environments to reap those that have exceeded their idle TTL tools/terminal_tool.py530-631
Key Behaviors:
ProcessRegistry reports active background tasks for a task_id, the environment is kept alive regardless of tool inactivity tools/terminal_tool.py536-544env.cleanup() is called outside the global lock to prevent slow container shutdowns from blocking the entire system tools/terminal_tool.py560-592_check_disk_usage_warning() and warns when thresholds are exceeded tools/terminal_tool.py123-149Sources: tools/terminal_tool.py123-149 tools/terminal_tool.py530-631 tools/process_registry.py142-151
| Backend | Class | Characteristics |
|---|---|---|
| Local | LocalEnvironment | Runs on host. Uses _run_bash for execution. Filters internal credentials via _sanitize_subprocess_env tools/environments/local.py148-173 Handles path translation between MSYS/Git Bash and Windows tools/environments/local.py24-108 |
| Docker | DockerEnvironment | Security-hardened with cap-drop ALL, no-new-privileges, and PID limits. Supports filesystem persistence via bind mounts. |
| Modal | ModalEnvironment | Cloud-based execution via native Modal Sandboxes. Supports filesystem snapshots and persistent storage. |
| SSH | SSHEnvironment | Remote execution via ControlMaster persistence. Uses hashed socket IDs to fit macOS path limits. |
| Singularity | SingularityEnvironment | Hardened Singularity/Apptainer containers with resource limits and optional writable overlays for persistence. |
| Daytona | DaytonaEnvironment | Cloud-based execution using the Daytona Python SDK. Supports persistent sandboxes that can be stopped and resumed. |
Sources: tools/environments/local.py24-173 tools/environments/base.py1-21
The ProcessRegistry tracks background processes spawned via terminal(background=true). These processes execute through the environment interface, ensuring they run inside the sandbox (Docker, SSH, etc.) rather than on the host machine tools/process_registry.py12-15
MAX_OUTPUT_CHARS tools/process_registry.py58WATCH_MIN_INTERVAL_SECONDS) and strike-based circuit breakers tools/process_registry.py63-70processes.json (CHECKPOINT_PATH) to allow recovering tracking of long-running tasks after a gateway restart tools/process_registry.py54-56host_start_time) to ensure a PID hasn't been recycled by the OS before attempting to poll or kill a process tools/process_registry.py102Sources: tools/process_registry.py1-139 tools/process_registry.py142-151
The execute_code tool allows the agent to write Python scripts that call other Hermes tools via an RPC mechanism. This collapses multi-step tool chains into a single inference turn tools/code_execution_tool.py3-6
_SECRET_SUBSTRINGS tools/code_execution_tool.py135-173SANDBOX_ALLOWED_TOOLS (e.g., web_search, read_file, terminal) are available inside the execute_code sandbox tools/code_execution_tool.py62-70Sources: tools/code_execution_tool.py1-77 tools/code_execution_tool.py135-173
The relationship between high-level tools and the environment abstraction is mediated by terminal_tool and the ProcessRegistry.
Sources: tools/terminal_tool.py25-32 tools/process_registry.py142-151 tools/environments/base.py187-200
Refresh this wiki
This wiki was recently refreshed. Please wait 3 days to refresh again.