wsly Mihai Valentin
Install wsly with WinGet
winget install --id=MihaiValentin.wsly -e Runs a command in an interactive WSL Bash session so Bash startup configuration and shell functions are available, optionally keeping the shell open on success.
winget install --id=MihaiValentin.wsly -e Runs a command in an interactive WSL Bash session so Bash startup configuration and shell functions are available, optionally keeping the shell open on success.
wsly runs a command inside an interactive WSL Bash session, then leaves
that session open when the command succeeds.
It exists for commands and shell functions that are configured only by an
interactive Bash startup file. A direct call does not load that configuration,
so this fails when project-jump is a shell function:
wsl project-jump api
# /bin/bash: line 1: project-jump: command not found
After installing wsly, this both loads the shell function and leaves you in
the selected project:
wsly project-jump api
wsl.exedocker-desktop do not include Bash and are not supported.~/.bashrc.From this checkout, in PowerShell:
Set-ExecutionPolicy -Scope Process Bypass
.\install.ps1
The installer copies wsly.ps1 to %LOCALAPPDATA%\wsly\bin and adds that
directory to the current user's PATH. Open a new PowerShell window after the
install.
Each tagged release includes a portable wsly-.zip, a per-user
wsly--setup.exe installer, and a SHA-256 checksum for each asset.
Download an asset and its matching .sha256 file from the GitHub Release, then
verify it before opening or extracting it:
Get-FileHash .\wsly--setup.exe -Algorithm SHA256
Get-Content .\wsly--setup.exe.sha256
The two hashes must match. Run the verified setup EXE for a standard install,
or extract the ZIP, open PowerShell in the extracted wsly-
directory, then run the installation commands above.
To build and verify the same archive locally before publishing a tag, run from WSL or another Bash environment:
powershell -ExecutionPolicy Bypass -File scripts/package-release.ps1
It writes both distributable assets and checksums to dist/ and refuses to
overwrite an existing release build. The Bash packager remains available for
building only the portable ZIP on Linux. When Windows PowerShell runs this
command from a WSL UNC checkout, it writes to a versioned folder under
%TEMP% instead; the script prints that folder when it finishes.
To replace an existing install:
Set-ExecutionPolicy -Scope Process Bypass
.\install.ps1 -Force
To install without adding the completion bridge to your PowerShell profile:
Set-ExecutionPolicy -Scope Process Bypass
.\install.ps1 -NoCompletion
Set-ExecutionPolicy -Scope Process Bypass
.\uninstall.ps1
The uninstaller removes wsly's files, PATH entry, and only the profile line
marked as wsly's completion integration. Use -KeepPath or
-KeepCompletionProfileEntry to preserve either setting.
wsly chooses the WSL launcher at runtime; it does not embed a machine-specific
path. It uses this order:
WSLY_WSL_EXE, when you explicitly set it.%SystemRoot%\System32\wsl.exe, the native Windows launcher.wsl.exe or wsl application on PATH.That deliberately prefers the native launcher over a WindowsApps execution
alias. For an unusual installation or compatible replacement launcher, set an
override before calling wsly:
$env:WSLY_WSL_EXE = ''
wsly project-jump api
The override may also be the name of an application already on PATH.
wsly project-jump api
wsly project-jump api deploy
wsly git status
With no arguments, wsly behaves like wsl and opens your default WSL shell.
Print the installed launcher version with:
wsly --version
To run a command with your interactive Bash configuration but remain in
PowerShell when it finishes, use -NoShell (or its short form, -n):
wsly -n cdp ls
wsly -NoShell git status
This mode streams the command's output and returns its exit code, but does not open the successful command's follow-on WSL shell.
To print a timing breakdown for helper-path resolution and WSL Bash execution,
use -Timing (or -t). This is useful when diagnosing a slow WSL startup,
shell configuration, or command:
wsly -n -t cdp ls
When you have more than one WSL distro, select the target explicitly:
wsly -Distro Ubuntu cdp ls
wsly -Distro Debian -n git status
Arguments are passed as individual command words, rather than assembled into a shell string. Quote an argument in PowerShell when it contains spaces.
wsly does not change PowerShell's working directory. Windows and WSL are
separate processes; instead, it opens a WSL shell whose directory was changed
by the command.
For an ordinary interactive call, wsly immediately displays a short startup
message while WSL and Bash are initializing. -NoShell stays silent so it can
be used cleanly in scripts, and Tab completion never writes status text into
its candidate list.
To suppress wsly's startup message for an interactive call, use -Quiet (or
-q). This does not suppress the command's output, errors, or -Timing
results:
wsly -q cdp nexus
The installer adds a small wsly completion bridge to your PowerShell profile.
It exposes wsly as a PowerShell function and, after opening a new PowerShell
window, pressing Tab after wsly cdp asks WSL to run the Bash completion
registered for cdp. Its configured choices are then offered by PowerShell.
It works with Bash completion functions defined or loaded by ~/.bashrc.
Run install.ps1 -Force to add completion to an existing installation. By
default, PowerShell cycles candidates when you press Tab. To display its
completion menu instead, add this to your PowerShell profile:
Set-PSReadLineKeyHandler -Key Tab -Function MenuComplete
The first Tab press for a distro starts WSL to obtain candidates; wsly caches its helper path for the rest of the PowerShell session and caches identical completion requests for 10 seconds. Completion definitions that depend on an interactive terminal, terminal UI, or Bash readline internals may not be portable through the bridge.
wsly is not recognized: open a new PowerShell window after installing,
then run Get-Command wsly. Confirm %LOCALAPPDATA%\wsly\bin is on your
user PATH.~/.bashrc; wsly sources
that file before it runs your command.-Distro and
verify available names with wsl --list --verbose. Select a user-facing
Linux distro with Bash, not an internal distro such as docker-desktop.Set-ExecutionPolicy -Scope Process Bypass; .\install.ps1 -Force, open a
new PowerShell window, then confirm Get-Command wsly reports Function.WSLY_WSL_EXE to a
compatible launcher path for the current PowerShell session.The repository's CI parses the PowerShell launcher on Windows and runs shell-level contract tests for the Bash helper on Linux. Run the helper tests locally with:
bash tests/test-wsly-bash.sh
The final integration check requires a real Windows host with WSL installed:
.\install.ps1 -Force
wsly
The launcher is intentionally one file and has no dependencies beyond WSL.
The installed launcher is accompanied by a small Bash helper. wsly translates
that helper's path for the active WSL distro, starts interactive Bash with the
helper, and passes your command as individual arguments. The helper explicitly
sources ~/.bashrc, then runs the command and opens a shell on success.
This avoids passing Bash program text through PowerShell's native-command argument marshalling. The behavior is equivalent to:
If the requested command fails, wsly returns that exit code instead of
opening a new shell.
Contributions from humans and coding agents are welcome. Agent-assisted pull requests are held to the same standard as every other contribution: the person opening the pull request is responsible for understanding it, testing it, and responding to review feedback.
See CONTRIBUTING.md for the workflow, then follow the Code of Conduct.