anthropics / anthropics/claude-code

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

Open
#93,124 1 comment 0 reactions 0 assignees View on GitHub
area:browser-extension bug has repro platform:wsl
Dominant language
Python
Stars
145k
Forks
23.1k
PR merge metrics
PR metrics pending

Description

## 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:

```js
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

```js
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:

```js
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:

```js
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 -u -e `, 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-/.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//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.
2. **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.
3. **Detect the Windows browser from WSL**, via interop, rather than requiring a Linux browser
binary that will not exist in a normal WSL install.
4. **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.
5. 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:

```bash
# 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
```

Contributor guide

No contributing guide indexed for this repository

Research direction

Start by reproducing the Windows 11 and WSL2 steps, then inspect the ccd-cli 2.1.260 platform-detection and native-host installation paths described in the report. Trace service-worker.ts-bMnDo4ez.js and run the supplied byte-framing and host-probe checks. Done means a WSL-path project session exposes browser tools in Windows Chrome without requiring a Windows-path workaround.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, linux, shell, ubuntu
Domain
cli, desktop, operating-systems
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
28/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.