2026-01-03 01:56:43 +00:00
---
2026-01-12 02:49:55 +00:00
summary: "Exec tool usage, stdin modes, and TTY support"
2026-01-03 01:56:43 +00:00
read_when:
2026-01-12 02:49:55 +00:00
- Using or modifying the exec tool
2026-01-03 01:56:43 +00:00
- Debugging stdin or TTY behavior
2026-01-31 16:04:03 -05:00
title: "Exec Tool"
2026-01-03 01:56:43 +00:00
---
2026-01-12 02:49:55 +00:00
# Exec tool
2026-01-03 01:56:43 +00:00
Run shell commands in the workspace. Supports foreground + background execution via `process` .
2026-01-12 02:49:55 +00:00
If `process` is disallowed, `exec` runs synchronously and ignores `yieldMs` /`background` .
2026-01-07 23:35:04 +01:00
Background sessions are scoped per agent; `process` only sees sessions from the same agent.
2026-01-03 01:56:43 +00:00
## Parameters
- `command` (required)
2026-01-18 04:27:33 +00:00
- `workdir` (defaults to cwd)
- `env` (key/value overrides)
2026-01-03 20:15:02 +00:00
- `yieldMs` (default 10000): auto-background after delay
2026-01-03 01:56:43 +00:00
- `background` (bool): background immediately
- `timeout` (seconds, default 1800): kill on expiry
2026-02-16 21:47:18 -05:00
- `pty` (bool): run in a pseudo-terminal when available (TTY-only CLIs, coding agents, terminal UIs)
2026-01-18 04:27:33 +00:00
- `host` (`sandbox | gateway | node` ): where to execute
- `security` (`deny | allowlist | full` ): enforcement mode for `gateway` /`node`
- `ask` (`off | on-miss | always` ): approval prompts for `gateway` /`node`
- `node` (string): node id/name for `host=node`
2026-01-24 21:12:46 +00:00
- `elevated` (bool): request elevated mode (gateway host); `security=full` is only forced when elevated resolves to `full`
2026-01-18 04:27:33 +00:00
Notes:
2026-01-31 21:13:13 +09:00
2026-01-18 04:27:33 +00:00
- `host` defaults to `sandbox` .
- `elevated` is ignored when sandboxing is off (exec already runs on the host).
2026-01-30 03:15:10 +01:00
- `gateway` /`node` approvals are controlled by `~/.openclaw/exec-approvals.json` .
2026-01-18 07:44:28 +00:00
- `node` requires a paired node (companion app or headless node host).
2026-01-18 04:27:33 +00:00
- If multiple nodes are available, set `exec.node` or `tools.exec.node` to select one.
2026-01-20 11:25:24 +00:00
- On non-Windows hosts, exec uses `SHELL` when set; if `SHELL` is `fish` , it prefers `bash` (or `sh` )
from `PATH` to avoid fish-incompatible scripts, then falls back to `SHELL` if neither exists.
2026-02-01 15:35:48 -08:00
- Host execution (`gateway` /`node` ) rejects `env.PATH` and loader overrides (`LD_*` /`DYLD_*` ) to
prevent binary hijacking or injected code.
2026-01-26 21:37:52 +00:00
- Important: sandboxing is **off by default ** . If sandboxing is off, `host=sandbox` runs directly on
the gateway host (no container) and **does not require approvals ** . To require approvals, run with
`host=gateway` and configure exec approvals (or enable sandboxing).
2026-01-03 01:56:43 +00:00
2026-01-17 05:43:27 +00:00
## Config
- `tools.exec.notifyOnExit` (default: true): when true, backgrounded exec sessions enqueue a system event and request a heartbeat on exit.
2026-01-22 00:49:02 +00:00
- `tools.exec.approvalRunningNoticeMs` (default: 10000): emit a single “running” notice when an approval-gated exec runs longer than this (0 disables).
2026-01-18 04:27:33 +00:00
- `tools.exec.host` (default: `sandbox` )
2026-01-21 03:40:21 +00:00
- `tools.exec.security` (default: `deny` for sandbox, `allowlist` for gateway + node when unset)
2026-01-18 04:27:33 +00:00
- `tools.exec.ask` (default: `on-miss` )
- `tools.exec.node` (default: unset)
2026-02-14 20:44:25 +01:00
- `tools.exec.pathPrepend` : list of directories to prepend to `PATH` for exec runs (gateway + sandbox only).
2026-01-21 21:44:28 +00:00
- `tools.exec.safeBins` : stdin-only safe binaries that can run without explicit allowlist entries.
2026-01-19 00:35:39 +00:00
Example:
2026-01-31 21:13:13 +09:00
2026-01-19 00:35:39 +00:00
```json5
{
tools: {
exec: {
2026-01-31 21:13:13 +09:00
pathPrepend: ["~/bin", "/opt/oss/bin"],
},
},
2026-01-19 00:35:39 +00:00
}
```
### PATH handling
2026-02-01 15:35:48 -08:00
- `host=gateway` : merges your login-shell `PATH` into the exec environment. `env.PATH` overrides are
rejected for host execution. The daemon itself still runs with a minimal `PATH` :
2026-01-19 00:35:39 +00:00
- macOS: `/opt/homebrew/bin` , `/usr/local/bin` , `/usr/bin` , `/bin`
- Linux: `/usr/local/bin` , `/usr/bin` , `/bin`
- `host=sandbox` : runs `sh -lc` (login shell) inside the container, so `/etc/profile` may reset `PATH` .
2026-01-30 03:15:10 +01:00
OpenClaw prepends `env.PATH` after profile sourcing via an internal env var (no shell interpolation);
2026-01-27 03:33:09 +00:00
`tools.exec.pathPrepend` applies here too.
2026-02-01 15:35:48 -08:00
- `host=node` : only non-blocked env overrides you pass are sent to the node. `env.PATH` overrides are
2026-02-14 20:14:34 +01:00
rejected for host execution and ignored by node hosts. If you need additional PATH entries on a node,
configure the node host service environment (systemd/launchd) or install tools in standard locations.
2026-01-17 05:43:27 +00:00
2026-01-18 08:15:12 +00:00
Per-agent node binding (use the agent list index in config):
```bash
2026-01-30 03:15:10 +01:00
openclaw config get agents.list
openclaw config set agents.list[0].tools.exec.node "node-id-or-name"
2026-01-18 08:15:12 +00:00
```
2026-01-18 08:26:28 +00:00
Control UI: the Nodes tab includes a small “Exec node binding” panel for the same settings.
2026-01-18 06:11:38 +00:00
## Session overrides (`/exec`)
Use `/exec` to set **per-session ** defaults for `host` , `security` , `ask` , and `node` .
Send `/exec` with no arguments to show the current values.
Example:
2026-01-31 21:13:13 +09:00
2026-01-18 06:11:38 +00:00
```
/exec host=gateway security=allowlist ask=on-miss node=mac-1
```
2026-01-26 22:18:36 +00:00
## Authorization model
`/exec` is only honored for **authorized senders ** (channel allowlists/pairing plus `commands.useAccessGroups` ).
It updates **session state only ** and does not write config. To hard-disable exec, deny it via tool
policy (`tools.deny: ["exec"]` or per-agent). Host approvals still apply unless you explicitly set
`security=full` and `ask=off` .
2026-01-18 07:44:28 +00:00
## Exec approvals (companion app / node host)
2026-01-18 01:33:52 +00:00
2026-01-18 04:27:33 +00:00
Sandboxed agents can require per-request approval before `exec` runs on the gateway or node host.
2026-01-18 01:33:52 +00:00
See [Exec approvals ](/tools/exec-approvals ) for the policy, allowlist, and UI flow.
2026-01-22 00:49:02 +00:00
When approvals are required, the exec tool returns immediately with
`status: "approval-pending"` and an approval id. Once approved (or denied / timed out),
the Gateway emits system events (`Exec finished` / `Exec denied` ). If the command is still
running after `tools.exec.approvalRunningNoticeMs` , a single `Exec running` notice is emitted.
2026-01-21 21:44:28 +00:00
## Allowlist + safe bins
Allowlist enforcement matches **resolved binary paths only ** (no basename matches). When
`security=allowlist` , shell commands are auto-allowed only if every pipeline segment is
allowlisted or a safe bin. Chaining (`;` , `&&` , `||` ) and redirections are rejected in
2026-02-14 19:42:52 +01:00
allowlist mode unless every top-level segment satisfies the allowlist (including safe bins).
Redirections remain unsupported.
2026-01-21 21:44:28 +00:00
2026-01-03 01:56:43 +00:00
## Examples
Foreground:
2026-01-31 21:13:13 +09:00
2026-01-03 01:56:43 +00:00
```json
2026-01-31 21:13:13 +09:00
{ "tool": "exec", "command": "ls -la" }
2026-01-03 01:56:43 +00:00
```
Background + poll:
2026-01-31 21:13:13 +09:00
2026-01-03 01:56:43 +00:00
```json
2026-01-12 02:49:55 +00:00
{"tool":"exec","command":"npm run build","yieldMs":1000}
2026-01-03 01:56:43 +00:00
{"tool":"process","action":"poll","sessionId":"<id>"}
```
2026-01-12 03:42:49 +00:00
2026-01-17 06:12:25 +00:00
Send keys (tmux-style):
2026-01-31 21:13:13 +09:00
2026-01-17 06:12:25 +00:00
```json
{"tool":"process","action":"send-keys","sessionId":"<id>","keys":["Enter"]}
{"tool":"process","action":"send-keys","sessionId":"<id>","keys":["C-c"]}
{"tool":"process","action":"send-keys","sessionId":"<id>","keys":["Up","Up","Enter"]}
```
2026-01-17 06:38:47 +00:00
Submit (send CR only):
2026-01-31 21:13:13 +09:00
2026-01-17 06:38:47 +00:00
```json
2026-01-31 21:13:13 +09:00
{ "tool": "process", "action": "submit", "sessionId": "<id>" }
2026-01-17 06:38:47 +00:00
```
2026-01-17 06:12:25 +00:00
Paste (bracketed by default):
2026-01-31 21:13:13 +09:00
2026-01-17 06:12:25 +00:00
```json
2026-01-31 21:13:13 +09:00
{ "tool": "process", "action": "paste", "sessionId": "<id>", "text": "line1\nline2\n" }
2026-01-17 06:12:25 +00:00
```
2026-01-12 03:42:49 +00:00
## apply_patch (experimental)
`apply_patch` is a subtool of `exec` for structured multi-file edits.
Enable it explicitly:
```json5
{
tools: {
exec: {
2026-02-14 23:50:04 +01:00
applyPatch: { enabled: true, workspaceOnly: true, allowModels: ["gpt-5.2"] },
2026-01-31 21:13:13 +09:00
},
},
2026-01-12 03:42:49 +00:00
}
```
Notes:
2026-01-31 21:13:13 +09:00
2026-01-12 03:42:49 +00:00
- Only available for OpenAI/OpenAI Codex models.
- Tool policy still applies; `allow: ["exec"]` implicitly allows `apply_patch` .
2026-01-17 05:43:27 +00:00
- Config lives under `tools.exec.applyPatch` .
2026-02-15 01:21:07 +01:00
- `tools.exec.applyPatch.workspaceOnly` defaults to `true` (workspace-contained). Set it to `false` only if you intentionally want `apply_patch` to write/delete outside the workspace directory.