Claude Code on WSL

Verify, maintain, and remove the setup

This repository preserves a WSL2 + Windows Terminal setup. Linux checks cover scripts and documentation; Windows notifications, clipboard integration, and terminal input still need testing on a real WSL2 installation.

For a read-only report on an installation, run bash scripts/doctor.sh from the cloned repository. It compares installed scripts with the repository copies, inspects Claude Code and Codex settings, and flags known conflicts. It writes nothing and does not test Windows GUI behavior.

Before changing configuration

Install one feature at a time and keep your existing settings. Save a copy of each file you will edit. For example, before changing Claude Code settings:

if [ -f ~/.claude/settings.json ]; then
  cp --backup=numbered ~/.claude/settings.json ~/.claude/settings.json.bak
fi

Do the same for a script, shell startup file, keybindings file, or service unit before replacing it. For Windows Terminal and VSCode, save copies through Windows before editing. Record the settings you add so removal does not affect other tools.

Merge JSON objects and append only the required array entries. Do not replace an existing settings file with a small example from a guide. After editing, check JSON:

jq empty ~/.claude/settings.json

For JSON files with comments, use the application’s editor/validator instead of plain jq. Restart the relevant application and confirm it loads the change.

Check each installed feature

Component Check after installation Remove or restore
Statusline Run the sample payload, then open Claude Code and inspect available fields Remove this statusLine setting, restore any previous setting/script, and delete the installed script only if unused
Notifications Send a forced test balloon, test foreground suppression, then trigger a hook event Remove only handlers calling this script; retain the script while Codex or tmux uses it
Screenshot paste Check the user service, paste a screenshot, and repeat after restarting WSL Disable the service before deleting its unit; remove only the added keybinding and unused binary
LSP Check each selected server’s executable/version, then navigate to a definition with Claude Disable the selected plugins; remove server binaries only if your editor does not need them
Browser routing Test both the quoted BROWSER executable and xdg-open Restore the previous environment setting and HTTP/HTTPS handlers before removing the desktop file
Terminal titles Open a fresh zsh tab and check directory and command titles Remove the added _wt_* functions, their two add-zsh-hook registrations, and the added environment export; restore previous terminal/agent title settings and start a fresh shell
Shift+Enter Type two lines in Claude Code; Shift+Enter should insert a newline Remove only the added binding in Windows Terminal or VSCode, or restore the binding you replaced; reopen the terminal
CapsLock remap Check that CapsLock acts as Escape after signing in again Delete only that mapping in SharpKeys, write to the registry, then sign out and back in
Attribution preference Check the next commit/PR you request from Claude Restore the previous values, or remove the added fields to use defaults
tmux helper Run the disposable job below and inspect its exit status and log Let jobs finish; remove the helper if unused, retaining logs/state until no longer needed

For a tmux smoke check, choose a session name not already in use. From the cloned repository, with tmux and setsid available:

bash bin/tmux-notify-run setup-check -- /bin/echo 'setup check'
# After the job finishes:
bash bin/tmux-notify-run --status setup-check
cat "${XDG_STATE_HOME:-$HOME/.local/state}/tmux-notify-run/setup-check/job.log"

Expect exit=0 and setup check in the log. A missing notification script does not fail the job; verify Windows delivery separately. The helper creates files under the state directory above and can reuse a finished session name, replacing that job’s state/log, so use a dedicated name for this check.

Optional integrations

WSL2 verification status

The setup was used daily on WSL2 until the move to Ubuntu + Ghostty, documented on 2026-09-08. No per-guide Windows, WSL, or Claude Code versions were recorded then. These later changes pass the Linux checks but have not been run on WSL2:

Guide Changed since 2026-09-08 Check on WSL2
Notifications Script moved to bin/ with a configurable PowerShell path and --force validation (2026-09-08); text passed base64-encoded and a 12 s exit limit (2026-10-15) Forced balloon, foreground suppression, click-to-focus, no tray icon left behind
Codex notification Uses the notification script above A completed turn whose reply contains ’
tmux helper Log finished before the status is written (2026-10-15) One job’s completion balloon
Screenshot paste Pinned, checksum-verified install (2026-10-15) Paste, then paste again after wsl --shutdown
Browser routing WSL-form paths, a symlink for paths with spaces, and a check for xdg-open’s built-in WSL support (2026-10-23) "$BROWSER" and xdg-open with a symlinked Program Files browser
Figma Desktop MCP Mirrored networking requirement (2026-10-15) /mcp connects with mirrored networking

After testing a guide on WSL2, add a line below with the date, the guides, and the Windows, WSL, distro, terminal, and Claude Code versions. bash scripts/doctor.sh prints most of them.

Automated checks

Requires Bash 4.4+, Python 3.11+, Git, and jq. Checks that need tmux, zsh, PowerShell 7 (pwsh), or shellcheck are skipped when the tool is missing. From the cloned repository:

bash scripts/check.sh

The same command runs in GitHub Actions, which provides every optional tool and sets CHECKS_REQUIRE_ALL=1 so nothing is skipped:

The notification tests do not run Windows PowerShell or display a balloon. Passing CI does not certify Windows interoperability, GUI behavior, third-party installers, or configuration loading in a live Claude Code session.

To report a WSL2 issue, use the issue form and include the output of bash scripts/doctor.sh.