CodexWSLWindowsComputer UseChromeMCPRust

Fixing Codex Computer Use Across WSL and Windows

Manuel Parra2026-07-0911 min read

Codex Desktop was running its app server inside WSL, while the Chrome and Computer Use integrations depended on Windows-side plugin runtimes. Every call through those integrations failed before its JavaScript ran because Codex sent a Linux file URI to a Windows MCP server in the sandbox working-directory field, sandboxCwd.

The first missing step was to translate that URI for the process receiving it: /mnt/c/... to file:///C:/..., and paths inside the WSL filesystem to file://wsl.localhost/<distro>/.... I applied a public patch to the exact Codex release used by the desktop app.

A fresh process then exposed two more WSL-to-Windows boundaries. CODEX_CLI_PATH had to select a Windows-native sandbox helper. Plugin clients also had to load through Windows-valid file URLs.

This write-up follows the error that exposed the mismatch, the checks that ruled out other causes, the version-pinned build, the fresh-process repairs, and the separate Chrome recovery and end-to-end browser check.

The setup

  • Host application: Codex Desktop on Windows.
  • Codex app server and shell: WSL2.
  • Workspace: opened through WSL.
  • Windows integrations: Chrome and Computer Use plugins.
  • Tool transport: a Windows node_repl.exe registered as a local MCP server over standard input/output (STDIO).

Codex sent each request from Linux, and the local MCP server received it on Windows. Both systems could reach the workspace, but the file URI had to use the receiving operating system's path convention.

Failure: request validation rejected sandboxCwd

The smallest test asked the MCP server to evaluate a trivial JavaScript expression and return its working directory. It failed before the expression ran:

Mcp error: -32602: js: codex/sandbox-state-meta:
sandboxCwd is not a local file URI: file:///mnt/c/.../project

sandboxCwd is a field in MCP tool-call _meta under codex/sandbox-state-meta. Codex sends it when the server advertises the sandbox-state capability. In this call, the Windows MCP server rejected the Linux-local URI during request validation. Browser selectors, Chrome state, and Windows input handling were downstream of that failure and had not run.

The public report with the same failure class was openai/codex#29639. Its workspace was stored under /home/... in the native WSL filesystem, while mine was exposed under /mnt/c/.... In both cases, a Windows .exe received a Linux-local sandboxCwd URI.

What I ruled out

I checked each boundary separately before changing the generated configuration.

The plugins were installed

Both Chrome and Computer Use were installed and enabled. Their tools appeared in the session. This was not a missing-plugin failure.

The local MCP server received the request

Codex had generated a STDIO MCP configuration entry for the Windows executable. The file existed. The structured MCP validation error showed that the process had started and received the request.

The workspace was reachable

WSL could read the workspace normally. Windows could address the same directory through a drive path or the WSL UNC namespace. The directory existed; the receiver rejected the URI used to describe it.

Changing the MCP server's cwd did not change sandboxCwd

The rejected value came from MCP tool-call _meta, not from the process-level cwd in the generated MCP configuration. Editing that generated block changed the wrong field, and Codex Desktop could overwrite it on restart.

Removing sandbox context was not the fix

Removing sandboxCwd would bypass this validation but omit the sandbox working directory from the request. The fix needed to preserve that field and encode its value for Windows.

One directory, two local file URIs

For a workspace mounted from a Windows drive, WSL sees:

/mnt/c/work/project

The Linux-local URI is:

file:///mnt/c/work/project

A Windows process needs the drive form:

file:///C:/work/project

A workspace stored inside the WSL filesystem needs a different translation. Linux may see:

/home/user/project

Windows reaches that directory through the WSL UNC namespace:

file://wsl.localhost/<distro>/home/user/project

Using /mnt/c was not itself the bug. The error came from sending a URI local to Linux to a process validating it under Windows rules.

Codex already knew the active WSL distribution and the MCP server's STDIO command. It did not combine those facts before attaching sandboxCwd.

The patch: map sandboxCwd only for Windows STDIO servers under WSL

