🪟 WSL¶
A WSL distro is a Linux userland without the pieces a desktop Linux takes for granted: no local SSH agent holding your keys, and no graphical browser. This repo wires up both, guarded so nothing leaks into a native Linux or macOS session.
SSH keys live in 1Password¶
In WSL your SSH private keys are not on the Linux side at all — they live in
1Password on the Windows host. Rather than forwarding an agent socket, the
1Password WSL integration forwards the whole SSH request to the
Windows OpenSSH client (ssh.exe), which talks to the 1Password SSH agent and
raises the approval prompt on Windows.
What is configured automatically¶
| Concern | How | Where |
|---|---|---|
| Git over SSH | core.sshCommand = ssh.exe |
dot_config/git/config.tmpl |
Interactive ssh / ssh-add |
aliased to ssh.exe / ssh-add.exe |
dot_config/shell/functions/wsl-ssh.sh, dot_config/fish/conf.d/wsl-ssh.fish |
| Commit signing | gpg.ssh.program = op-ssh-sign-wsl.exe |
dot_config/git/config.tmpl (see git-signing.md) |
The aliases are guarded on WSL_DISTRO_NAME and on ssh.exe being
reachable, so they never leak into a native Linux or macOS session and stay
inert if WSL interop is disabled.
Prerequisites¶
- 1Password for Windows installed and signed in on the Windows host.
- The 1Password SSH agent enabled there.
- Your SSH key stored in 1Password.
Verify the agent is reachable from inside WSL:
You should see the same keys as on Windows. If you get command not found,
either use the full path /mnt/c/Windows/System32/OpenSSH/ssh-add.exe or check
that [interop] enabled = true in your WSL config.
Commit signing¶
Signing in WSL runs through op-ssh-sign-wsl.exe on the Windows host, driven
by the gitSigningKey chezmoi variable. The setup is shared with the other
platforms, so it lives in git-signing.md — use the
Configure for Windows Subsystem for Linux (WSL) option when copying the
snippet out of the 1Password app.
Note
useYubiKey = true takes precedence: that flow signs with a FIDO2 key from
~/.ssh/id_*_sk*.pub and ignores gitSigningKey. See
yubikey.md.
SSH config lives on Windows¶
Because the request is executed by ssh.exe, host aliases and options must be
in the Windows %USERPROFILE%\.ssh\config, not the WSL one.
Authorization model¶
Approving a key authorizes the current WSL session only. A new session or tab prompts again — the same authorization model 1Password uses everywhere else.
Opening links in a browser¶
A WSL distro has no browser of its own, and no xdg-open. Anything that opens
one — gh auth login, OAuth flows, npm docs — looks for xdg-open or
$BROWSER, and when neither points anywhere useful it falls back to whatever
terminal browser happens to be installed. Completing an OAuth flow in lynx is
not a good time.
~/.local/bin/wsl-browser hands the URL to Windows via powershell.exe
Start-Process, which opens it in the real default browser. BROWSER is
pointed at it, which fixes every tool at once instead of configuring them one
at a time.
| Concern | How | Where |
|---|---|---|
| Opening a URL | powershell.exe Start-Process |
dot_local/bin/executable_wsl-browser |
$BROWSER |
exported when running under WSL | dot_config/shell/functions/wsl-browser.sh, dot_config/fish/conf.d/wsl-browser.fish |
Guarded on WSL_DISTRO_NAME and on powershell.exe being reachable, so it
stays inert on a native Linux session or when interop is disabled.
Two deliberate choices in that script:
- It only accepts
http(s)URLs or files that exist.Start-Processis Windows' general "run this" verb, not a browser — handedcalc.exeor a path to an executable, it would run it. Since$BROWSERis invoked by other programs, anything else is refused rather than quietly launched. - The URL is passed through
WSLENV, not interpolated into the PowerShell command string, so a URL containing quotes or semicolons is always data and never code.
Why not wslu?¶
wslu provides wslview, which does the same job and would be the
obvious dependency. It was archived upstream in 2025 — last
release 4.1.3, April 2024 — and it is not packaged for Debian 13. Installing an
unmaintained .deb outside apt is worse than shipping the few lines above.
If it ever returns to the archives, wslview is a drop-in replacement: point
BROWSER at it and delete the script.
Check it¶
If a tool still opens a terminal browser it is probably remembering its own
setting — gh, for example, has gh config set browser. Clear it with
gh config set browser "" and let $BROWSER win.
What does not work in WSL¶
1Password shell plugins (op plugin run) are unsupported under WSL, so the
gh / copilot wrappers are not applied there. See
1password-shell-plugins.md.