Skip to content

Commit e084529

Browse files
committed
feat(codex): keep app-server local for remote execution
1 parent bc5a82b commit e084529

44 files changed

Lines changed: 3688 additions & 274 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ Docs: https://docs.openclaw.ai
66

77
### Changes
88

9+
- **Codex remote execution preview:** keep the Gateway and Codex app-server co-located while routing only authenticated unified exec to a remote Codex exec-server, with history-preserving topology changes, filtered child environments, managed-policy checks, and Docker live-proof coverage. (#101282, #101326)
910
- **Android chat agent selector:** switch the active agent directly from the live chat screen while keeping chat, Talk mode, and home canvas on the same canonical session. (#80422) Thanks @bcperry.
1011
- **Gateway host status:** show the connected Gateway's host, network address, OS, runtime, uptime, CPU, memory, and disk details in Control UI Settings. (#100478)
1112
- **iOS offline chat:** pre-paint recent sessions and canonical transcripts from a protected, bounded per-gateway cache, keep sending disabled offline, and purge cached conversation text when pairing is reset. (#100194)

docs/plugins/codex-harness-reference.md

Lines changed: 63 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,9 @@ This keeps the app-server version tied to the bundled `codex` plugin instead of
6060
whichever separate Codex CLI happens to be installed locally. Set
6161
`appServer.command` only when you intentionally want a different executable.
6262

63-
For an already-running app-server, use WebSocket transport:
63+
Codex marks TCP WebSocket app-server transport as
64+
[experimental and unsupported](https://github.com/openai/codex/blob/rust-v0.142.5/codex-rs/app-server/README.md#protocol).
65+
Do not rely on it for production. For an already-running test app-server:
6466

6567
```json5
6668
{
@@ -71,7 +73,7 @@ For an already-running app-server, use WebSocket transport:
7173
config: {
7274
appServer: {
7375
transport: "websocket",
74-
url: "ws://gateway-host:39175",
76+
url: "wss://codex.example.com/app-server",
7577
authToken: "${CODEX_APP_SERVER_TOKEN}",
7678
requestTimeoutMs: 60000,
7779
},
@@ -106,6 +108,7 @@ For an already-running app-server, use WebSocket transport:
106108
| `serviceTier` | unset | Optional Codex app-server service tier. `"priority"` enables fast-mode routing, `"flex"` requests flex processing, and `null` clears the override. Legacy `"fast"` is accepted as `"priority"`. |
107109
| `networkProxy` | disabled | Opt into Codex permissions-profile networking for app-server commands. OpenClaw defines the selected `permissions.<profile>.network` config and selects it with `default_permissions` instead of sending `sandbox`. |
108110
| `experimental.sandboxExecServer` | `false` | Preview opt-in that registers an OpenClaw sandbox-backed Codex environment with the supported Codex app-server so native Codex execution can run inside the active OpenClaw sandbox. |
111+
| `experimental.remoteExecution` | unset | Preview single-target authenticated remote execution. Keeps app-server local over stdio and routes native filesystem/process work through one registry-backed exec-server. Requires `remoteWorkspaceRoot`. |
109112

110113
`appServer.networkProxy` is explicit because it changes the Codex sandbox
111114
contract. When enabled, OpenClaw also sets `features.network_proxy.enabled` and
@@ -165,6 +168,64 @@ plugins via `plugin/install` and refreshes inventory. Only connect OpenClaw to
165168
remote app-servers that are trusted to accept OpenClaw-managed plugin installs
166169
and app inventory refreshes.
167170

171+
## Remote execution environments
172+
173+
For remote workspaces, keep the managed app-server beside the Gateway over
174+
stdio and register a remote executor separately:
175+
176+
```bash
177+
codex exec-server \
178+
--remote https://environment-registry.example.com/api \
179+
--environment-id devbox-example
180+
```
181+
182+
Configure `appServer.experimental.remoteExecution` with the same registry and
183+
environment id. Its `authToken` authenticates the app-server side of the Noise
184+
rendezvous; configure the exec-server's registry authentication separately.
185+
OpenClaw disables inherited raw exec-server URL routing and lets Codex select
186+
the configured remote environment as the default. See the complete
187+
[deployment example and preview limits](/plugins/codex-harness#remote-execution-environments).
188+
189+
Gateway-owned stdio app-servers clear inherited `CODEX_EXEC_SERVER_URL` and
190+
`CODEX_EXEC_SERVER_NOISE_*` routing variables. Configure remote execution only
191+
through this validated plugin surface.
192+
193+
The configuration fails closed unless transport is stdio,
194+
`remoteWorkspaceRoot` is an absolute POSIX path, the registry uses HTTPS or
195+
true loopback HTTP, and all SecretInputs resolve. It also rejects
196+
remote-execution environment names in `clearEnv`, `networkProxy`,
197+
`sandboxExecServer`, and an active OpenClaw sandbox. Codex Computer Use and
198+
local stdio MCP servers are unavailable because Codex `0.142.x` removes the
199+
local execution environment in Noise mode. HTTP MCP remains app-server-local;
200+
stdio MCP requires an intentional `environment_id = "remote"`. Bounded turns
201+
clear remote routing and remain local. Codex requirements remain owned by the
202+
Gateway-side app-server.
203+
Initialization does not prove executor registration;
204+
deployment readiness must check registry/executor health separately. OpenClaw
205+
forces unified exec and a core-only remote shell environment, clears configured
206+
shell `set` values, and filters default secret names plus
207+
`CODEX_EXEC_SERVER_*` from child environments. That filtering reduces
208+
accidental disclosure; it does not stop same-user code from inspecting the
209+
exec-server process. Use narrowly scoped, rotatable registry credentials and
210+
an executor isolation boundary that prevents workspace commands from reading
211+
the exec-server environment. Keep registry credentials out of the workspace.
212+
213+
This preview configures exactly one authenticated registry target per spawned
214+
app-server process. It does not provide executor pools, failover, or per-thread
215+
target selection. The app-server host and remote executor must use Linux or
216+
macOS POSIX path semantics; Windows is unsupported on either side. Native Codex
217+
and OpenClaw user/project hook commands plus legacy notifications are disabled
218+
because Codex `0.142.x` runs them on the app-server host with the executor-native
219+
cwd. Codex-managed command hooks cannot be disabled this way; OpenClaw checks
220+
`hooks/list` and rejects remote execution when any are active. An active
221+
OpenClaw `before_tool_call`/trusted-tool policy also fails closed; app-server
222+
approval requests remain supported. Active legacy managed config or managed
223+
feature requirements that can override the forced execution policy also fail
224+
closed.
225+
226+
After changing the remote execution topology, send a normal message before
227+
`/btw` so the main thread can rotate into the current environment.
228+
168229
## Approval and sandbox modes
169230

170231
Local stdio app-server sessions default to YOLO mode:

docs/plugins/codex-harness.md

Lines changed: 136 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -358,10 +358,12 @@ app-server is too old, or the app-server cannot start.
358358

359359
## App-server policy
360360

361-
By default, the plugin starts OpenClaw's managed Codex binary locally with
362-
stdio transport. Set `appServer.command` only to intentionally run a
363-
different executable. Use WebSocket transport only when an app-server is
364-
already running elsewhere:
361+
By default, the plugin starts OpenClaw's managed Codex binary beside the
362+
Gateway and owns it over stdio. Keep that control-plane topology in
363+
production. Codex upstream marks TCP WebSocket app-server transport
364+
[experimental and unsupported](https://github.com/openai/codex/blob/rust-v0.142.5/codex-rs/app-server/README.md#protocol),
365+
so use it only for development or diagnostics when an app-server is already
366+
running elsewhere:
365367

366368
```json5
367369
{
@@ -372,7 +374,7 @@ already running elsewhere:
372374
config: {
373375
appServer: {
374376
transport: "websocket",
375-
url: "ws://gateway-host:39175",
377+
url: "wss://codex.example.com/app-server",
376378
authToken: "${CODEX_APP_SERVER_TOKEN}",
377379
},
378380
},
@@ -382,6 +384,121 @@ already running elsewhere:
382384
}
383385
```
384386

387+
### Remote execution environments
388+
389+
When Codex must execute on another host, keep the managed app-server with the
390+
Gateway over stdio and move only filesystem and process execution:
391+
392+
```text
393+
OpenClaw Gateway -> stdio -> codex app-server -> Noise registry -> codex exec-server
394+
```
395+
396+
Start an authenticated executor with the environment id registered for this
397+
OpenClaw deployment:
398+
399+
```bash
400+
codex exec-server \
401+
--remote https://environment-registry.example.com/api \
402+
--environment-id devbox-example
403+
```
404+
405+
Then configure the Gateway-owned app-server:
406+
407+
```json5
408+
{
409+
plugins: {
410+
entries: {
411+
codex: {
412+
enabled: true,
413+
config: {
414+
appServer: {
415+
transport: "stdio",
416+
mode: "guardian",
417+
remoteWorkspaceRoot: "/home/codex/workspaces",
418+
experimental: {
419+
remoteExecution: {
420+
registryUrl: "https://environment-registry.example.com/api",
421+
environmentId: "devbox-example",
422+
authToken: "${CODEX_EXEC_SERVER_NOISE_AUTH_TOKEN}",
423+
chatgptAccountId: "${CODEX_EXEC_SERVER_NOISE_CHATGPT_ACCOUNT_ID}",
424+
},
425+
},
426+
},
427+
},
428+
},
429+
},
430+
},
431+
}
432+
```
433+
434+
This preview requires Codex app-server `0.142.0` or newer, stdio transport,
435+
and an absolute POSIX `remoteWorkspaceRoot`. The registry URL must use HTTPS
436+
except for a true loopback URL. `authToken` and optional `chatgptAccountId`
437+
accept SecretInput values and authenticate the app-server side of the
438+
rendezvous; configure the exec-server's registry authentication separately.
439+
OpenClaw disables inherited raw exec-server URL routing so the app-server
440+
cannot fall back to an unauthenticated socket.
441+
442+
Gateway-owned stdio app-servers clear inherited `CODEX_EXEC_SERVER_URL` and
443+
`CODEX_EXEC_SERVER_NOISE_*` routing variables. Configure remote execution only
444+
through this validated plugin surface.
445+
446+
Codex auth, app inventory, thread state, and control-plane lifecycle remain
447+
with the Gateway-owned app-server. Normal Codex threads use the configured
448+
remote environment by default. Enabling this mode, or changing its registry,
449+
environment, account identity, credentials without an explicit account
450+
identity, or remote workspace root, forks the existing native Codex thread into
451+
the new topology so committed history is preserved.
452+
453+
Current preview limits:
454+
455+
- One app-server process supports exactly one authenticated remote target. The
456+
configured `environmentId` is a registry rendezvous id, not a pool selector;
457+
this preview does not provide failover, per-thread box selection, or dynamic
458+
switching among multiple executors.
459+
- The Gateway/app-server host and remote executor must use Linux or macOS POSIX
460+
path semantics. Windows is unsupported on either side in this preview.
461+
- OpenClaw forces Codex unified exec, disables zsh-fork fallbacks, legacy
462+
notifications, and user/project native hooks, and clears all hook command
463+
arrays. Codex-managed command hooks cannot be disabled by thread config, so
464+
OpenClaw checks `hooks/list` and rejects remote execution when any are active.
465+
It also rejects legacy managed config layers and managed feature requirements
466+
that can override the forced execution policy.
467+
An active OpenClaw `before_tool_call`/trusted-tool policy also fails closed
468+
because Codex `0.142.x` cannot route those hooks back to the Gateway with a
469+
Gateway-local cwd. The app-server approval bridge remains available.
470+
- Remote commands receive only Codex's core executor environment. OpenClaw
471+
replaces shell-environment customization for remote threads, clears configured
472+
`set` values, and excludes default `*KEY*`, `*SECRET*`, `*TOKEN*`, and explicit
473+
`CODEX_EXEC_SERVER_*` names.
474+
- `appServer.networkProxy`, `appServer.experimental.sandboxExecServer`, and
475+
Codex Computer Use cannot be combined with remote execution. An active
476+
OpenClaw sandbox also rejects this mode. Enforce required executor egress at
477+
the remote environment boundary.
478+
- Codex `0.142.x` removes its local execution environment when Noise remote
479+
execution is active. OpenClaw therefore rejects local stdio MCP servers in
480+
this mode. HTTP MCP remains app-server-local; a stdio MCP may run only when
481+
its Codex config intentionally sets `environment_id = "remote"`.
482+
- OpenClaw bounded turns, including model-backed search, review, and media
483+
understanding, intentionally clear remote routing and run in a temporary
484+
local workspace.
485+
- After changing the remote execution topology, send a normal message before
486+
`/btw` so the main thread can rotate into the current environment.
487+
- Codex requirements and approval policy are evaluated by the app-server.
488+
Provision `/etc/codex/requirements.toml` on the Gateway/app-server host; a
489+
copy on only the executor does not govern the app-server. Requirements that
490+
pin incompatible execution features make this preview fail closed.
491+
- App-server initialization does not prove that the matching executor is
492+
registered. Gate deployment readiness on registry/executor health and use a
493+
harmless native operation as end-to-end proof.
494+
- Give the exec-server only narrowly scoped, rotatable credentials. OpenClaw's
495+
enforced remote shell policy removes those variables from normal child
496+
environments, reducing accidental disclosure; it is not an isolation
497+
boundary against same-user code that can inspect the exec-server process.
498+
Run the exec-server behind an OS, container, or VM boundary that prevents
499+
workspace commands from reading its process environment, and never store
500+
registry credentials inside the workspace.
501+
385502
Local stdio app-server sessions default to the trusted local operator
386503
posture: `approvalPolicy: "never"`, `approvalsReviewer: "user"`, and
387504
`sandbox: "danger-full-access"`. If local Codex requirements disallow that
@@ -639,6 +756,7 @@ Supported `appServer` fields:
639756
| `serviceTier` | unset | Optional Codex app-server service tier. `"priority"` enables fast-mode routing, `"flex"` requests flex processing, `null` clears the override, and legacy `"fast"` is accepted as `"priority"`. |
640757
| `networkProxy` | disabled | Opt into Codex permissions-profile networking for app-server commands. OpenClaw defines the selected `permissions.<profile>.network` config and selects it with `default_permissions` instead of sending `sandbox`. |
641758
| `experimental.sandboxExecServer` | `false` | Preview opt-in that registers an OpenClaw sandbox-backed Codex environment with the supported Codex app-server so native Codex execution can run inside the active OpenClaw sandbox. |
759+
| `experimental.remoteExecution` | unset | Preview single-target authenticated remote execution. Keeps app-server local over stdio and routes native filesystem/process work through one registry-backed exec-server. Requires `remoteWorkspaceRoot`. |
642760

643761
`appServer.networkProxy` is explicit because it changes the Codex sandbox
644762
contract. When enabled, OpenClaw also sets `features.network_proxy.enabled`
@@ -914,9 +1032,20 @@ headers are valid.
9141032
`plugins.entries.codex.config.discovery.timeoutMs` or disable discovery.
9151033
See [Codex harness reference](/plugins/codex-harness-reference#model-discovery).
9161034

917-
**WebSocket transport fails immediately:** check `appServer.url`,
1035+
**Remote execution reaches the app-server but not the executor:** verify Codex
1036+
app-server `0.142.0` or newer, stdio transport, an HTTPS registry URL, the exact
1037+
environment id, resolved SecretInputs, and a registered healthy exec-server.
1038+
`/codex status` proves only the app-server control plane; use a harmless native
1039+
filesystem or command operation for end-to-end executor proof. A topology or
1040+
environment identity change forks the prior thread and preserves its history.
1041+
Remote execution forcibly disables native hook relay commands. An OpenClaw
1042+
tool policy that requires the relay makes startup fail instead of silently
1043+
running hooks on the Gateway with the executor cwd.
1044+
1045+
**Experimental WebSocket transport fails immediately:** check `appServer.url`,
9181046
`authToken`, headers, and that the remote app-server speaks the same Codex
919-
app-server protocol version.
1047+
app-server protocol version. Do not use TCP WebSocket app-server transport as
1048+
the production remote-execution topology.
9201049

9211050
**Native shell or patch tools are blocked with `Native hook relay
9221051
unavailable`:** the Codex thread is still trying to use a native hook relay

0 commit comments

Comments
 (0)