-
Notifications
You must be signed in to change notification settings - Fork 0
Windows WSL2 Host
Windows can host a jam. Not natively — a native Windows host was investigated and dropped, because
nothing reattaches to a running ConPTY, so the person running the jam would be the one person stuck
on a slow proxied screen. The route is WSL2: tmux, claude, claude-jam and the daemon all run
inside the Linux distribution, and you sit in Windows Terminal looking at it.
From claude-jam's point of view that is a Linux host. Everything on Hosting a Jam applies unchanged. This page is only the four places where Windows is still visible.
Read this first. Nobody working on claude-jam has a Windows machine. Every decision on this page is unit-tested on macOS, Linux and Windows CI, and the WSL-specific behaviour —
wslpath, DrvFs, interop, localhost forwarding — has never been run on a real install.docs/COMPATIBILITY.mdin the repo says which is which, row by row, and there is a command that answers most of it on your machine:git clone --depth 1 https://github.com/roypadina/claude-jam ~/claude-jam-src node ~/claude-jam-src/scripts/check-wsl.mjsIt needs no
npm install— it imports only claude-jam's own pure modules — and it prints PASS / FAIL / NOT EXERCISED, one line per fact. It is not in the npm package on purpose (the published tarball carries no test scripts).If something here is wrong, that output is the bug report.
In Windows Terminal, on the Ubuntu (or other) profile — not PowerShell:
wsl --version # (run this one in PowerShell) WSL 2 and a recent kernelInside the distribution:
sudo apt update && sudo apt install -y tmux curl procps
node --version # >= 22. Install node INSIDE WSL, not the Windows one
claude --version # the Claude Code CLI, installed inside WSL
npm i -g claude-jam # or clone the repo
claude-jam --helpTwo things people get wrong here, both of which look like claude-jam being broken:
-
Install node and
claudeinside the distribution. A Windows node onPATHthrough interop will start, and then nothing that needs a pty will work properly. -
Run
claude-jamfrom a Linux directory (~/code/...), not from/mnt/c/.... See §2.
WSL gives you two filesystems, and they are not equivalent:
| what it is | use it for | |
|---|---|---|
/home/you/... |
the distribution's own ext4 | the jam, and ideally your project |
/mnt/c/... |
your Windows drive, mounted as DrvFs | files that have to be on Windows |
claude-jam refuses to put its state directory on a Windows drive, and it will tell you so:
refusing to use this jam's state dir /mnt/c/tmp/claude-jam-7777: its mode is 777, which grants
the group access — jam's state dir holds host.key and token.json, so it must be 0700.
/mnt/c/tmp/claude-jam-7777 is on Windows drive C:, mounted into WSL as DrvFs. Windows drives
cannot hold a private directory here: without the `metadata` mount option every file reports
mode 0777 and one owner, and `chmod` on such a mount reports success and changes nothing — so
neither chmod nor another --port can fix this.
That is not conservatism. The state directory holds host.key, which is host authority — a
process that can read it can type into your real Claude session — and a directory that reports
0777 cannot be told apart from one another user could reach. chmod will not help: on a DrvFs
mount without the metadata option it reports success and changes nothing.
The state directory is $TMPDIR/claude-jam-<port>, and $TMPDIR inside WSL is /tmp, which is on
the Linux side. So this only bites you if you have set TMPDIR yourself. If you have:
unset TMPDIR # or
claude-jam host --state ~/.claude-jam-stateYour project can stay on /mnt/c. Only the state directory must not. Working from /mnt/c is
slower and file-watching is less reliable — that is WSL, not claude-jam — but it works, and
jam-uploads/ lands there fine.
Windows and Linux name the same file differently, and you will paste both kinds. claude-jam
translates the Windows spellings for /send:
| you type | it opens |
|---|---|
/send C:\Users\you\shot.png |
/mnt/c/Users/you/shot.png |
/send \\wsl$\Ubuntu\home\you\notes.md |
/home/you/notes.md |
/send ~/notes.md, /send ./x.png
|
unchanged |
/send \\wsl$\Debian\home\you\x |
refused — that is another distribution, not mounted here |
/send \\fileserver\team\x.docx |
refused — a Windows network share is not mounted in WSL |
Going the other way, to open something from Windows: a file at /home/you/proj/jam-uploads/a.png
is \\wsl$\Ubuntu\home\you\proj\jam-uploads\a.png in Explorer, and explorer.exe . from inside
the distribution opens the current directory in Windows.
/paste reads the Windows clipboard through interop, so Win+Shift+S then /paste in your
client works the way it does on a Mac. If interop is off you get a line saying so, and /send
still works. (Unverified: see the warning at the top.)
This is the part where WSL2 being a virtual machine behind NAT shows. When you start a jam the join block says so:
Send this to a friend:
invite: claude-jam join ws://172.28.144.3:7777 --name <You> --token …
from Windows on this PC: claude-jam join ws://localhost:7777 --name <You> --token …
this jam runs in WSL2 (Ubuntu), so the addresses above are the VM's. Windows on this PC
reaches it on localhost; another machine needs mirrored networking, a portproxy, or --tunnel.
| who | how | notes |
|---|---|---|
| you, from Windows Terminal | the localhost line |
WSL2 forwards localhost into the VM by default (localhostForwarding in %USERPROFILE%\.wslconfig) |
| you, inside WSL | either line | it is all one machine |
| anyone else, over the internet | claude-jam host --tunnel |
a relay dials out, so NAT is irrelevant. This is the reliable answer |
| anyone else, on your LAN | mirrored networking, or a portproxy | see below |
For a LAN guest you need one of:
# .wslconfig, Windows 11 22H2+ — the clean way. Restart WSL after (wsl --shutdown).
[wsl2]
networkingMode=mirrored# or forward one port, as Administrator. The WSL IP changes on every boot, so this needs redoing.
netsh interface portproxy add v4tov4 listenport=7777 listenaddress=0.0.0.0 `
connectport=7777 connectaddress=(wsl hostname -I).Trim()
New-NetFirewallRule -DisplayName "claude-jam 7777" -Direction Inbound -LocalPort 7777 -Protocol TCP -Action AllowIf you use --view, its port needs the same treatment; the join block prints its localhost URL
for you.
--funnel needs Tailscale installed inside the distribution — the Windows Tailscale cannot
serve a port that lives in the VM. --funnel is unverified on every platform (see
Remote Access).
LAN discovery (claude-jam find) does not work here, and says so: it needs Apple's dns-sd,
which Linux does not have. Use an invite link.
Run these in order. Each is a command and an expected observation, and the first one does most of the work.
| # | where | command | expected |
|---|---|---|---|
| 1 | WSL |
node ~/claude-jam-src/scripts/check-wsl.mjs (see the clone line above) |
all checks passed. Every FAIL line names what it measured — that is the bug report |
| 2 | WSL | claude-jam host --name You --cwd ~/somewhere |
the jam starts; the join block carries the from Windows on this PC: line |
| 3 | Windows Terminal (PowerShell) | curl.exe -s -m 3 http://localhost:7777/health |
{"ok":true,...} — this is localhost forwarding, and it is a claim until you run it |
| 4 | Windows | claude-jam join ws://localhost:7777 --name You2 --token <token> |
a second client joins; you see the same screen twice |
| 5 | WSL |
/send C:\Windows\System32\drivers\etc\hosts in the host client |
it is offered — the path was translated |
| 6 | WSL | copy an image (Win+Shift+S), then /paste
|
the image is offered. A refusal naming interop is also a result — write down which |
| 7 | another machine | curl -s -m 3 http://<windows-ip>:7777/health |
refused/timeout is expected unless you did §4. Says which |
| 8 | WSL |
claude-jam host --tunnel …, then join from a phone |
this is the path that should not need any of §4 |
| 9 | WSL |
claude-jam end <name>, then claude-jam sessions
|
gone, and no state directory left |
If step 1 prints NOT EXERCISED for wslpath, you are not in WSL — check you are on the Ubuntu
profile and not PowerShell.
-
LAN discovery is unsupported (no
dns-sdon Linux). Invite links work. - The state directory cannot be on a Windows drive. §2.
-
A LAN guest needs mirrored networking or a portproxy.
--tunnelneeds neither. -
/mnt/cis slow and its file-watching is unreliable. That is WSL. -
None of this has been run on a real Windows machine. The repo's
docs/COMPATIBILITY.mdsays so row by row, andscripts/check-wsl.mjsis how that changes.