This document describes RunCommandTool (agent tool for executing shell commands) and how safe mode works via Bubblewrap (bwrap) on Linux. Unsafe mode uses the OS subprocess directly and works on all platforms.
RunCommandTool runs shell commands (e.g. ls -la, python script.py). Two modes:
- Safe (default): The command runs inside Bubblewrap (bwrap) sandbox: minimal filesystem view (read-only /usr, workspace bind), namespaces, no network by default. Linux only; requires
bwrapto be installed. Ifbwrapis not found, the tool returns an error with an installation link. - Unsafe: The command runs via the OS (asyncio subprocess). You can set workspace_path so the process uses that directory as cwd and path-like arguments cannot escape outside it. Works on Windows, macOS, Linux.
So: safe (default) = bwrap isolation (Linux); unsafe = OS subprocess (all platforms).
- Config: In the global
tools:section or per-agent:workspace_path(required when the tool is used),mode("safe"or"unsafe"),timeout_seconds,include_paths(optional list of allowed commands/paths),exclude_paths(optional list of forbidden commands/paths). Default mode is safe. If RunCommandTool is used anywhere (global or in any agent) andworkspace_pathis not set for the effective config, the application logs an error and exits at startup (exit code 1). - LLM: The agent passes a
commandstring (andreasoning) to the tool. - Validation: If
include_pathsorexclude_pathsare set, the tool checks that the command executable and paths in arguments are allowed. Commands are matched by name (e.g."ls") or resolved path (e.g./usr/bin/ls). include_paths has priority over exclude_paths: if a path is in both, it is allowed. - Unsafe: The tool resolves
workspace_path(if set), validates path-like tokens, then runssh -c "<command>"withcwd=workspace_pathand a timeout. Returns formatted stdout, stderr, return code. - Safe: The tool checks that
bwrapis available (e.g.which bwrap). If not, returns an error with link to Bubblewrap installation. If available:- If
include_pathsorexclude_pathsare set in the tool configuration, OverlayFS mounts are created at server startup (not per-command):- Server checks global
tools:and each agent'stoolslist; if RunCommandTool is used anywhere withmode: "safe"andinclude_paths/exclude_pathsset, OverlayFSManager creates overlay filesystems:- Creates temporary directories for overlay layers (lowerdir, upperdir, workdir)
- Mounts original directories as lower layer (read-only)
- Creates whiteout files in upper layer for excluded binaries
- Mounts overlay filesystems and stores mount paths
- These mounts are reused for all command executions during server lifetime
- Server checks global
- At runtime, the tool uses pre-initialized OverlayFS mounts from OverlayFSManager
- This restricts which binaries are available inside the sandbox at the filesystem level, including commands executed by scripts
- If neither
include_pathsnorexclude_pathsare set, uses default mounts (read-only/usr, etc.) - On server shutdown, all OverlayFS mounts are automatically unmounted and temporary directories cleaned up
- Runs the command via
bwrapwith the configured mounts and a timeout. Returns formatted stdout, stderr, return code.
- If
Safe mode uses a minimal but useful bwrap setup so the sandbox works out of the box:
- Default filesystem (when
include_pathsis not set): Read-only bind of/usr; symlinks for/bin,/lib,/lib64;--proc /proc,--dev /dev; a writable workspace directory bound as/workspace(fromworkspace_pathif set, else a temporary directory or current working directory). - Restricted filesystem (when
include_pathsorexclude_pathsare set): Uses OverlayFS to create a filtered view of the filesystem:- Initialization: OverlayFS is initialized once at server startup if RunCommandTool is used with
mode: "safe"anywhere (globaltools:or any agent'stools). Paths (include_paths/exclude_paths) may be unset; then no overlay mounts are created but the manager is ready. If paths are set, overlay mounts are created for those directories. - Lower layer: Original directories (e.g.,
/usr/bin) mounted read-only - Upper layer: Temporary directory containing whiteout files for exclude_paths
- Merged layer: OverlayFS mount combining lower and upper layers, hiding excluded files
- For example, if
include_paths: ["ls", "cat"]andexclude_paths: ["rm"], and all are in/usr/bin:- Lower layer:
/usr/bin(read-only, contains all binaries) - Upper layer: Contains whiteout file
.wh.rmto hiderm - Merged:
/usr/binoverlay showinglsandcatbut notrm
- Lower layer:
- The overlay is mounted in bwrap at the original location
- Essential system directories (
/lib,/usr/lib,/lib64,/usr/lib64) are always mounted for shared library dependencies - Reuse: Same overlay mounts are reused for all command executions during server lifetime (no per-command overhead)
- Cleanup: On server shutdown, all OverlayFS mounts are automatically unmounted and temporary directories removed
- This ensures that commands executed inside scripts (e.g.
bash script.shcallingrm) are also restricted: ifrmis hidden by whiteout, it won't be available in the sandbox
- Initialization: OverlayFS is initialized once at server startup if RunCommandTool is used with
- Execution: Process runs with
--chdir /workspace,--unshare-all,--die-with-parent; command is run as/bin/sh -c "<command>". - Timeout: Enforced by the tool (subprocess timeout) after
timeout_seconds.
This gives isolation (namespaces, limited filesystem) without extra configuration. When include_paths/exclude_paths are used, the sandbox uses OverlayFS to restrict binaries at the filesystem level, so scripts cannot execute forbidden commands even if they try.
How OverlayFS works:
- Lower layer (read-only): Contains the original filesystem (e.g.,
/usr/binwith all binaries) - Upper layer (writable): Contains whiteout files (
.wh.<filename>) that hide files from the lower layer - Work directory: Temporary directory used by OverlayFS for atomic operations
- Merged mount: The combined view where excluded files are hidden
Whiteout files:
- Format: Character device with major/minor number 0/0, or regular file named
.wh.<original_filename> - When OverlayFS encounters a whiteout, it hides the corresponding file from the lower layer
- This allows excluding specific files from a directory without excluding the entire directory
Lifecycle Management:
- Server startup: OverlayFS is initialized by
OverlayFSManagerduring FastAPIlifespanstartup phase - Configuration: RunCommandTool config is taken from global
tools:or from any agent (first candidate withmode: "safe"wins). If everywhere ismode: "unsafe", overlay is not initialized. If any config (global or any agent) hasmode: "safe", overlay is initialized (include_paths/exclude_paths may be unset; then 0 mounts). - Initialization: Whenever at least one safe config exists (global or per-agent)
- Runtime: Pre-initialized mounts are reused for all command executions (no per-command overhead)
- Server shutdown: All OverlayFS mounts are automatically unmounted and temporary directories cleaned up during FastAPI
lifespanshutdown phase
Advantages:
- Native kernel mechanism (no SUID required)
- Fine-grained file exclusion within directories
- Works seamlessly with bwrap
- Efficient: mounts created once at startup, reused for all commands
- Automatic cleanup on server shutdown
All parameters are optional. Set in the global tools: section or per-agent.
| Parameter | Type | Default | Description |
|---|---|---|---|
workspace_path |
str | None | Directory for cwd (unsafe) or bwrap workspace (safe). In safe mode, this directory is bound as /workspace inside the sandbox. Required when RunCommandTool is used: if not set, the application exits at startup with an error. |
mode |
str | "safe" |
"safe" or "unsafe". Safe uses bwrap (Linux only); unsafe uses local subprocess. |
timeout_seconds |
int | 60 | Max execution time in seconds. |
include_paths |
list[str] | None | Allowed commands/paths. If set, only commands in this list can be executed. Commands are matched by name (e.g. "ls") or full path (e.g. "/usr/bin/ls"). Paths in command arguments are also checked. Has priority over exclude_paths (same path in both is allowed). |
exclude_paths |
list[str] | None | Excluded commands/paths. If set, these are forbidden unless also in include_paths. |
Tool parameters (from the LLM / schema): reasoning (str), command (str, full command line).
Example (unsafe):
tools:
run_command_tool:
workspace_path: "/tmp/agent_workspace"
mode: "unsafe"
timeout_seconds: 120Example (safe, Linux with bwrap installed):
tools:
run_command_tool:
workspace_path: "/tmp/agent_workspace"
mode: "safe"
timeout_seconds: 60Example (with include_paths/exclude_paths - restrict allowed commands):
tools:
run_command_tool:
workspace_path: "/tmp/agent_workspace"
mode: "unsafe"
timeout_seconds: 60
include_paths:
- "ls"
- "cat"
- "/usr/bin/python3"
- "/tmp/agent_workspace" # Allow access to workspace directory
exclude_paths:
- "rm"
- "/usr/bin/rm"Safe mode requires bwrap on the system. If it is not installed, the tool returns an error message with a link to installation instructions.
- Installation: See Bubblewrap - Installation. On Debian/Ubuntu:
apt install bubblewrap. On Fedora:dnf install bubblewrap. On Arch:pacman -S bubblewrap. - Docker: When using the project Docker image, bubblewrap is installed via
aptin the image so safe mode works without extra steps.
Unsafe mode uses the OS subprocess and optional workspace_path; works on all platforms. Use when you only need a directory boundary or when bwrap is not available (e.g. Windows, macOS).
bubblewrap is a lightweight unprivileged sandbox using Linux namespaces and bind mounts. It is used by Flatpak and others. Safe mode combines bwrap with OverlayFS to provide fine-grained filesystem control:
- bwrap provides namespace isolation (PID, UTS, IPC, NET, MNT, USER, CGROUP, TIME)
- OverlayFS provides file-level exclusion through whiteout files
- This combination allows mounting directories while excluding specific files, without requiring SUID binaries
Safe mode builds a minimal environment so that commands run in isolation with a single writable workspace and filtered binary access.
- Unsafe: Runs as the same user as the agent. Path validation limits access to
workspace_path; use timeout to avoid hanging. - Safe: Uses bwrap for namespace and filesystem isolation. The sandbox is not a full security boundary; use as a mitigation layer. Ensure
workspace_pathpoints to a dedicated workspace, not a sensitive directory.
| Item | Description |
|---|---|
| RunCommandTool | Runs shell commands; unsafe = OS subprocess (all platforms); safe = bwrap sandbox (Linux, requires bwrap). |
| bwrap | Must be installed for safe mode. Install: Bubblewrap - Installation. |
| Minimal defaults | Safe mode uses a minimal bwrap setup: ro-bind /usr, workspace as /workspace, unshare-all, timeout. |
| OverlayFS | When include_paths/exclude_paths are set, uses OverlayFS with whiteout files to exclude specific binaries from directories. |