Share feedback
Answers are generated based on the documentation.

Shell Tool

Execute arbitrary shell commands in the user's environment.

Overview

The shell tool allows agents to execute arbitrary shell commands synchronously. This is one of the most powerful tools — it lets agents run builds, install dependencies, query APIs, and interact with the system. Each call runs in a fresh, isolated shell session — no state persists between calls.

Commands have a default 30-second timeout and require user confirmation unless --yolo is used. For servers, watchers, and other long-running commands, add the background_jobs toolset alongside shell.

Shell interpreter detection

The shell tool automatically detects and names the resolved shell interpreter (e.g., bash, zsh, powershell, pwsh, cmd) in its description to the model, along with the operating system (Linux, macOS, Windows). This helps models use the correct shell syntax for the host environment.

For example:

  • On Linux with bash: "Executes the given shell command with bash on Linux."
  • On Windows with PowerShell: "Executes the given shell command with powershell on Windows. Use Windows PowerShell 5.1 syntax: chain commands with ";" (not "&&"), and avoid POSIX commands/flags like "ls -la"."

This reduces wasted turns where models assume POSIX syntax on Windows or vice versa.

Configuration

toolsets:
  - type: shell

Options

PropertyTypeDescription
envobjectEnvironment variables to set for all shell commands
saferbooleanDeprecated and ignored — shell commands are always classified now (see Command classification). Kept so existing YAMLs still parse.
sudo_askpassbooleanOpt in to prompting for a sudo password (see Sudo support). Default false.

Custom Environment Variables

toolsets:
  - type: shell
    env:
      MY_VAR: "value"
      PATH: "${env.PATH}:/custom/bin"

Command classification

Every shell command is classified against an embedded taxonomy before the approval decision — no opt-in required:

  • Destructive matches (rm -rf <path>, docker volume rm, mkfs, dd if=… of=/dev/<disk>, …) are labelled destructive with a blast_radius (low / medium / high) and a category tag. The TUI confirmation dialog renders the blast radius with a color badge.
  • Known-safe reads (ls, cat, git status, git diff, docker ps, docker logs, kubectl get, …) are labelled safe.
  • Everything else is labelled unknown.

The session's safety mode decides what each label means: strict asks about everything, balanced auto-runs safe commands and asks about destructive/unknown ones, autonomous runs everything. Custom permission rules always win over the mode.

Compound shell (a && b, a; b, a | b) is never matched against the safe allowlist; any destructive segment falls through to ask. The full taxonomy lives in pkg/safety/safety_patterns.json.

See examples/safety_modes.yaml for a full example. The legacy safer: true toolset flag is deprecated and ignored.

Sudo support

By default a shell command has no controlling terminal, so a sudo command that needs a password hangs until it times out (the agent usually gives up and falls back to printing manual instructions).

Set sudo_askpass: true to enable a sudo privilege escalation flow:

toolsets:
  - type: shell
    sudo_askpass: true

When enabled, sudo commands prompt you for your password through the host UI (the input is masked). The password is handed to sudo over a private, per-session socket via the standard SUDO_ASKPASS mechanism — it is never written to the command line, the logs, or stored by the agent.

The bridge environment variables (SUDO_ASKPASS, CAGENT_ASKPASS_SOCKET, CAGENT_ASKPASS_TOKEN) are added only to commands that invoke sudo, but within such a command they are visible to every child process, not just sudo. They carry a socket path and a session token, not the password; the socket lives in a 0700 directory, so only your own user can reach it.

Notes and limitations:

  • Unix only. The flag has no effect on Windows.
  • Interactive UI only. In headless / non-interactive runs the prompt is declined automatically and sudo fails as before.
  • Only a bare sudo ... invocation in a POSIX shell (sh, bash, zsh, ...) is handled. sudo called by absolute path (/usr/bin/sudo), via env sudo, from inside a nested script, or under a non-POSIX shell (e.g. fish) is not intercepted and behaves as before.
  • Caching is sudo's own. Because each shell tool call runs in a fresh shell with no controlling terminal, sudo's credential cache does not persist across separate tool calls: you are prompted once per shell command that uses sudo. Within a single command, multiple sudo calls (e.g. sudo a && sudo b) usually share one prompt, subject to sudo's own timestamp configuration.
  • The prompt must be answered within the command's timeout; raise the timeout parameter for sudo commands that may wait on input.
  • Prompts are serialized: if a single command runs two sudo calls in parallel (e.g. sudo a & sudo b), the second waits for the first prompt to be answered rather than opening two dialogs at once.

Available Tools

The shell toolset exposes one tool:

Tool NameDescription
shellRun a command synchronously and return its combined output when it finishes.

shell parameters

ParameterTypeRequiredDescription
cmdstringThe shell command to execute.
cwdstringWorking directory to run the command in (default: .).
timeoutintegerPer-call execution timeout in seconds (default: 30).
Warning

Safety

The shell tool gives agents full access to the system shell. Always set max_iterations on agents that use the shell tool to prevent infinite loops. A value of 20–50 is typical for development agents. Use Sandbox Mode for additional isolation.

Note

Tool Confirmation

By default, Docker Agent asks for user confirmation before executing shell commands. Use --yolo to auto-approve all tool calls.