You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Agreed - I don't personally have any windows computers to test on but I would love to see a PR for support. It can't be that hard to support it, although windows has a much weirder shell environment which might cause issue
I did a pass over the codebase to scope this out. Here's what a native Windows port actually runs into.
One piece of good news up front: @anthropic-ai/claude-code-win32-x64 is already published on npm (v2.1.229), and src/main/json-claude-manager.ts:135-144 already maps win32-x64/win32-arm64 → claude.exe. So the Chat-tab binary resolution story is essentially done. node-pty also supports Windows via ConPTY.
Real blockers
Area
Where
Problem
Shell resolution
src/main/user-shell.ts:13-21
Hardcoded /bin/zsh → /bin/sh candidate list; the final fallback is a path that cannot exist on Windows
Login-shell flags
user-shell.ts:26 + 7 callsites
-ilc is bash/zsh-only. Used by json-claude-manager, editor, auto-approver, worktree setup scripts, github-auth, path-fix, and XTerminal
PTY default shell
pty-manager.ts:152
command || env.SHELL || '/bin/zsh' — $SHELL is unset on Windows
Hooks
hooks.ts:22,50-56
/tmp/harness-status plus an inline POSIX script wrapped in bash -c. This is the entire status-detection backbone — no hooks means no processing/waiting/needs-approval states
Process kill
pty-manager.ts:387-393
process.kill(-pid, …) process-group signalling; POSIX-only (relies on setsid())
Approval bridge
approval-bridge.ts:94-104
Unix domain socket; Windows needs a named pipe (\\.\pipe\…)
Shell activity polling
pty-manager.ts:315
Shells out to ps -A -o pid=,ppid=,comm=
PATH merge
path-fix.ts:100-112
Splits/joins on : instead of path.delimiter; whole function is also gated behind process.platform !== 'darwin' early-return
Packaging
package.json build block
No win section, no .ico (only .icns/.png), no dist:win script, no windows-latest CI job
Headless packaging
scripts/pack-headless.mjs:45-60,215-227
Platform detection covers only darwin-arm64/linux-x64/linux-arm64; the launcher shim is a #!/bin/sh script; output is .tar.gz
Dev/release scripts
scripts/release.sh, smoke-headless.sh, install-headless.sh, several package.json scripts
Bash-only, with hardcoded ~/Library/Application Support paths and tail -F/rm -f/awk/mktemp
The difficulties worth flagging
1. Verification is the actual bottleneck, not the code. Nobody on this thread has a Windows machine. A port touches ~25 files across shell spawning, PTY lifecycle, hooks IPC, sockets, and packaging, and none of it is verifiable past "it compiles and packages." Whatever lands first will need a volunteer with a Windows box to validate it — so it should ship explicitly labeled experimental, and CI should at minimum prove it typechecks, tests, and produces an installer on windows-latest.
2. The hooks rewrite is the load-bearing risk.makeHookCommand emits an inline POSIX shell script, and /tmp/harness-status doubles as the dedupe signature that agents/{claude,codex,cursor}.ts use to recognize Harness-installed hook entries. Changing that path naively means Harness stops recognizing hooks it already installed on existing macOS setups and starts appending duplicates on every re-install. The cleanest fix is probably replacing the inline script with a small shipped JS hook invoked via ELECTRON_RUN_AS_NODE (there's precedent — resources/mcp-bridge.js already ships as extraResources), which would simplify all three platforms rather than forking the script per-OS. But it's a rewrite of the status-detection backbone, so it wants its own PR.
3. The -ilc assumption is spread thin across the codebase. It isn't one function — it's a convention baked into eight call sites plus the renderer. This wants a src/main/platform/ abstraction (shell resolution, command-wrapping args, PATH delimiter, kill strategy, status dir, socket-vs-pipe) that everything routes through. Upside: that layer is pure logic and can be unit-tested on macOS, so most of the port becomes verifiable without a Windows machine.
4. Code signing. There's no Windows certificate today. Unsigned NSIS installers trigger SmartScreen warnings for every user. That's a call to make before any Windows artifact goes on a release: ship unsigned-and-documented, or hold Windows releases until there's a cert.
5. Graceful-degradation candidates. Shell activity polling (ps) and the .claude settings symlink (Windows needs Developer Mode or admin for symlinks) are both non-essential. Better to degrade cleanly on Windows — skip the poller, fall back to a file copy — than to block the port on them.
6. There's a cheaper interim answer. Harness already has a headless server plus a web client. A Windows user can run harness-server under WSL2 today and drive it from a browser, which covers a meaningful chunk of this issue for the cost of a docs paragraph rather than a port. Worth doing regardless of whether the native port happens.
Activity
frenchie4111 commentedon Aug 3, 2026
Agreed - I don't personally have any windows computers to test on but I would love to see a PR for support. It can't be that hard to support it, although windows has a much weirder shell environment which might cause issue
frenchie4111 commentedon Aug 13, 2026
I did a pass over the codebase to scope this out. Here's what a native Windows port actually runs into.
One piece of good news up front:
@anthropic-ai/claude-code-win32-x64is already published on npm (v2.1.229), andsrc/main/json-claude-manager.ts:135-144already mapswin32-x64/win32-arm64→claude.exe. So the Chat-tab binary resolution story is essentially done.node-ptyalso supports Windows via ConPTY.Real blockers
src/main/user-shell.ts:13-21/bin/zsh→/bin/shcandidate list; the final fallback is a path that cannot exist on Windowsuser-shell.ts:26+ 7 callsites-ilcis bash/zsh-only. Used by json-claude-manager, editor, auto-approver, worktree setup scripts, github-auth, path-fix, and XTerminalpty-manager.ts:152command || env.SHELL || '/bin/zsh'—$SHELLis unset on Windowshooks.ts:22,50-56/tmp/harness-statusplus an inline POSIX script wrapped inbash -c. This is the entire status-detection backbone — no hooks means no processing/waiting/needs-approval statespty-manager.ts:387-393process.kill(-pid, …)process-group signalling; POSIX-only (relies onsetsid())approval-bridge.ts:94-104\\.\pipe\…)pty-manager.ts:315ps -A -o pid=,ppid=,comm=path-fix.ts:100-112:instead ofpath.delimiter; whole function is also gated behindprocess.platform !== 'darwin'early-returnpackage.jsonbuild blockwinsection, no.ico(only.icns/.png), nodist:winscript, nowindows-latestCI jobscripts/pack-headless.mjs:45-60,215-227#!/bin/shscript; output is.tar.gzscripts/release.sh,smoke-headless.sh,install-headless.sh, severalpackage.jsonscripts~/Library/Application Supportpaths andtail -F/rm -f/awk/mktempThe difficulties worth flagging
1. Verification is the actual bottleneck, not the code. Nobody on this thread has a Windows machine. A port touches ~25 files across shell spawning, PTY lifecycle, hooks IPC, sockets, and packaging, and none of it is verifiable past "it compiles and packages." Whatever lands first will need a volunteer with a Windows box to validate it — so it should ship explicitly labeled experimental, and CI should at minimum prove it typechecks, tests, and produces an installer on
windows-latest.2. The hooks rewrite is the load-bearing risk.
makeHookCommandemits an inline POSIX shell script, and/tmp/harness-statusdoubles as the dedupe signature thatagents/{claude,codex,cursor}.tsuse to recognize Harness-installed hook entries. Changing that path naively means Harness stops recognizing hooks it already installed on existing macOS setups and starts appending duplicates on every re-install. The cleanest fix is probably replacing the inline script with a small shipped JS hook invoked viaELECTRON_RUN_AS_NODE(there's precedent —resources/mcp-bridge.jsalready ships asextraResources), which would simplify all three platforms rather than forking the script per-OS. But it's a rewrite of the status-detection backbone, so it wants its own PR.3. The
-ilcassumption is spread thin across the codebase. It isn't one function — it's a convention baked into eight call sites plus the renderer. This wants asrc/main/platform/abstraction (shell resolution, command-wrapping args, PATH delimiter, kill strategy, status dir, socket-vs-pipe) that everything routes through. Upside: that layer is pure logic and can be unit-tested on macOS, so most of the port becomes verifiable without a Windows machine.4. Code signing. There's no Windows certificate today. Unsigned NSIS installers trigger SmartScreen warnings for every user. That's a call to make before any Windows artifact goes on a release: ship unsigned-and-documented, or hold Windows releases until there's a cert.
5. Graceful-degradation candidates. Shell activity polling (
ps) and the.claudesettings symlink (Windows needs Developer Mode or admin for symlinks) are both non-essential. Better to degrade cleanly on Windows — skip the poller, fall back to a file copy — than to block the port on them.6. There's a cheaper interim answer. Harness already has a headless server plus a web client. A Windows user can run
harness-serverunder WSL2 today and drive it from a browser, which covers a meaningful chunk of this issue for the cost of a docs paragraph rather than a port. Worth doing regardless of whether the native port happens.Comment left on behalf of @frenchie4111 by Claude via Harness.