Claude in Chrome is unusable from WSL sessions, and the desktop app forces a WSL runtime for WSL-path projects

Status Open
Reported on v2.1.260
Maintainer reply None cached
Activity 2 comments · opened Sep 9, 2026

Summary

On Windows + WSL2, the "Claude in Chrome" browser tools cannot be used at all. The Claude
desktop app spawns the agent into WSL whenever the project working directory is a WSL path,
and the Claude Code CLI then disables Claude in Chrome because it detects WSL. There is no
supported way to keep a WSL project path and still drive the desktop browser.

This is a regression in practice: the same projects previously ran in a native Windows session
where the browser tools worked.

Environment

| Item | Value |
|---|---|
| Host OS | Windows 11 |
| WSL | WSL2, Ubuntu-24.04 |
| WSL kernel | 6.18.33.2-microsoft-standard-WSL2 |
| Claude Code runtime | ~/.claude/remote/ccd-cli/2.1.260 (spawned by the desktop app) |
| Claude Code (WSL install) | ~/.local/share/claude/versions/2.1.233 |
| Chrome | 152.0.7977.83 (Windows) |
| Claude Chrome extension | fcoeoabgfenejglbffodgkkbkcdhcgfn v1.0.91 |
| WSL networking | NAT (default), not mirrored |

Impact

Any developer whose code lives on the WSL filesystem (the recommended layout for performance)
loses browser automation entirely. The only workarounds are to move the working directory to a
Windows path, or to abandon the built-in tools.

Root cause analysis

Four independent defects compound. Each was verified on this machine.

1. In WSL, the native messaging manifest is installed where Windows Chrome never looks

The CLI treats WSL as Linux for native-host installation. It writes the manifest to Linux
Chrome profile directories:

~/.config/google-chrome/NativeMessagingHosts/com.anthropic.claude_code_browser_extension.json
~/.config/microsoft-edge/NativeMessagingHosts/...
~/.config/chromium/NativeMessagingHosts/...

The browser that actually runs is Windows Chrome, which resolves native messaging hosts from
the Windows registry (HKCU\Software\Google\Chrome\NativeMessagingHosts), never from a Linux
profile directory. The manifests written are therefore dead files.

Relevant CLI logic (from ccd-cli 2.1.260), where WSL is folded into the Linux case:

case "linux": case "wsl":
  if (r.linux.nativeMessagingPath.length > 0)
    o.push({ browser: s, path: l(i, ...r.linux.nativeMessagingPath) });
  break;
case "windows": break;

2. Browser detection on WSL only looks for a Linux browser binary

case "wsl": case "linux": {
  for (let s of o.linux.binaries)          // ["google-chrome","google-chrome-stable"]
    if (await $a(s).catch(() => null)) return i;
  break;
}

On a normal WSL install there is no Linux Chrome, so detection fails even though Chrome is
installed and running on the Windows host a few microseconds away over interop.

3. Claude in Chrome is hard-gated off for WSL, and the gate cannot be satisfied

The CLI ships the user-facing string:

Claude in Chrome is not supported in WSL at this time.

Platform detection:

if (this.sources.env.WSL_DISTRO_NAME || this.sources.env.WSL_INTEROP) this.platform = "wsl";
else { let e = this.kernelString(); this.platform = P3t(e) ? "wsl" : "linux"; }

function P3t(e) { return e.includes("microsoft") || e.includes("wsl"); }

Because the fallback reads /proc/version, which on every WSL2 kernel contains
microsoft-standard-WSL2, this cannot be influenced by configuration or environment. The
feature is unreachable by design on WSL.

4. The extension's host probe returns on the first responder, so Desktop always wins

service-worker.ts-bMnDo4ez.js in extension 1.0.91:

const t = [
  { name: "com.anthropic.claude_browser_extension",      label: "Desktop"     },
  { name: "com.anthropic.claude_code_browser_extension", label: "Claude Code" }
];
for (const r of t) try {
  const e = chrome.runtime.connectNative(r.name), t = await new Promise(...);
  if (true === t) return Dr = e, ..., true;      // returns on first success
  ...
}

Whenever the Claude desktop app is installed, its host answers pong first and the loop
returns. com.anthropic.claude_code_browser_extension is never attempted, so a Claude Code
host cannot be reached even when it is correctly registered and working. Verified directly:
deleting the Desktop registry key caused the Claude Code host to be launched automatically
about 5 seconds after Chrome start; restoring the key suppressed it again.

Proof that the transport itself works

Defects 1, 2 and 4 are all fixable, and the underlying transport is sound. I built a working
bridge on this machine:

  • Registered com.anthropic.claude_code_browser_extension in the Windows registry
  • Pointed it at a small Windows .exe that execs

wsl.exe -d <distro> -u <user> -e <wrapper>, with stdio inherited

  • The wrapper runs claude --chrome-native-host inside WSL

Results:

  • wsl.exe passes stdio byte-identical (verified by round-tripping all 256 byte values),

so the 4-byte-length + JSON native messaging framing survives the boundary intact

  • Chrome launched the host and it replied {"type":"pong"}
  • The host created /tmp/claude-mcp-browser-bridge-<user>/<pid>.sock inside WSL with the

expected 0700 directory / 0600 socket permissions that the CLI's
validateSocketSecurity() requires

So the only thing left blocking use is defect 3, the explicit WSL gate. The plumbing works.

Steps to reproduce

  1. On Windows with WSL2, keep a project on the WSL filesystem (e.g. /home/<user>/projects/app).
  2. Open that folder in the Claude desktop app Code tab. The agent is spawned into WSL.
  3. Install the Claude Chrome extension in Windows Chrome and sign in.
  4. Ask the session to use any browser tool.

Expected: the browser tools are available and drive Windows Chrome.
Actual: no browser tools are registered in the session. No native host is ever launched.

Requested fixes

In rough priority order:

  1. Support WSL as a first-class host. When the platform is WSL, register the native

messaging host in the Windows registry with a launcher that shells through wsl.exe,
instead of writing dead manifests into Linux profile directories. This is demonstrably
workable — stdio is byte-transparent across the boundary.

  1. Do not return on the first responding host in the extension probe. Enumerate all hosts

and let the user (or the session) select the target. As written, installing the desktop app
permanently shadows Claude Code.

  1. Detect the Windows browser from WSL, via interop, rather than requiring a Linux browser

binary that will not exist in a normal WSL install.

  1. Let the user choose the runtime in the desktop app. Forcing a WSL runtime purely because

the working directory is a WSL path removes the only configuration that made this work.
A per-project runtime setting would solve this independently of the above.

  1. If WSL support genuinely cannot ship soon, surface the gate in the UI. Right now the

tools are silently absent; the "not supported in WSL" string is never shown in the Code tab,
so the failure looks like a broken install and invites hours of debugging.

Notes

Verification commands used, for anyone reproducing:

# does the WSL boundary preserve native messaging framing?
python3 -c "import sys;sys.stdout.buffer.write(bytes(range(256)))" > /tmp/b.bin
md5sum /tmp/b.bin
cat /tmp/b.bin | wsl.exe -d ubuntu-24.04 -e cat | md5sum   # identical

# did Chrome launch a Claude Code host?
ls -la /tmp/claude-mcp-browser-bridge-$USER/
ps -ef | grep chrome-native-host

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