Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Terminal

8.1. Terminal — Executing Shell Commands

Seven backends to choose from

Local, Docker, SSH, Singularity, Modal, Daytona, and Vercel Sandbox. Daytona and Modal have “serverless persistence” — the environment sleeps when idle and wakes on demand, costing almost nothing between uses.

terminal:
  backend: docker

Whether shell state persists — depends on the backend

With Local and SSH, persistent_shell: true (the default) keeps a single bash process alive across many commands — cd, environment variables, and aliases all survive between calls. Docker works very differently: Hermes starts one long-lived container (docker run -d ... sleep infinity), and every terminal/file/execute_code command is routed through docker exec into that same container — a package pip installed once is still there on the next call, and a directory you cded into is preserved across /new, /reset, and even sub-agents spawned from delegate_task.

Two background-running modes

process(action="wait")   # wait for a background command to finish
process(action="poll")   # check progress without blocking

For interactive CLI tools that need a pseudo-terminal (Python REPL, Claude Code…), use pty=true.

Notes

  • For untrusted content (unknown repos, unverified MCP servers), always switch to the Docker/Daytona backend — the container then becomes the security boundary, and since the dangerous-command checks in chapter 6.3 are bypassed, the container must genuinely be well isolated.
  • PTY mode has \r vs \n issues with apps built on prompt_toolkit — prefer tmux for spawning interactive processes rather than using a direct PTY.
  • The Docker backend does not mount the host’s current working directory into the container by default — you must opt in explicitly via docker_volumes if you want the agent to work directly on host files.