I found a focused public fork commit that implemented the missing mapping: Nicolas0315/codex@1870471. I checked out the release used by Codex Desktop, applied the patch there, and kept the change scoped to this runtime boundary.

The patch:

  1. Stores each MCP server's STDIO command in its metadata.
  2. Detects whether Codex is running under WSL.
  3. Maps sandboxCwd only for a Windows .exe STDIO command launched through WSL interop.
  4. Maps /mnt/<drive>/... to a Windows drive file URI.
  5. Maps other WSL paths to a wsl.localhost UNC file URI.
  6. Leaves Linux commands, non-WSL hosts, Streamable HTTP MCP servers, and already compatible paths unchanged.

In reduced form:

if is_wsl() && windows_exe_via_wsl_interop(stdio_command) {
    sandbox_cwd = map_wsl_uri_for_windows(sandbox_cwd, distro_name);
}

The server-type check prevents the mapping from changing requests sent to Linux MCP servers.

Version-pinned build and tests

I built from the release tag used by the desktop app with Cargo's lockfile unchanged. The adjacent Codex executables remained on that same release. Before the release build, I ran the test groups touched by the patch:

WSL sandboxCwd mapping tests: 6 passed
MCP server metadata regression test: 1 passed
Formatting and targeted fix checks: passed
Locked release build: passed

The mapping tests covered both workspace locations:

  • /mnt/c/... becomes file:///C:/....
  • /home/... becomes file://wsl.localhost/<distro>/home/....

The guardrail tests also kept the original URI for a Linux STDIO command and for a non-WSL host.

Fresh-process verification exposed two more boundaries

The already-running desktop task could reach Computer Use. That did not prove a newly launched CLI process could reconstruct the same chain from its saved configuration. Fresh-process testing separated four runtime roles that had looked like one configuration problem:

WSL Codex caller          -> patched Linux Codex executable
Windows MCP host          -> Windows node_repl.exe
Windows sandbox helper    -> Windows Codex executable via CODEX_CLI_PATH
plugin module specifier   -> Windows-valid file URL

Plain codex still selected the stock launcher

The desktop app had an explicit path to the patched Linux executable. A plain codex command in WSL did not use that setting; shell resolution still selected the stock package launcher. I added a higher-priority CLI entry that points to the verified patched build and left the package-managed launchers installed as rollback paths.

This fixed launcher selection without replacing the package installation.

The Windows sandbox helper tried to execute a Linux binary

The Windows node_repl.exe creates its sandboxed Node child through a Codex helper selected by CODEX_CLI_PATH. Pointing that variable to the Linux executable produced Windows error 193: the file was a valid Linux ELF, but not a valid Win32 application.

The platform-specific executable roles therefore had to diverge:

  • The WSL-hosted Codex caller uses the patched Linux executable.
  • The Windows MCP host uses the bundled Windows node_repl.exe.
  • The helper selected by the Windows MCP environment uses a Windows-native Codex executable.

I registered the command name codex-wsl-bridge on both platforms. WSL resolves it to the patched Linux build; Windows resolves it to the bundled PE. The generated configuration can therefore use one command name while each host runs the correct executable.

I kept the sandbox enabled. Disabling it also avoided the failing child process, but would have removed the isolation instead of fixing the executable boundary.

Dynamic imports needed Windows-valid module specifiers

The integration is installed as a plugin, but Windows Node loads the plugin's .mjs client with import(). Once Node started reliably, a module path discovered by the Linux process could still arrive as:

await import("/mnt/c/.../computer-use-client.mjs")

Windows Node needs a Windows-valid file URL:

await import("file:///C:/.../computer-use-client.mjs")

The installed plugin instructions convert this path during normal use. I also added a narrowly matched, trusted PreToolUse path-rewrite hook for deterministic enforcement. The hook changes only /mnt/<drive>/... string literals inside dynamic imports sent to the Node REPL. It leaves shell paths, Linux-native tools, and unrelated JavaScript unchanged. Codex records trust against the exact hook definition, so a later edit disables it until the new definition is reviewed.

Checks after the build

