From 39bcb45ca145c1a07617a5218397025a7ce01bec Mon Sep 17 00:00:00 2001 From: "openclaw-docs-sync[bot]" Date: Thu, 23 Apr 2026 17:11:45 +0000 Subject: [PATCH] chore(sync): mirror docs from openclaw/openclaw@4792a50710aab6d0f30d7478967ef185892baf43 --- .openclaw-sync/source.json | 4 +- docs/gateway/protocol.md | 294 +++++++++++++---------------------- docs/tools/exec-approvals.md | 231 ++++++++++++++++----------- 3 files changed, 252 insertions(+), 277 deletions(-) diff --git a/.openclaw-sync/source.json b/.openclaw-sync/source.json index aed61d9cc..3416fa57e 100644 --- a/.openclaw-sync/source.json +++ b/.openclaw-sync/source.json @@ -1,5 +1,5 @@ { "repository": "openclaw/openclaw", - "sha": "fb47c1d6bf0b95c788f647a05faec934d08abb19", - "syncedAt": "2026-04-23T17:04:12.975Z" + "sha": "4792a50710aab6d0f30d7478967ef185892baf43", + "syncedAt": "2026-04-23T17:10:15.586Z" } diff --git a/docs/gateway/protocol.md b/docs/gateway/protocol.md index 393aa7b8d..991537243 100644 --- a/docs/gateway/protocol.md +++ b/docs/gateway/protocol.md @@ -4,7 +4,7 @@ read_when: - Implementing or updating gateway WS clients - Debugging protocol mismatches or connect failures - Regenerating protocol schema/models -title: "Gateway Protocol" +title: "Gateway protocol" --- # Gateway protocol (WebSocket) @@ -260,199 +260,129 @@ Each client connection keeps its own per-client sequence number so broadcasts pr ## Common RPC method families -This page is not a generated full dump, but the public WS surface is broader -than the handshake/auth examples above. These are the main method families the -Gateway exposes today. +The public WS surface is broader than the handshake/auth examples above. This +is not a generated dump — `hello-ok.features.methods` is a conservative +discovery list built from `src/gateway/server-methods-list.ts` plus loaded +plugin/channel method exports. Treat it as feature discovery, not a full +enumeration of `src/gateway/server-methods/*.ts`. -`hello-ok.features.methods` is a conservative discovery list built from -`src/gateway/server-methods-list.ts` plus loaded plugin/channel method exports. -Treat it as feature discovery, not as a generated dump of every callable helper -implemented in `src/gateway/server-methods/*.ts`. + + + - `health` returns the cached or freshly probed gateway health snapshot. + - `diagnostics.stability` returns the recent bounded diagnostic stability recorder. It keeps operational metadata such as event names, counts, byte sizes, memory readings, queue/session state, channel/plugin names, and session ids. It does not keep chat text, webhook bodies, tool outputs, raw request or response bodies, tokens, cookies, or secret values. Operator read scope is required. + - `status` returns the `/status`-style gateway summary; sensitive fields are included only for admin-scoped operator clients. + - `gateway.identity.get` returns the gateway device identity used by relay and pairing flows. + - `system-presence` returns the current presence snapshot for connected operator/node devices. + - `system-event` appends a system event and can update/broadcast presence context. + - `last-heartbeat` returns the latest persisted heartbeat event. + - `set-heartbeats` toggles heartbeat processing on the gateway. + -### System and identity + + - `models.list` returns the runtime-allowed model catalog. + - `usage.status` returns provider usage windows/remaining quota summaries. + - `usage.cost` returns aggregated cost usage summaries for a date range. + - `doctor.memory.status` returns vector-memory / embedding readiness for the active default agent workspace. + - `sessions.usage` returns per-session usage summaries. + - `sessions.usage.timeseries` returns timeseries usage for one session. + - `sessions.usage.logs` returns usage log entries for one session. + -- `health` returns the cached or freshly probed gateway health snapshot. -- `diagnostics.stability` returns the recent bounded diagnostic stability - recorder. It keeps operational metadata such as event names, counts, byte - sizes, memory readings, queue/session state, channel/plugin names, and session - ids. It does not keep chat text, webhook bodies, tool outputs, raw request or - response bodies, tokens, cookies, or secret values. Operator read scope is - required. -- `status` returns the `/status`-style gateway summary; sensitive fields are - included only for admin-scoped operator clients. -- `gateway.identity.get` returns the gateway device identity used by relay and - pairing flows. -- `system-presence` returns the current presence snapshot for connected - operator/node devices. -- `system-event` appends a system event and can update/broadcast presence - context. -- `last-heartbeat` returns the latest persisted heartbeat event. -- `set-heartbeats` toggles heartbeat processing on the gateway. + + - `channels.status` returns built-in + bundled channel/plugin status summaries. + - `channels.logout` logs out a specific channel/account where the channel supports logout. + - `web.login.start` starts a QR/web login flow for the current QR-capable web channel provider. + - `web.login.wait` waits for that QR/web login flow to complete and starts the channel on success. + - `push.test` sends a test APNs push to a registered iOS node. + - `voicewake.get` returns the stored wake-word triggers. + - `voicewake.set` updates wake-word triggers and broadcasts the change. + -### Models and usage + + - `send` is the direct outbound-delivery RPC for channel/account/thread-targeted sends outside the chat runner. + - `logs.tail` returns the configured gateway file-log tail with cursor/limit and max-byte controls. + -- `models.list` returns the runtime-allowed model catalog. -- `usage.status` returns provider usage windows/remaining quota summaries. -- `usage.cost` returns aggregated cost usage summaries for a date range. -- `doctor.memory.status` returns vector-memory / embedding readiness for the - active default agent workspace. -- `sessions.usage` returns per-session usage summaries. -- `sessions.usage.timeseries` returns timeseries usage for one session. -- `sessions.usage.logs` returns usage log entries for one session. + + - `talk.config` returns the effective Talk config payload; `includeSecrets` requires `operator.talk.secrets` (or `operator.admin`). + - `talk.mode` sets/broadcasts the current Talk mode state for WebChat/Control UI clients. + - `talk.speak` synthesizes speech through the active Talk speech provider. + - `tts.status` returns TTS enabled state, active provider, fallback providers, and provider config state. + - `tts.providers` returns the visible TTS provider inventory. + - `tts.enable` and `tts.disable` toggle TTS prefs state. + - `tts.setProvider` updates the preferred TTS provider. + - `tts.convert` runs one-shot text-to-speech conversion. + -### Channels and login helpers + + - `secrets.reload` re-resolves active SecretRefs and swaps runtime secret state only on full success. + - `secrets.resolve` resolves command-target secret assignments for a specific command/target set. + - `config.get` returns the current config snapshot and hash. + - `config.set` writes a validated config payload. + - `config.patch` merges a partial config update. + - `config.apply` validates + replaces the full config payload. + - `config.schema` returns the live config schema payload used by Control UI and CLI tooling: schema, `uiHints`, version, and generation metadata, including plugin + channel schema metadata when the runtime can load it. The schema includes field `title` / `description` metadata derived from the same labels and help text used by the UI, including nested object, wildcard, array-item, and `anyOf` / `oneOf` / `allOf` composition branches when matching field documentation exists. + - `config.schema.lookup` returns a path-scoped lookup payload for one config path: normalized path, a shallow schema node, matched hint + `hintPath`, and immediate child summaries for UI/CLI drill-down. Lookup schema nodes keep the user-facing docs and common validation fields (`title`, `description`, `type`, `enum`, `const`, `format`, `pattern`, numeric/string/array/object bounds, and flags like `additionalProperties`, `deprecated`, `readOnly`, `writeOnly`). Child summaries expose `key`, normalized `path`, `type`, `required`, `hasChildren`, plus the matched `hint` / `hintPath`. + - `update.run` runs the gateway update flow and schedules a restart only when the update itself succeeded. + - `wizard.start`, `wizard.next`, `wizard.status`, and `wizard.cancel` expose the onboarding wizard over WS RPC. + -- `channels.status` returns built-in + bundled channel/plugin status summaries. -- `channels.logout` logs out a specific channel/account where the channel - supports logout. -- `web.login.start` starts a QR/web login flow for the current QR-capable web - channel provider. -- `web.login.wait` waits for that QR/web login flow to complete and starts the - channel on success. -- `push.test` sends a test APNs push to a registered iOS node. -- `voicewake.get` returns the stored wake-word triggers. -- `voicewake.set` updates wake-word triggers and broadcasts the change. + + - `agents.list` returns configured agent entries. + - `agents.create`, `agents.update`, and `agents.delete` manage agent records and workspace wiring. + - `agents.files.list`, `agents.files.get`, and `agents.files.set` manage the bootstrap workspace files exposed for an agent. + - `agent.identity.get` returns the effective assistant identity for an agent or session. + - `agent.wait` waits for a run to finish and returns the terminal snapshot when available. + -### Messaging and logs + + - `sessions.list` returns the current session index. + - `sessions.subscribe` and `sessions.unsubscribe` toggle session change event subscriptions for the current WS client. + - `sessions.messages.subscribe` and `sessions.messages.unsubscribe` toggle transcript/message event subscriptions for one session. + - `sessions.preview` returns bounded transcript previews for specific session keys. + - `sessions.resolve` resolves or canonicalizes a session target. + - `sessions.create` creates a new session entry. + - `sessions.send` sends a message into an existing session. + - `sessions.steer` is the interrupt-and-steer variant for an active session. + - `sessions.abort` aborts active work for a session. + - `sessions.patch` updates session metadata/overrides. + - `sessions.reset`, `sessions.delete`, and `sessions.compact` perform session maintenance. + - `sessions.get` returns the full stored session row. + - Chat execution still uses `chat.history`, `chat.send`, `chat.abort`, and `chat.inject`. `chat.history` is display-normalized for UI clients: inline directive tags are stripped from visible text, plain-text tool-call XML payloads (including `...`, `...`, `...`, `...`, and truncated tool-call blocks) and leaked ASCII/full-width model control tokens are stripped, pure silent-token assistant rows such as exact `NO_REPLY` / `no_reply` are omitted, and oversized rows can be replaced with placeholders. + -- `send` is the direct outbound-delivery RPC for channel/account/thread-targeted - sends outside the chat runner. -- `logs.tail` returns the configured gateway file-log tail with cursor/limit and - max-byte controls. + + - `device.pair.list` returns pending and approved paired devices. + - `device.pair.approve`, `device.pair.reject`, and `device.pair.remove` manage device-pairing records. + - `device.token.rotate` rotates a paired device token within its approved role and scope bounds. + - `device.token.revoke` revokes a paired device token. + -### Talk and TTS + + - `node.pair.request`, `node.pair.list`, `node.pair.approve`, `node.pair.reject`, and `node.pair.verify` cover node pairing and bootstrap verification. + - `node.list` and `node.describe` return known/connected node state. + - `node.rename` updates a paired node label. + - `node.invoke` forwards a command to a connected node. + - `node.invoke.result` returns the result for an invoke request. + - `node.event` carries node-originated events back into the gateway. + - `node.canvas.capability.refresh` refreshes scoped canvas-capability tokens. + - `node.pending.pull` and `node.pending.ack` are the connected-node queue APIs. + - `node.pending.enqueue` and `node.pending.drain` manage durable pending work for offline/disconnected nodes. + -- `talk.config` returns the effective Talk config payload; `includeSecrets` - requires `operator.talk.secrets` (or `operator.admin`). -- `talk.mode` sets/broadcasts the current Talk mode state for WebChat/Control UI - clients. -- `talk.speak` synthesizes speech through the active Talk speech provider. -- `tts.status` returns TTS enabled state, active provider, fallback providers, - and provider config state. -- `tts.providers` returns the visible TTS provider inventory. -- `tts.enable` and `tts.disable` toggle TTS prefs state. -- `tts.setProvider` updates the preferred TTS provider. -- `tts.convert` runs one-shot text-to-speech conversion. + + - `exec.approval.request`, `exec.approval.get`, `exec.approval.list`, and `exec.approval.resolve` cover one-shot exec approval requests plus pending approval lookup/replay. + - `exec.approval.waitDecision` waits on one pending exec approval and returns the final decision (or `null` on timeout). + - `exec.approvals.get` and `exec.approvals.set` manage gateway exec approval policy snapshots. + - `exec.approvals.node.get` and `exec.approvals.node.set` manage node-local exec approval policy via node relay commands. + - `plugin.approval.request`, `plugin.approval.list`, `plugin.approval.waitDecision`, and `plugin.approval.resolve` cover plugin-defined approval flows. + -### Secrets, config, update, and wizard - -- `secrets.reload` re-resolves active SecretRefs and swaps runtime secret state - only on full success. -- `secrets.resolve` resolves command-target secret assignments for a specific - command/target set. -- `config.get` returns the current config snapshot and hash. -- `config.set` writes a validated config payload. -- `config.patch` merges a partial config update. -- `config.apply` validates + replaces the full config payload. -- `config.schema` returns the live config schema payload used by Control UI and - CLI tooling: schema, `uiHints`, version, and generation metadata, including - plugin + channel schema metadata when the runtime can load it. The schema - includes field `title` / `description` metadata derived from the same labels - and help text used by the UI, including nested object, wildcard, array-item, - and `anyOf` / `oneOf` / `allOf` composition branches when matching field - documentation exists. -- `config.schema.lookup` returns a path-scoped lookup payload for one config - path: normalized path, a shallow schema node, matched hint + `hintPath`, and - immediate child summaries for UI/CLI drill-down. - - Lookup schema nodes keep the user-facing docs and common validation fields: - `title`, `description`, `type`, `enum`, `const`, `format`, `pattern`, - numeric/string/array/object bounds, and boolean flags like - `additionalProperties`, `deprecated`, `readOnly`, `writeOnly`. - - Child summaries expose `key`, normalized `path`, `type`, `required`, - `hasChildren`, plus the matched `hint` / `hintPath`. -- `update.run` runs the gateway update flow and schedules a restart only when - the update itself succeeded. -- `wizard.start`, `wizard.next`, `wizard.status`, and `wizard.cancel` expose the - onboarding wizard over WS RPC. - -### Existing major families - -#### Agent and workspace helpers - -- `agents.list` returns configured agent entries. -- `agents.create`, `agents.update`, and `agents.delete` manage agent records and - workspace wiring. -- `agents.files.list`, `agents.files.get`, and `agents.files.set` manage the - bootstrap workspace files exposed for an agent. -- `agent.identity.get` returns the effective assistant identity for an agent or - session. -- `agent.wait` waits for a run to finish and returns the terminal snapshot when - available. - -#### Session control - -- `sessions.list` returns the current session index. -- `sessions.subscribe` and `sessions.unsubscribe` toggle session change event - subscriptions for the current WS client. -- `sessions.messages.subscribe` and `sessions.messages.unsubscribe` toggle - transcript/message event subscriptions for one session. -- `sessions.preview` returns bounded transcript previews for specific session - keys. -- `sessions.resolve` resolves or canonicalizes a session target. -- `sessions.create` creates a new session entry. -- `sessions.send` sends a message into an existing session. -- `sessions.steer` is the interrupt-and-steer variant for an active session. -- `sessions.abort` aborts active work for a session. -- `sessions.patch` updates session metadata/overrides. -- `sessions.reset`, `sessions.delete`, and `sessions.compact` perform session - maintenance. -- `sessions.get` returns the full stored session row. -- chat execution still uses `chat.history`, `chat.send`, `chat.abort`, and - `chat.inject`. -- `chat.history` is display-normalized for UI clients: inline directive tags are - stripped from visible text, plain-text tool-call XML payloads (including - `...`, `...`, - `...`, `...`, and - truncated tool-call blocks) and leaked ASCII/full-width model control tokens - are stripped, pure silent-token assistant rows such as exact `NO_REPLY` / - `no_reply` are omitted, and oversized rows can be replaced with placeholders. - -#### Device pairing and device tokens - -- `device.pair.list` returns pending and approved paired devices. -- `device.pair.approve`, `device.pair.reject`, and `device.pair.remove` manage - device-pairing records. -- `device.token.rotate` rotates a paired device token within its approved role - and scope bounds. -- `device.token.revoke` revokes a paired device token. - -#### Node pairing, invoke, and pending work - -- `node.pair.request`, `node.pair.list`, `node.pair.approve`, - `node.pair.reject`, and `node.pair.verify` cover node pairing and bootstrap - verification. -- `node.list` and `node.describe` return known/connected node state. -- `node.rename` updates a paired node label. -- `node.invoke` forwards a command to a connected node. -- `node.invoke.result` returns the result for an invoke request. -- `node.event` carries node-originated events back into the gateway. -- `node.canvas.capability.refresh` refreshes scoped canvas-capability tokens. -- `node.pending.pull` and `node.pending.ack` are the connected-node queue APIs. -- `node.pending.enqueue` and `node.pending.drain` manage durable pending work - for offline/disconnected nodes. - -#### Approval families - -- `exec.approval.request`, `exec.approval.get`, `exec.approval.list`, and - `exec.approval.resolve` cover one-shot exec approval requests plus pending - approval lookup/replay. -- `exec.approval.waitDecision` waits on one pending exec approval and returns - the final decision (or `null` on timeout). -- `exec.approvals.get` and `exec.approvals.set` manage gateway exec approval - policy snapshots. -- `exec.approvals.node.get` and `exec.approvals.node.set` manage node-local exec - approval policy via node relay commands. -- `plugin.approval.request`, `plugin.approval.list`, - `plugin.approval.waitDecision`, and `plugin.approval.resolve` cover - plugin-defined approval flows. - -#### Other major families - -- automation: - - `wake` schedules an immediate or next-heartbeat wake text injection - - `cron.list`, `cron.status`, `cron.add`, `cron.update`, `cron.remove`, - `cron.run`, `cron.runs` -- skills/tools: `commands.list`, `skills.*`, `tools.catalog`, `tools.effective` + + - Automation: `wake` schedules an immediate or next-heartbeat wake text injection; `cron.list`, `cron.status`, `cron.add`, `cron.update`, `cron.remove`, `cron.run`, `cron.runs` manage scheduled work. + - Skills and tools: `commands.list`, `skills.*`, `tools.catalog`, `tools.effective`. + + ### Common event families diff --git a/docs/tools/exec-approvals.md b/docs/tools/exec-approvals.md index 23d8b86a4..fdacdc594 100644 --- a/docs/tools/exec-approvals.md +++ b/docs/tools/exec-approvals.md @@ -4,35 +4,44 @@ read_when: - Configuring exec approvals or allowlists - Implementing exec approval UX in the macOS app - Reviewing sandbox escape prompts and implications -title: "Exec Approvals" +title: "Exec approvals" --- # Exec approvals -Exec approvals are the **companion app / node host guardrail** for letting a sandboxed agent run -commands on a real host (`gateway` or `node`). Think of it like a safety interlock: -commands are allowed only when policy + allowlist + (optional) user approval all agree. -Exec approvals are **in addition** to tool policy and elevated gating (unless elevated is set to `full`, which skips approvals). -Effective policy is the **stricter** of `tools.exec.*` and approvals defaults; if an approvals field is omitted, the `tools.exec` value is used. -Host exec also uses the local approvals state on that machine. A host-local -`ask: "always"` in `~/.openclaw/exec-approvals.json` keeps prompting even if -session or config defaults request `ask: "on-miss"`. -Use `openclaw approvals get`, `openclaw approvals get --gateway`, or -`openclaw approvals get --node ` to inspect the requested policy, -host policy sources, and the effective result. -For the local machine, `openclaw exec-policy show` exposes the same merged view and -`openclaw exec-policy set|preset` can synchronize the local requested policy with the -local host approvals file in one step. When a local scope requests `host=node`, -`openclaw exec-policy show` reports that scope as node-managed at runtime instead of -pretending the local approvals file is the effective source of truth. +Exec approvals are the **companion app / node host guardrail** for letting a +sandboxed agent run commands on a real host (`gateway` or `node`). A safety +interlock: commands are allowed only when policy + allowlist + (optional) user +approval all agree. Exec approvals stack **on top of** tool policy and elevated +gating (unless elevated is set to `full`, which skips approvals). -If the companion app UI is **not available**, any request that requires a prompt is -resolved by the **ask fallback** (default: deny). + +Effective policy is the **stricter** of `tools.exec.*` and approvals defaults; +if an approvals field is omitted, the `tools.exec` value is used. Host exec +also uses local approvals state on that machine — a host-local `ask: "always"` +in `~/.openclaw/exec-approvals.json` keeps prompting even if session or config +defaults request `ask: "on-miss"`. + -Native chat approval clients can also expose channel-specific affordances on the -pending approval message. For example, Matrix can seed reaction shortcuts on the -approval prompt (`✅` allow once, `❌` deny, and `♾️` allow always when available) -while still leaving the `/approve ...` commands in the message as a fallback. +## Inspecting the effective policy + +- `openclaw approvals get`, `... --gateway`, `... --node ` — show requested policy, host policy sources, and the effective result. +- `openclaw exec-policy show` — local-machine merged view. +- `openclaw exec-policy set|preset` — synchronize the local requested policy with the local host approvals file in one step. + +When a local scope requests `host=node`, `exec-policy show` reports that scope +as node-managed at runtime instead of pretending the local approvals file is +the source of truth. + +If the companion app UI is **not available**, any request that would normally +prompt is resolved by the **ask fallback** (default: deny). + + +Native chat approval clients can seed channel-specific affordances on the +pending approval message. For example, Matrix seeds reaction shortcuts (`✅` +allow once, `❌` deny, `♾️` allow always) while still leaving `/approve ...` +commands in the message as a fallback. + ## Where it applies @@ -268,60 +277,19 @@ Important trust notes: ## Safe bins (stdin-only) -`tools.exec.safeBins` defines a small list of **stdin-only** binaries (for example `cut`) -that can run in allowlist mode **without** explicit allowlist entries. Safe bins reject -positional file args and path-like tokens, so they can only operate on the incoming stream. -Treat this as a narrow fast-path for stream filters, not a general trust list. -Do **not** add interpreter or runtime binaries (for example `python3`, `node`, `ruby`, `bash`, `sh`, `zsh`) to `safeBins`. -If a command can evaluate code, execute subcommands, or read files by design, prefer explicit allowlist entries and keep approval prompts enabled. -Custom safe bins must define an explicit profile in `tools.exec.safeBinProfiles.`. -Validation is deterministic from argv shape only (no host filesystem existence checks), which -prevents file-existence oracle behavior from allow/deny differences. -File-oriented options are denied for default safe bins (for example `sort -o`, `sort --output`, -`sort --files0-from`, `sort --compress-program`, `sort --random-source`, -`sort --temporary-directory`/`-T`, `wc --files0-from`, `jq -f/--from-file`, -`grep -f/--file`). -Safe bins also enforce explicit per-binary flag policy for options that break stdin-only -behavior (for example `sort -o/--output/--compress-program` and grep recursive flags). -Long options are validated fail-closed in safe-bin mode: unknown flags and ambiguous -abbreviations are rejected. -Denied flags by safe-bin profile: +`tools.exec.safeBins` defines a small list of **stdin-only** binaries (for +example `cut`) that can run in allowlist mode **without** explicit allowlist +entries. Safe bins reject positional file args and path-like tokens, so they +can only operate on the incoming stream. Treat this as a narrow fast-path for +stream filters, not a general trust list. -[//]: # "SAFE_BIN_DENIED_FLAGS:START" - -- `grep`: `--dereference-recursive`, `--directories`, `--exclude-from`, `--file`, `--recursive`, `-R`, `-d`, `-f`, `-r` -- `jq`: `--argfile`, `--from-file`, `--library-path`, `--rawfile`, `--slurpfile`, `-L`, `-f` -- `sort`: `--compress-program`, `--files0-from`, `--output`, `--random-source`, `--temporary-directory`, `-T`, `-o` -- `wc`: `--files0-from` - -[//]: # "SAFE_BIN_DENIED_FLAGS:END" - -Safe bins also force argv tokens to be treated as **literal text** at execution time (no globbing -and no `$VARS` expansion) for stdin-only segments, so patterns like `*` or `$HOME/...` cannot be -used to smuggle file reads. -Safe bins must also resolve from trusted binary directories (system defaults plus optional -`tools.exec.safeBinTrustedDirs`). `PATH` entries are never auto-trusted. -Default trusted safe-bin directories are intentionally minimal: `/bin`, `/usr/bin`. -If your safe-bin executable lives in package-manager/user paths (for example -`/opt/homebrew/bin`, `/usr/local/bin`, `/opt/local/bin`, `/snap/bin`), add them explicitly -to `tools.exec.safeBinTrustedDirs`. -Shell chaining and redirections are not auto-allowed in allowlist mode. - -Shell chaining (`&&`, `||`, `;`) is allowed when every top-level segment satisfies the allowlist -(including safe bins or skill auto-allow). Redirections remain unsupported in allowlist mode. -Command substitution (`$()` / backticks) is rejected during allowlist parsing, including inside -double quotes; use single quotes if you need literal `$()` text. -On macOS companion-app approvals, raw shell text containing shell control or expansion syntax -(`&&`, `||`, `;`, `|`, `` ` ``, `$`, `<`, `>`, `(`, `)`) is treated as an allowlist miss unless -the shell binary itself is allowlisted. -For shell wrappers (`bash|sh|zsh ... -c/-lc`), request-scoped env overrides are reduced to a -small explicit allowlist (`TERM`, `LANG`, `LC_*`, `COLORTERM`, `NO_COLOR`, `FORCE_COLOR`). -For allow-always decisions in allowlist mode, known dispatch wrappers -(`env`, `nice`, `nohup`, `stdbuf`, `timeout`) persist inner executable paths instead of wrapper -paths. Shell multiplexers (`busybox`, `toybox`) are also unwrapped for shell applets (`sh`, `ash`, -etc.) so inner executables are persisted instead of multiplexer binaries. If a wrapper or -multiplexer cannot be safely unwrapped, no allowlist entry is persisted automatically. -If you allowlist interpreters like `python3` or `node`, prefer `tools.exec.strictInlineEval=true` so inline eval still requires an explicit approval. In strict mode, `allow-always` can still persist benign interpreter/script invocations, but inline-eval carriers are not persisted automatically. + +Do **not** add interpreter or runtime binaries (for example `python3`, `node`, +`ruby`, `bash`, `sh`, `zsh`) to `safeBins`. If a command can evaluate code, +execute subcommands, or read files by design, prefer explicit allowlist entries +and keep approval prompts enabled. Custom safe bins must define an explicit +profile in `tools.exec.safeBinProfiles.`. + Default safe bins: @@ -331,10 +299,78 @@ Default safe bins: [//]: # "SAFE_BIN_DEFAULTS:END" -`grep` and `sort` are not in the default list. If you opt in, keep explicit allowlist entries for -their non-stdin workflows. -For `grep` in safe-bin mode, provide the pattern with `-e`/`--regexp`; positional pattern form is -rejected so file operands cannot be smuggled as ambiguous positionals. +`grep` and `sort` are not in the default list. If you opt in, keep explicit +allowlist entries for their non-stdin workflows. For `grep` in safe-bin mode, +provide the pattern with `-e`/`--regexp`; positional pattern form is rejected +so file operands cannot be smuggled as ambiguous positionals. + + + + Validation is deterministic from argv shape only (no host filesystem + existence checks), which prevents file-existence oracle behavior from + allow/deny differences. File-oriented options are denied for default safe + bins; long options are validated fail-closed (unknown flags and ambiguous + abbreviations are rejected). + + Denied flags by safe-bin profile: + + [//]: # "SAFE_BIN_DENIED_FLAGS:START" + + - `grep`: `--dereference-recursive`, `--directories`, `--exclude-from`, `--file`, `--recursive`, `-R`, `-d`, `-f`, `-r` + - `jq`: `--argfile`, `--from-file`, `--library-path`, `--rawfile`, `--slurpfile`, `-L`, `-f` + - `sort`: `--compress-program`, `--files0-from`, `--output`, `--random-source`, `--temporary-directory`, `-T`, `-o` + - `wc`: `--files0-from` + + [//]: # "SAFE_BIN_DENIED_FLAGS:END" + + Safe bins also force argv tokens to be treated as **literal text** at + execution time (no globbing and no `$VARS` expansion) for stdin-only + segments, so patterns like `*` or `$HOME/...` cannot be used to smuggle + file reads. + + + + + Safe bins must resolve from trusted binary directories (system defaults + plus optional `tools.exec.safeBinTrustedDirs`). `PATH` entries are never + auto-trusted. Default trusted directories are intentionally minimal: + `/bin`, `/usr/bin`. If your safe-bin executable lives in + package-manager/user paths (for example `/opt/homebrew/bin`, + `/usr/local/bin`, `/opt/local/bin`, `/snap/bin`), add them explicitly to + `tools.exec.safeBinTrustedDirs`. + + + + Shell chaining (`&&`, `||`, `;`) is allowed when every top-level segment + satisfies the allowlist (including safe bins or skill auto-allow). + Redirections remain unsupported in allowlist mode. Command substitution + (`$()` / backticks) is rejected during allowlist parsing, including inside + double quotes; use single quotes if you need literal `$()` text. + + On macOS companion-app approvals, raw shell text containing shell control + or expansion syntax (`&&`, `||`, `;`, `|`, `` ` ``, `$`, `<`, `>`, `(`, + `)`) is treated as an allowlist miss unless the shell binary itself is + allowlisted. + + For shell wrappers (`bash|sh|zsh ... -c/-lc`), request-scoped env + overrides are reduced to a small explicit allowlist (`TERM`, `LANG`, + `LC_*`, `COLORTERM`, `NO_COLOR`, `FORCE_COLOR`). + + For `allow-always` decisions in allowlist mode, known dispatch wrappers + (`env`, `nice`, `nohup`, `stdbuf`, `timeout`) persist the inner executable + path instead of the wrapper path. Shell multiplexers (`busybox`, `toybox`) + are unwrapped for shell applets (`sh`, `ash`, etc.) the same way. If a + wrapper or multiplexer cannot be safely unwrapped, no allowlist entry is + persisted automatically. + + If you allowlist interpreters like `python3` or `node`, prefer + `tools.exec.strictInlineEval=true` so inline eval still requires an + explicit approval. In strict mode, `allow-always` can still persist benign + interpreter/script invocations, but inline-eval carriers are not persisted + automatically. + + + ### Safe bins versus allowlist @@ -642,20 +678,29 @@ stale results from a prior successful run. - **full** is powerful; prefer allowlists when possible. - **ask** keeps you in the loop while still allowing fast approvals. -- Per-agent allowlists prevent one agent’s approvals from leaking into others. +- Per-agent allowlists prevent one agent's approvals from leaking into others. - Approvals only apply to host exec requests from **authorized senders**. Unauthorized senders cannot issue `/exec`. -- `/exec security=full` is a session-level convenience for authorized operators and skips approvals by design. - To hard-block host exec, set approvals security to `deny` or deny the `exec` tool via tool policy. - -Related: - -- [Exec tool](/tools/exec) -- [Elevated mode](/tools/elevated) -- [Skills](/tools/skills) +- `/exec security=full` is a session-level convenience for authorized operators and skips approvals by design. To hard-block host exec, set approvals security to `deny` or deny the `exec` tool via tool policy. ## Related -- [Exec](/tools/exec) — shell command execution tool -- [Sandboxing](/gateway/sandboxing) — sandbox modes and workspace access -- [Security](/gateway/security) — security model and hardening -- [Sandbox vs Tool Policy vs Elevated](/gateway/sandbox-vs-tool-policy-vs-elevated) — when to use each + + + Shell command execution tool. + + + Break-glass path that also skips approvals. + + + Sandbox modes and workspace access. + + + Security model and hardening. + + + When to reach for each control. + + + Skill-backed auto-allow behavior. + +