A Hermes terminal backend selects where terminal-tool work and its associated file and code operations run. It does not move every Hermes process or Python dependency into that environment. The effective backend may be your Mac or Linux host, a Docker sandbox, an SSH server, Modal, Daytona, or a Singularity/Apptainer environment. Choosing the wrong one can make a healthy agent look broken because it sees the wrong files, network, credentials, or runtime.
This guide owns one job: choose the right Hermes terminal backend, prove which backend is active, and diagnose cases where Hermes appears to use Docker even though config.yaml says local.
Quick answer#
Use local for trusted work on the machine where Hermes runs, docker when commands need a disposable boundary, ssh when the code or service lives on another server, and a cloud/HPC backend only when the workload genuinely needs it. Set the backend with hermes config set terminal.backend local, start a new session, and verify the effective runtime with a harmless command such as pwd plus uname -a. If hermes config get terminal.backend says local but tools still enter Docker, update Hermes, inspect TERMINAL_ENV in every environment source used by the running gateway, and fully reload the long-running process.
The backend is a security and data boundary, not a cosmetic preference. Before changing it, back up durable state with the Hermes backup guide, confirm the active profile, and keep secrets in the profile environment rather than copying them into prompts. For an always-on server, pair this guide with VPS deployment, Docker Compose setup, and gateway troubleshooting. If maintaining that stack is not the job you want, compare the managed path on FlyHermes pricing.
The six backend choices#
Local#
local runs commands directly on the Hermes host. It is the fastest choice for a trusted personal machine and the easiest way to work on an existing local repository. It also has the broadest blast radius: the agent can touch files and commands available to the Hermes user. Use OS permissions, a dedicated profile, tool approvals, and a clean Git worktree when the task is risky.
hermes config set terminal.backend local
hermes config get terminal.backend
Docker#
docker runs tool work in a container boundary. Choose it for dependency isolation, disposable builds, or tasks that should not run directly on the host. Docker must be installed and reachable by the user that actually runs Hermes. A gateway service account without Docker socket access will fail even when Docker works in your interactive shell. Continue with the Docker terminal backend guide and the Docker troubleshooting checklist.
SSH#
ssh sends tool execution to a remote machine. It is useful when the repository, GPU, database, or deployment runtime lives elsewhere. Verify host-key trust, least-privilege credentials, remote working directory, and non-interactive PATH before giving the agent a real task. Use the SSH terminal backend setup for the exact connection checklist.
Modal and Daytona#
Modal and Daytona are remote execution backends for workloads that benefit from disposable cloud compute or managed workspaces. They add provider authentication, remote lifecycle, network, and persistence boundaries. Do not choose them merely because they sound more scalable; use them when a local or SSH runtime cannot satisfy the workload. See the Modal setup guide or Daytona setup guide.
Singularity / Apptainer#
Singularity is the HPC-oriented option for environments where Docker is unavailable or inappropriate. It is useful on research clusters with scheduler, image, mount, and GPU policies. Follow the Singularity backend guide and verify the exact cluster rules before enabling unattended jobs.
Docker vs Podman vs a jail: what Hermes actually supports#
These names describe different layers, so do not treat them as interchangeable settings:
- Docker terminal backend: a documented Hermes backend. Hermes stays on the host while terminal, file, and code-execution work runs in a persistent or ephemeral container.
- Whole-agent Docker: the Hermes process, gateway, and optional Dashboard run in the official container. This is a deployment choice, not
terminal.backend: docker. Use the Docker vs native installation guide before choosing it. - Podman: a container engine with a Docker-compatible command/API surface, but it is not a separate
terminal.backendvalue. Do not setterminal.backend: podman. Treat Podman as an advanced compatibility path only after proving the exact Hermes image, socket, mounts, networking, persistence, and restart behavior on your host. - OS jail or sandbox: FreeBSD jail, macOS sandboxing, systemd hardening, and similar controls constrain the host process. They are not Hermes terminal backends. If you build one, it is an operator-owned security layer around
local, not a supported config shortcut. - Singularity/Apptainer: the documented HPC-oriented backend for clusters where Docker is unavailable or forbidden. It is not a general Podman replacement.
Which one should you choose?#
Use Docker when you want the supported container boundary with the least ambiguity. Use Podman only when an organizational or rootless-container requirement justifies owning compatibility testing. Use an OS-level jail only when your platform team already operates that control and can prove filesystem, process, network, and secret boundaries. If the real goal is simply a 24/7 agent without container, gateway, update, and backup ownership, compare the managed FlyHermes path instead of adding another runtime layer.
Podman compatibility acceptance test#
Before unattended use, require all of these checks to pass from the same user and service process that runs Hermes:
- The Docker-compatible client and socket are reachable without interactive shell setup.
- The configured image starts and reports the expected architecture, Python, Node, and working directory.
- Required project mounts are present; host secrets and unrelated home directories are absent.
- Container networking reaches only the services the job needs, including any host alias used for local APIs.
- Persistent mode survives a Hermes/gateway restart; ephemeral mode actually removes prior task state.
- Memory/CPU limits and termination behavior work under a deliberately bounded test.
- A harmless CLI turn and a turn sent through the real gateway produce the same backend evidence.
If any check fails, return to the supported Docker backend or use local with explicit host controls. Do not advertise a Podman experiment as equivalent to the documented Docker path merely because one podman run command succeeded.
Decision checklist#
Choose the narrowest backend that can complete the job:
- Need the current machine and repository? Use local.
- Need dependency isolation or a disposable build? Use Docker.
- Need an existing remote server or GPU box? Use SSH.
- Need temporary managed cloud compute? Evaluate Modal or Daytona.
- Need an HPC-compatible container runtime? Use Singularity/Apptainer.
- Need a 24/7 agent but do not want to operate servers, providers, gateways, and dashboard security? Compare self-hosted vs hosted Hermes.
Verify the effective backend#
Do not stop at the value written in config.yaml. Prove the complete path used by the active profile and process.
hermes config path
hermes config get terminal.backend
hermes doctor
hermes chat -q 'Run pwd and uname -a, then report the execution environment.'
Check five facts in the result: active profile, working directory, operating system, expected files, and expected network/runtime access. Then test one representative operation such as reading a repository file or running its smallest test. A successful config write does not prove that an old gateway process, another profile, or an environment override is not still selecting a different backend.
Why Hermes can appear stuck on Docker#
A fresh August 2026 Discord support case captured the confusing symptom precisely: hermes config get terminal.backend returned local, but terminal, execute_code, and file operations later behaved as Docker-bound. The final diagnosis was not memory injection and not an agent secretly changing infrastructure. A stale TERMINAL_ENV value was entering the long-running gateway environment during reload. The gateway reload path was fixed upstream, but the case provides a durable troubleshooting order.
- Update first. Run
hermes update, then start a new session on the updated process. - Confirm the active profile and config path. A correct value in one profile does not control another profile.
- Read the configured value. Run
hermes config get terminal.backend. - Look for environment overrides. Check the profile
.env, machine-managed environment files, the service definition, and the live process environment forTERMINAL_ENV. Do not print unrelated secrets. - Remove duplicate sources. Prefer
terminal.backendinconfig.yamlas the single user-level source unless an environment override is intentionally required. - Reload the long-running runtime. CLI sessions, dashboard/backend processes, and messaging gateways can retain old in-memory configuration.
- Run an end-to-end proof from the same channel and profile that failed. A local shell test does not prove a Matrix, Telegram, Discord, or Desktop-backed turn uses the same environment.
- Capture diagnostics before changing more variables. On current Hermes,
hermes debug share --nouscan provide a redacted diagnostics report for support.
Do not let the agent diagnose its own backend from conversational memory alone. The effective config, process environment, and real tool output are the evidence.
Local shell vs gateway service: prove both#
A common trap is testing only the interactive shell. A user service can inherit a different PATH, home directory, profile, Docker socket permission, or environment than the shell where hermes config get was run. Test the runtime from the same entry point that failed:
- CLI failure: start a new CLI session and run the proof command.
- Telegram, Discord, Matrix, or Slack failure: send the proof task through that channel after the gateway reload.
- Dashboard/Desktop failure: reconnect to the intended backend and verify the active profile before testing.
- Scheduled job failure: inspect the job's profile, provider/model pinning, last status, and delivery result as well as the terminal backend.
For Linux user services, compare the service definition and live process environment without dumping the whole environment. Filter specifically for TERMINAL_, Hermes home/profile, PATH, and the service command. Credentials should remain redacted.
A cron dependency error may be outside the terminal backend#
A package installed inside the task's Docker sandbox does not become available to the Python process running the gateway. The same applies to an SSH backend: a successful import on the remote host tells you nothing about packages on the scheduler host.
For the managed systemd path, current cron documentation says the external worker uses the gateway's interpreter and checkout. Separate that startup stage from a tool command executed later:
- If the worker exits before acknowledging ownership and stderr names an import error, inspect the gateway interpreter and dependency selection. The terminal sandbox may never have started.
- If the agent starts but a terminal command cannot import a project dependency, inspect the interpreter inside the selected terminal backend and its project environment.
- If both run but the expected file is absent, compare the actual working directory and mounts. Reinstalling Python packages cannot expose an unmounted host directory.
Record the interpreter path and package origin on the failing side before making changes. The cron startup diagnostic includes a small probe that reports those paths without dumping credentials. Avoid a generic pip install repair until you know which interpreter would receive it.
PM-managed Hermes dependencies, project dependencies and a container image have different owners. Follow the package-management diagnostics for the application runtime; use the project's declared environment for its own code. After changing a managed Python generation, restart the affected Hermes process before testing again. Keep the Docker sandbox enabled if its isolation is required: switching to local merely to hide a dependency error changes the security boundary.
Backend failure matrix#
Config says local, tools use Docker#
Update Hermes, remove unintended TERMINAL_ENV overrides, reload the actual long-running process, start a new session, and test from the original channel/profile. If it persists, capture a redacted diagnostics report before editing more files.
Docker exits before any command runs#
Confirm the effective backend is really Docker. Then verify Docker is installed, the daemon is healthy, and the Hermes user can access it. If Docker was never intended, set terminal.backend to local instead of trying to repair an unnecessary container dependency.
SSH works manually but Hermes cannot connect#
Check the non-interactive user, key path, host key, remote PATH, working directory, and whether the profile running Hermes can read the credential. A successful connection from another shell or user does not prove the Hermes process can connect.
Commands run but files are missing#
Print pwd, list the expected project root, and identify the backend before modifying mount or path config. In Docker, confirm the host path is mounted. In SSH/cloud backends, confirm the repository exists on the remote runtime.
Backend changed after an update or setup wizard#
Run hermes config get terminal.backend, inspect the config path for the active profile, and check environment overrides. Do not infer backend state from old chat history or memory. Tool/config changes may require a new session; long-running gateway or dashboard processes require a full reload.
Safe first task after switching#
Use a read-only proof before package installs or writes:
Report the current working directory, operating system, active user, and whether the expected project directory exists. Do not change files or install anything.
Then run one tiny project-specific command, such as a version check or the smallest unit test. Only after both checks pass should you allow broad package installs, deployment commands, or scheduled execution.
Self-hosted ownership vs managed outcome#
Terminal backends are one of the real operating costs of self-hosting. A local machine can sleep, Docker needs images and permissions, SSH needs credential and host maintenance, and cloud/HPC backends need provider-specific lifecycle controls. The Hermes cost calculator helps count those costs. Self-host when that control is valuable; choose FlyHermes when browser/mobile access and managed uptime matter more than owning each execution boundary.
Recommended next steps#
- Install or repair the base runtime with the Hermes Agent installation guide.
- Configure a disposable sandbox with the Docker backend guide.
- Operate a remote machine with the SSH backend guide.
- Secure an always-on host with the Hermes server hardening guide.
- Verify bot/platform symptoms with gateway troubleshooting.
- Compare the managed route on FlyHermes pricing.
Update failures can be backend failures#
When a Hermes update appears to break terminal tools, verify whether the selected backend is local, Docker, SSH, or Modal before blaming the model. Recent Docker-image and install/update threads show this exact confusion. Pair this guide with Hermes update command hangs, Docker install, and security hardening so backend changes are deliberate.
The browser and terminal can fail in different namespaces#
A local, Docker, or SSH terminal backend does not automatically place Chrome in the same network namespace. Record where Hermes, the browser daemon, and the CDP endpoint run, then test from that boundary. The Hermes browser automation troubleshooting guide explains stale ports, localhost mistakes, named-session isolation, and safe recovery.
Do not confuse the Docker backend with Docker installation#
The Docker terminal backend keeps Hermes and its gateways on the host while execution runs in a sandbox. Running the whole application in the official image is a separate architecture. The Docker vs native installation guide shows when each boundary is the better choice.