From abf940db61876ff3bca1d51b777cfc9a55e6d726 Mon Sep 17 00:00:00 2001 From: pashpashpash Date: Wed, 22 Apr 2026 01:53:49 -0700 Subject: [PATCH] fix(codex): unchain app-server defaults (#70082) --- CHANGELOG.md | 1 + docs/plugins/codex-harness.md | 13 ++++++++----- extensions/codex/openclaw.plugin.json | 4 ++-- extensions/codex/src/app-server/config.test.ts | 6 +++--- extensions/codex/src/app-server/config.ts | 4 ++-- extensions/codex/src/app-server/run-attempt.test.ts | 6 ++++-- 6 files changed, 20 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b8f008b1bdc..77aeadcd7cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ Docs: https://docs.openclaw.ai ### Fixes - Gateway/pairing webchat: render `/pair qr` replies as structured media instead of raw markdown text, preserve inline reply threading and silent-control handling on media replies, avoid persisting sensitive QR images into transcript history, and keep local webchat media embedding behind internal-only trust markers. (#70047) Thanks @BunsDev. +- Codex harness: default app-server runs to unchained local execution, so OpenAI heartbeats can use network and shell tools without stalling behind native Codex approvals or the workspace-write sandbox. - OpenAI/Responses: keep embedded OpenAI Responses runs on HTTP when `models.providers.openai.baseUrl` points at a local mock or other non-public endpoint, so mocked/custom endpoints no longer drift onto the hardcoded public websocket transport. (#69815) Thanks @vincentkoc. - Channels/config: require resolved runtime config on channel send/action/client helpers and block runtime helper `loadConfig()` calls, so SecretRefs are resolved at startup/boundaries instead of being re-read during sends. - CLI/channels: preserve bundled setup promotion metadata when a loaded partial channel plugin omits it, so adding a non-default account still moves legacy single-account fields such as Telegram `streaming` into `accounts.default`. diff --git a/docs/plugins/codex-harness.md b/docs/plugins/codex-harness.md index bcd750e53ce..8ba4a80bc56 100644 --- a/docs/plugins/codex-harness.md +++ b/docs/plugins/codex-harness.md @@ -263,9 +263,12 @@ By default, the plugin starts Codex locally with: codex app-server --listen stdio:// ``` -By default, OpenClaw asks Codex to request native approvals. You can tune that -policy further, for example by tightening it and routing reviews through the -guardian: +By default, OpenClaw starts local Codex harness sessions fully unchained: +`approvalPolicy: "never"` and `sandbox: "danger-full-access"`. That matches the +trusted local operator posture used by the Codex CLI and lets autonomous +heartbeats use network and shell tools without waiting on an invisible native +approval path. You can tighten that policy, for example by routing reviews +through the guardian: ```json5 { @@ -320,8 +323,8 @@ Supported `appServer` fields: | `authToken` | unset | Bearer token for WebSocket transport. | | `headers` | `{}` | Extra WebSocket headers. | | `requestTimeoutMs` | `60000` | Timeout for app-server control-plane calls. | -| `approvalPolicy` | `"on-request"` | Native Codex approval policy sent to thread start/resume/turn. | -| `sandbox` | `"workspace-write"` | Native Codex sandbox mode sent to thread start/resume. | +| `approvalPolicy` | `"never"` | Native Codex approval policy sent to thread start/resume/turn. | +| `sandbox` | `"danger-full-access"` | Native Codex sandbox mode sent to thread start/resume. | | `approvalsReviewer` | `"user"` | Use `"guardian_subagent"` to let Codex guardian review native approvals. | | `serviceTier` | unset | Optional Codex service tier, for example `"priority"`. | diff --git a/extensions/codex/openclaw.plugin.json b/extensions/codex/openclaw.plugin.json index 76a4df052b8..4364e12b1e9 100644 --- a/extensions/codex/openclaw.plugin.json +++ b/extensions/codex/openclaw.plugin.json @@ -66,12 +66,12 @@ "approvalPolicy": { "type": "string", "enum": ["never", "on-request", "on-failure", "untrusted"], - "default": "on-request" + "default": "never" }, "sandbox": { "type": "string", "enum": ["read-only", "workspace-write", "danger-full-access"], - "default": "workspace-write" + "default": "danger-full-access" }, "approvalsReviewer": { "type": "string", diff --git a/extensions/codex/src/app-server/config.test.ts b/extensions/codex/src/app-server/config.test.ts index 0c1a8a8dae3..80edd717d4c 100644 --- a/extensions/codex/src/app-server/config.test.ts +++ b/extensions/codex/src/app-server/config.test.ts @@ -60,7 +60,7 @@ describe("Codex app-server config", () => { ).toThrow("appServer.url is required"); }); - it("defaults native Codex approvals to on-request", () => { + it("defaults native Codex approvals to unchained local execution", () => { const runtime = resolveCodexAppServerRuntimeOptions({ pluginConfig: {}, env: {}, @@ -68,8 +68,8 @@ describe("Codex app-server config", () => { expect(runtime).toEqual( expect.objectContaining({ - approvalPolicy: "on-request", - sandbox: "workspace-write", + approvalPolicy: "never", + sandbox: "danger-full-access", approvalsReviewer: "user", }), ); diff --git a/extensions/codex/src/app-server/config.ts b/extensions/codex/src/app-server/config.ts index d7f91448e34..12a9c749cf4 100644 --- a/extensions/codex/src/app-server/config.ts +++ b/extensions/codex/src/app-server/config.ts @@ -136,11 +136,11 @@ export function resolveCodexAppServerRuntimeOptions( approvalPolicy: resolveApprovalPolicy(config.approvalPolicy) ?? resolveApprovalPolicy(env.OPENCLAW_CODEX_APP_SERVER_APPROVAL_POLICY) ?? - "on-request", + "never", sandbox: resolveSandbox(config.sandbox) ?? resolveSandbox(env.OPENCLAW_CODEX_APP_SERVER_SANDBOX) ?? - "workspace-write", + "danger-full-access", approvalsReviewer: resolveApprovalsReviewer(config.approvalsReviewer) ?? (env.OPENCLAW_CODEX_APP_SERVER_GUARDIAN === "1" ? "guardian_subagent" : "user"), diff --git a/extensions/codex/src/app-server/run-attempt.test.ts b/extensions/codex/src/app-server/run-attempt.test.ts index 786bf7efded..02a09da8ad2 100644 --- a/extensions/codex/src/app-server/run-attempt.test.ts +++ b/extensions/codex/src/app-server/run-attempt.test.ts @@ -188,6 +188,8 @@ describe("runCodexAppServerAttempt", () => { params: expect.objectContaining({ model: "gpt-5.4-codex", modelProvider: "openai", + approvalPolicy: "never", + sandbox: "danger-full-access", }), }, { @@ -435,9 +437,9 @@ describe("runCodexAppServerAttempt", () => { threadId: "thread-existing", model: "gpt-5.4-codex", modelProvider: "openai", - approvalPolicy: "on-request", + approvalPolicy: "never", approvalsReviewer: "user", - sandbox: "workspace-write", + sandbox: "danger-full-access", persistExtendedHistory: true, }); });