diff --git a/docs/plugins/codex-harness-reference/approval-and-sandbox.md b/docs/plugins/codex-harness-reference/approval-and-sandbox.md index d088866a0079..b4c023ebc94e 100644 --- a/docs/plugins/codex-harness-reference/approval-and-sandbox.md +++ b/docs/plugins/codex-harness-reference/approval-and-sandbox.md @@ -10,6 +10,11 @@ sidebarTitle: "Approval and sandbox" The approval and sandbox posture of a Codex turn, and where native execution runs. Part of the [Codex harness reference](/plugins/codex-harness-reference); [Where each section moved](/plugins/codex-harness-reference#where-each-section-moved) lists every section. +For native plugin/app tools, also follow the +[app approval decision order](/plugins/codex-native-plugins#approval-decision-order). +App admission, tool enablement, per-tool approval modes, and OpenClaw's +elicitation response are separate from the general presets below. + ## Approval and sandbox modes Local stdio app-server sessions default to YOLO mode: diff --git a/docs/plugins/codex-harness-runtime/permissions.md b/docs/plugins/codex-harness-runtime/permissions.md index c21e67aa9716..de654840d796 100644 --- a/docs/plugins/codex-harness-runtime/permissions.md +++ b/docs/plugins/codex-harness-runtime/permissions.md @@ -32,6 +32,11 @@ Plugin, account, Computer Use, and MCP approval classification runs before ordinary input handling. A denied policy or unmappable approval schema returns an explicit decline and never becomes a general-purpose form. +For native app tools, see the +[approval decision order](/plugins/codex-native-plugins#approval-decision-order) +for OpenClaw defaults, native per-tool overrides, remembered approvals, and +how eligible hosted app tools reach consent while disabled tools remain blocked. + OpenClaw supports app-server MCP elicitation modes `form`, `openai/form`, and `url`. Standard and extended forms can contain at most 12 fields. OpenClaw normalizes field names to Gateway-safe question IDs, retains the original names diff --git a/docs/plugins/codex-native-plugins.md b/docs/plugins/codex-native-plugins.md index 5aa6d1e1239e..91637e205f10 100644 --- a/docs/plugins/codex-native-plugins.md +++ b/docs/plugins/codex-native-plugins.md @@ -6,6 +6,7 @@ read_when: - You are migrating source-installed openai-curated Codex plugins - You are discovering or installing a Codex marketplace plugin - You are troubleshooting codexPlugins, app inventory, destructive actions, or plugin app diagnostics + - You need the precedence of OpenClaw policy, native app defaults, and per-tool overrides --- Native Codex plugin support lets a Codex-mode OpenClaw agent use Codex @@ -212,6 +213,15 @@ runtime, revoked app, narrower policy, or unavailable inventory stops before app execution and reports how to restore access or reauthorize the automation. Model fallbacks cannot move this authority to another runtime or account. +This path is stricter than an ordinary interactive turn. OpenClaw generates +per-tool `enabled` and `approval_mode` values from current tool metadata and +the captured authority. An explicit native `enabled: true` cannot override a +captured or current destructive/open-world restriction on a scheduled run. +Approval intersections keep `"prompt"` if either side requires it; +`"approve"` defers to the other side. Combining `"auto"` with `"writes"` +produces `"prompt"`, because their annotation-dependent rules are not totally +ordered. + Jobs created before app authority capture may keep their ordinary OpenClaw tool cap and continue non-app work, but cannot recover Codex app access automatically. Recreate or reauthorize only a job that needs app access, from a @@ -533,20 +543,140 @@ cleanup cannot be confirmed. `destructive_enabled` on each app comes from the effective global or per-plugin `allow_destructive_actions` policy; `true`, `"auto"`, and `"ask"` all set `destructive_enabled: true`, and `false` sets it `false`. Codex still -enforces destructive tool metadata from its native app tool annotations. +evaluates native tool enablement and annotations in the order below. `_default` is disabled with `open_world_enabled: false`; enabled plugin apps get `open_world_enabled: true`. OpenClaw does not expose a separate plugin-level open-world policy knob and does not maintain per-plugin destructive tool-name deny lists. -Admitted apps retain their native Codex approval mode and reviewer, including -app defaults and saved link or tool overrides. With no native approval setting, -Codex uses its `auto` approval mode, and read-only tools usually run without a prompt. -Use `allow_destructive_actions: "auto"` to route native human approval requests -through OpenClaw; native `prompt` with the `auto_review` reviewer stays within -Codex's automatic review flow. These settings also apply when resuming a thread -or asking a `/btw` side question. Explicit OpenClaw `"ask"` policy overrides saved -native approvals as described below; `false` still disables destructive tools. +## Approval decision order + +For an ordinary interactive Codex turn, follow these decisions in order: + +1. **Admission:** OpenClaw selects the plugin/app identities allowed on this + thread. Unavailable inventory or unproven ownership does not grant access. +2. **Thread configuration:** OpenClaw overlays its app policy on the target + app-server's native configuration. Codex administrative requirements still + apply. +3. **Tool enablement:** Codex decides whether the particular tool is callable. + A disabled tool cannot be made callable by approving a prompt. +4. **Approval mode and reviewer:** Codex decides whether the call needs review + and whether to use its automatic reviewer or send a user approval request. +5. **OpenClaw response:** When a plugin approval request reaches OpenClaw, its + elicitation bridge applies the effective `allow_destructive_actions` value. + +These are separate decisions. `enabled: true` does not mean automatic approval, +and `approval_mode: "approve"` does not enable a disabled tool. OpenClaw dynamic +tools, ordinary MCP forms, and native shell permissions have their own flows; +see [Native permissions and MCP elicitations](/plugins/codex-harness-runtime/permissions). + +### Which configuration owns each setting + +| Setting | Owner and purpose | +| ------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `plugins.entries.codex.config.codexPlugins` | OpenClaw's admission and plugin elicitation policy. | +| `codexPlugins.allow_destructive_actions` | Shared OpenClaw default for configured plugins and admitted account apps. | +| `codexPlugins.plugins..allow_destructive_actions` | Explicit override for that configured plugin. | +| Native `apps._default`, `apps.`, and `apps..tools` | Codex app defaults and per-tool settings, after configuration layers and the OpenClaw thread patch are combined. | +| `plugins.entries.codex.config.appServer.approvalPolicy` and `approvalsReviewer` | General Codex approval posture and reviewer, distinct from app/tool policy. See [Approval and sandbox modes](/plugins/codex-harness-reference/approval-and-sandbox). | + +OpenClaw resolves the destructive-action setting as: + +```text +per-plugin value ?? codexPlugins shared value ?? true +``` + +Omitting a per-plugin value inherits the shared value. Explicit `false`, +`true`, `"auto"`, and `"ask"` all override it. In particular, a generated +per-plugin `"auto"` overrides a shared `false`; `"auto"` is a policy value, +not an instruction to inherit. + +The shared default lives in the same OpenClaw configuration as the plugin +entries. It requires no separate host-wide configuration file. Native Codex +settings belong to the app-server that runs the tools: the default managed +local server uses an agent-scoped Codex home; a remote server uses its own +configuration. Starting Codex from OpenClaw or a deployment manager +does not remove this native configuration layer. OpenClaw's thread patches +do not rewrite saved native settings. + +### Native tool enablement + +After OpenClaw's admission patch, Codex evaluates an app tool in this order: + +1. A disabled app blocks all its tools, including explicitly enabled tools. + Managed app disablement remains authoritative. +2. An explicit `apps..tools..enabled` wins for that tool. +3. Otherwise, an explicit `apps..default_tools_enabled` wins. +4. Otherwise, Codex checks `destructive_enabled` and `open_world_enabled` + against the tool's annotations. Each category setting falls back from the + app to `apps._default`, then to `true`. Missing annotations are treated as + destructive/open-world for this eligibility check. + +For tool configuration, an exact tool-name entry wins over a tool-title entry. +Codex selects the whole entry first; it does not fill missing fields from the +title entry. Omit `enabled` to inherit; TOML has no `null` value. + +For example, on an admitted app with `destructive_enabled: false`, an omitted +tool `enabled` leaves destructive tools blocked. Explicit `enabled: true` +allows that particular tool through this native eligibility check, while +`enabled: false` blocks it even if the app allows destructive tools. The call +still has to pass approval and execution checks. This is an exception to an +app default, not a way to enable an unadmitted app or widen scheduled authority. + +### Native approval mode + +For an enabled tool, Codex selects the first applicable approval mode: + +1. Managed per-tool approval requirement. +2. The selected native tool entry's `approval_mode`. +3. The selected connected account's + `apps..links..default_tools_approval_mode`. +4. `apps..default_tools_approval_mode`. +5. `apps._default.default_tools_approval_mode`. +6. `"auto"`. + +The account link is the connected account used for this call, not the +OpenClaw conversation. The following modes decide whether review is needed; +they do not themselves promise an OpenClaw prompt: + +| Native mode | Approval requirement | +| ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `"approve"` | No tool approval request. Other access and execution restrictions still apply. | +| `"prompt"` | Requires approval, including for read-only tools. | +| `"writes"` | Requires approval unless the tool explicitly declares itself read-only. | +| `"auto"` | Uses annotations: explicitly destructive tools require approval; otherwise explicitly read-only tools do not. Remaining tools require approval when destructive/open-world hints are true or missing. | + +Reviewer selection is separate: the connected account's reviewer overrides +the app reviewer, then `apps._default.approvals_reviewer`, then the thread +reviewer. Codex only accepts a configured reviewer allowed by administrative +requirements; otherwise it uses the thread reviewer. A model-specific +requirement for automatic review takes precedence. Strict automatic review +can also require review when a tool's mode would otherwise skip it. + +Unless OpenClaw policy is explicitly `"ask"`, admitted apps retain their +native approval mode and reviewer, including app defaults and saved account-link +or tool overrides. This also applies when resuming a thread or asking a `/btw` +side question. With no native approval setting, Codex falls back to `"auto"`. + +Use OpenClaw `allow_destructive_actions: "auto"` to route native human approval +requests through OpenClaw consent. Native `"prompt"` with the `"auto_review"` +reviewer stays in Codex's automatic review flow. OpenClaw `true` preserves the +native mode too, but auto-accepts supported approval requests that reach the +bridge, as described below. + +OpenClaw `"ask"` also overlays saved approval fields for current non-read-only +tool names/aliases and connected accounts, selecting native `"auto"` and a +human app/account reviewer. It preserves tool enablement. If tool summaries +are unavailable, it targets all saved tool approval entries. Thus `"ask"` +requires one-shot consent for the actions Codex sends for approval; it does +not mean native `"prompt"` for every read. Other apps retain their reviewer. + +On ordinary native-plugin turns and `/btw` side questions with bound apps, +OpenClaw enables MCP elicitation delegation even when the general +`appServer.approvalPolicy` is `"never"`; this does not enable unrelated shell +approval categories. The app mode, reviewer, and bridge response still +determine the outcome. General approval policy is not a replacement for the +per-app/tool settings above. ## Destructive action policy @@ -556,25 +686,23 @@ plugins, while unsafe schemas and ambiguous ownership fail closed: - Global `allow_destructive_actions` defaults to `true`. - Per-plugin `allow_destructive_actions` overrides the global policy for that plugin. -- `false`: OpenClaw excludes destructive hosted app tools before execution. - Native approval requests for permitted tools still go through OpenClaw consent, - including during a `/btw` side question. Plugin-provided MCP server approval - requests receive a deterministic decline. +- `false`: OpenClaw sets native `destructive_enabled: false`; tool eligibility + follows the native defaults and explicit exceptions described above. Approval + requests for eligible hosted app tools still go through OpenClaw consent, + including permitted reads and `/btw` side questions. The bridge does not + classify tools again or blanket-decline their requests. Plugin-provided MCP + server approval requests still receive a deterministic decline. - `true`: OpenClaw auto-accepts only safe schemas it can map to an approval response, such as a boolean approve field. - `"auto"`: OpenClaw exposes destructive plugin actions to Codex, then turns ownership-proven MCP approval elicitations into OpenClaw plugin approvals before returning the Codex approval response. - `"ask"`: OpenClaw uses the same Codex write/destructive gating as - `"auto"`, overrides saved per-tool and per-account approvals in the native - thread's configuration, and offers only one-shot approval or denial. Saved - native settings stay unchanged, and user-config reloads preserve the thread's - approval policy. These checks also run before reusing a thread or answering a + `"auto"`, applies the tool/account approval overlays described above, and + offers only one-shot approval or denial. Saved native settings stay unchanged, + and user-config reloads preserve the thread's approval policy. These checks + also run before reusing a thread or answering a `/btw` side question. Changed override keys rebuild the thread with current policy. - For each admitted app using `"ask"`, OpenClaw selects Codex's human approvals - reviewer for that app so Codex sends its approval elicitations to - OpenClaw; other apps and non-app thread approvals keep their configured - reviewer and policy. - Missing plugin identity, ambiguous ownership, a missing or mismatched turn id, or an unsafe elicitation schema declines instead of prompting. @@ -587,6 +715,31 @@ configuration and prevent app admission; move those app settings to a supported user or project configuration layer. Native administrative requirements remain authoritative. +### Approval examples + +Assume an admitted, authenticated app, no conflicting managed requirement, +and a human reviewer for calls that need approval. The read tools below declare +`readOnlyHint: true` and `destructiveHint: false`: + +| Configuration | Observable result on an ordinary turn | +| --------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| OpenClaw shared `false`, per-plugin `"auto"` | The plugin override wins. Destructive tools are eligible; approval elicitations that reach OpenClaw request consent. | +| OpenClaw `"auto"`, native app default `"prompt"`, no tool/link override, non-destructive read | Native `"prompt"` survives. The read requests consent; Allow once permits the call and Deny blocks it. | +| OpenClaw `"auto"`, native read-tool `approval_mode: "prompt"` | The per-tool mode survives. The read requests consent; Allow once permits the call and Deny blocks it. | +| OpenClaw `false`, native app default `"prompt"`, no tool/link override, non-destructive read | Native eligibility allows the read, and OpenClaw requests consent. Allow once permits the call and Deny blocks it. | +| OpenClaw `false`, destructive tool explicitly `enabled: true` and `approval_mode: "approve"` | The native tool exception bypasses the category default and requires no tool approval request. The bridge's decline path is not an execution-time category ceiling. | +| OpenClaw `"ask"`, saved non-read-only tool approval `"approve"` | The thread overlay replaces that saved approval with native `"auto"`; calls needing approval use one-shot consent. | + +If the reviewer in the native `"prompt"` examples is `"auto_review"` instead +of `"user"`, Codex performs automatic review rather than displaying an +OpenClaw consent prompt. Neither reviewer choice enables a tool that failed +the eligibility check. + +Remembered approval and explicit enablement are different settings. Codex's +persistent app-tool approval writes `approval_mode: "approve"`, not +`enabled: true`; Allow once does not persist either setting. Recheck both when +explaining why a tool ran or why no prompt appeared. + ## Troubleshooting | Code | Meaning | Fix |