After the build and fresh-process repairs, all six WSL-to-Windows checks passed. Chrome required a separate recovery and browser test.

1. Direct MCP call

The original JavaScript probe ran and returned a Windows working directory. The mapped sandboxCwd had passed request validation.

2. Plain CLI process from a Windows-mounted workspace

A new non-interactive codex process started from /mnt/c/..., reached the Windows Node runtime, and completed a Computer Use bootstrap without receiving a corrected path manually.

3. Plain CLI process from the native WSL filesystem

I repeated the fresh-process test from a native WSL directory. It reached the same sandboxed Windows runtime and returned the same Computer Use inventory. This checked both workspace URI mappings rather than proving only the /mnt/c case.

4. Deliberately raw plugin import

I disabled the persistent mapping instruction for this probe, passed an exact raw /mnt/c/... dynamic import, and did not bypass hook trust. The trusted PreToolUse path-rewrite hook changed the call to file:///C:/... before Windows Node received it. The same import completed when the WSL-hosted CLI started from either a Windows-mounted workspace or the native WSL filesystem.

5. Computer Use application discovery

A read-only Computer Use discovery call returned 40 Windows applications. No app was launched or manipulated.

6. Post-restart acceptance check

The desktop app had been holding the previous Node transport in memory. After a full restart, the reopened app had a newer process start time and loaded the plugin client through file:///C:/.... A direct JavaScript probe returned a Windows working directory, and read-only Computer Use discovery again returned 40 applications. No app was launched or manipulated.

7. Chrome connection recovery and end-to-end check

Chrome still did not appear as an available browser after the sandboxCwd fix. These checks passed:

  • Chrome was installed and running.
  • The ChatGPT Chrome Extension was installed and enabled in the selected profile.
  • The native-messaging manifest was present and valid.

Chrome availability returned after I reinstalled the plugin, reopened Codex, opened one blank Chrome window in the selected profile, and retried the connection. I did not identify which component had gone stale, so this remains a recovery sequence rather than a second root-cause fix.

A later end-to-end check used Codex to open a tab in the selected Chrome profile. A separate local Manifest V3 prototype then applied a reviewed native tab-group plan without closing tabs or reading page content. The prototype was an acceptance exercise, not part of the sandboxCwd fix or a second root-cause diagnosis.

These were separate failures. The URI mapping restored MCP request transport and Computer Use. The Chrome sequence restored the browser connection, and the tab-opening check verified it with a real browser action.

What I would check first next time

I would use this order of diagnosis again:

  1. Run the smallest MCP call. If request validation fails before user code, UI selectors, tabs, and clicks are downstream of the failure.
  2. Name both processes. “Codex on Windows” hides the useful detail: a Codex app server in WSL was calling a Windows .exe over STDIO.
  3. Inspect tool-call metadata and process configuration separately. A valid executable and process cwd do not make a foreign sandboxCwd URI valid.
  4. Preserve the sandbox context. Translate its working-directory URI for the receiver instead of removing it.
  5. Build the exact release. Desktop integrations can depend on matching executables and protocol versions.
  6. Check each layer. Test the URI mapping, platform-specific executable resolution, the Windows sandbox helper, a raw plugin import, Computer Use discovery, and the restarted desktop app.
  7. Keep separate failures separate. A fixed MCP request path can expose a later plugin-session problem. After recovery, verify one real browser action instead of stopping at availability.

Status and caveat

As of July 10, 2026, openai/codex#29639 remains open, has no linked pull request, and upstream main does not contain this mapping. The commit is a public fork patch rather than an official release.

I kept a rollback copy, pinned the build to the installed Codex version, and would replace it with an upstream release once the same mapping ships there.

Credits

  • atlantho — published the anonymized reproduction in openai/codex#29639, including the native WSL /home/... case.
  • Nicolas0315 — wrote the focused WSL-to-Windows sandboxCwd mapping patch used for the compatibility build.
  • OpenAI Codex — its open-source request path made it possible to inspect, test, and build the matching release.
  • Codex agent — helped trace the request metadata and repeat the Computer Use checks after the patched build was installed.