One-evening, production-grade dev environment for Windows 10 (2004+) and Windows 11 — a clean Windows host with all your development isolated in WSL2 Ubuntu.
Illustrative walkthrough — Stages 1–2 reproduced for pacing; the finale is real eza / git / lazygit.
wsl2-devkit provisions a fresh machine in four staged scripts: baseline Windows apps, WSL2 + Ubuntu, the full Linux dev toolchain, and VS Code — then hands you a one-command health check to prove it all worked.
Design principle: Windows stays clean. Editors, browsers and fonts live on Windows; every language runtime, linter and CLI tool lives in WSL2, where your code runs fast.
flowchart LR
A(["Fresh<br/>Windows 10/11"]) --> S0["Stage 0<br/>winget apps"]
S0 --> S1["Stage 1<br/>WSL2 + Ubuntu"]
S1 --> S2["Stage 2<br/>dev toolchain"]
S2 --> S3["Stage 3<br/>VS Code"]
S3 --> V{{"verify-setup.sh<br/>52 checks"}}
V --> DONE([Ready to code])
flowchart TB
subgraph WIN["Windows Host - clean"]
EDITOR["VS Code / Cursor<br/>+ Remote-WSL, themes, fonts"]
subgraph WSL["WSL2 - Ubuntu - all development"]
T["Node / Python / Go / Rust<br/>pnpm / uv / bun / lazygit / ripgrep / starship<br/>~/projects: web, python, go, rust, scripts, sandbox"]
end
end
EDITOR -. "code ." .-> WSL
wsl2-devkit/
├── windows/ # run from Windows PowerShell
│ ├── stage0-winget.ps1 # (optional) baseline Windows apps + Nerd Font
│ ├── stage1-windows.ps1 # enable WSL2 + install Ubuntu (Admin)
│ ├── stage3-vscode.ps1 # VS Code extensions + settings
│ └── wsl-tools.ps1 # backup / restore / clean / update / reset
├── wsl/ # run inside Ubuntu (WSL)
│ ├── stage2-ubuntu.sh # dev toolchain + shell config
│ └── verify-setup.sh # read-only health check
├── docs/
│ ├── OVERVIEW.md # what it is, who it's for, verify the claims
│ └── DOCUMENTATION.md # full reference guide
├── demo/ # VHS demo (make demo)
│ ├── devkit-demo.tape # walkthrough script
│ ├── devkit-demo.gif # rendered hero GIF (shown above)
│ └── lib/ # stage reproductions used by the walkthrough
├── tests/
│ └── profiles/ci.conf # selection profile for the CI smoke test
├── .github/workflows/ci.yml # ShellCheck + PSScriptAnalyzer + twice-run smoke
├── Makefile # make verify / lint / demo / help (run in WSL)
├── CONTRIBUTING.md # ground rules, local checks, supply-chain policy
├── SECURITY.md # private vulnerability reporting
├── AGENTS.md # machine context for AI coding assistants
├── CHANGELOG.md
└── LICENSE
| Stage | Script | Where | Time |
|---|---|---|---|
| 0 | windows/stage0-winget.ps1 |
PowerShell | ~5 min |
| 1 | windows/stage1-windows.ps1 |
PowerShell (Admin) | ~5 min |
| — | Restart, then create your Ubuntu user | — | ~3 min |
| 2 | wsl/stage2-ubuntu.sh |
Ubuntu terminal | ~10–15 min |
| 3 | windows/stage3-vscode.ps1 |
PowerShell | ~5 min |
| ✓ | wsl/verify-setup.sh |
Ubuntu terminal | ~10 sec |
Total: ~30 minutes. Stages run in order; each is idempotent (safe to re-run).
Important
Got the scripts as a ZIP download? Windows marks them as remote and RemoteSigned will refuse to run them ("not digitally signed"). Unblock once, from the extracted folder: Get-ChildItem -Recurse *.ps1 | Unblock-File. Also run from a local path (e.g. C:\...) — never from \\wsl.localhost\..., which always counts as remote. A git clone on the Windows side avoids all of this.
Installs browser, editor, Windows Terminal, Git, PowerToys, gsudo and the JetBrainsMono Nerd Font (so WSL CLI icons render). Self-elevates; skips anything already installed.
powershell -ExecutionPolicy Bypass -File .\windows\stage0-winget.ps1Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
.\windows\stage1-windows.ps1Note
On a fresh machine this stage runs twice: the first run enables the WSL features and asks for a reboot; Ubuntu installs on the second run.
Then open Ubuntu from the Start menu and create your username + password.
Clone this repo inside WSL (or copy wsl/stage2-ubuntu.sh into your home dir), then:
chmod +x stage2-ubuntu.sh
./stage2-ubuntu.sh # interactive: pick Node / Python / Go / Rust
exec $SHELL -l # reload your shell afterwardsTip
Stage 2 also runs fully non-interactive — the same path CI uses to test the kit:
./stage2-ubuntu.sh --yes # the menu's defaults, no prompts
./stage2-ubuntu.sh --all # everything (GPG key without passphrase)
./stage2-ubuntu.sh --profile my.conf # defaults + your INSTALL_*=true/false overrides
# git identity comes from existing git config, or GIT_NAME= / GIT_EMAIL= env varsInstalls UI extensions on Windows and pushes the workspace extensions into the WSL server.
.\windows\stage3-vscode.ps1bash wsl/verify-setup.sh # or: make verifyA green report means the machine is healthy; it exits non-zero if any required tool, shell hook, directory or credential is missing.
Languages — Node.js (LTS via nvm) + pnpm + bun · Python (pyenv) + uv + pipx · Go (official) · Rust (rustup, optional)
Modern CLI — eza · bat · ripgrep · fd · fzf · lazygit · zoxide · starship · gh · shellcheck
Security — Ed25519 SSH key · optional GPG signing key · sensible git defaults
VS Code — curated extensions installed into the WSL remote (language servers, linters, formatters, debuggers) with themes/Remote clients kept local
Project scaffolding helpers
newweb myapp # React + Vite + TypeScript
newpy myapp # Python + venv (uv)
newgo myapp # Go module
newrust myapp # Rust crateFrom the Ubuntu terminal — always work under ~/projects, then open the folder
in your editor over Remote-WSL:
cd ~/projects/web/my-app
code . # open in VS Code (connected to WSL)
cursor . # ...or CursorHandy aliases configured by Stage 2:
| Alias | Does |
|---|---|
p / projects |
cd ~/projects |
mkcd <dir> |
make a directory and cd into it |
z / zi |
smart cd (zoxide) / interactive pick |
lg |
lazygit |
gs / gl |
git status -sb / pretty git log |
gp / gpl |
git push / git pull |
ll / lt |
eza -la --icons --git / eza --tree --level=2 |
ni / nd / nb |
pnpm install / dev / build |
venv / activate |
create + activate / activate a Python venv |
reload |
source ~/.bashrc |
Full command and alias reference: docs/DOCUMENTATION.md.
.\windows\wsl-tools.ps1 status # versions, disk usage, config
.\windows\wsl-tools.ps1 backup # export distro (keeps 3 newest)
.\windows\wsl-tools.ps1 restore # restore from a backup (validated)
.\windows\wsl-tools.ps1 clean # clear caches + compact the VHD
.\windows\wsl-tools.ps1 update # update WSL + apt packages
.\windows\wsl-tools.ps1 reset # nuke + reinstall (typed confirmation)From WSL, make help lists the health-check and lint targets.
Important
Work in ~/projects, not /mnt/c/... — the Windows filesystem is slow across the WSL boundary.
These scripts run with your privileges — Stage 1 needs Administrator, and the WSL stages write your shell config, generate keys, and install toolchains. Read the code in windows/ and wsl/ before running it. What it does and doesn't do:
- No telemetry, no analytics, no phone-home. Nothing is uploaded anywhere.
- Keys stay local. The Ed25519 SSH key and optional GPG signing key are generated on your machine and never leave it — you paste the public half into GitHub yourself.
- Every vendor installer script is pinned and checksum-verified in-repo. apt uses signed repos. The Go release and all seven installer scripts (nvm, pyenv, uv, bun, rustup, starship, zoxide) are fetched from immutable tag/commit refs and verified against SHA256 hashes committed in this repo before a byte of them executes — a moved tag, truncated transfer, or compromised origin refuses to run. Where an installer downloads its payload at runtime (bun, starship, zoxide binaries; rustup toolchains), that payload is the vendor's latest signed release.
- CI-tested on every push. ShellCheck + PSScriptAnalyzer gate the scripts, and a GitHub Actions job runs the real Stage 2 twice on a clean Ubuntu runner, asserts the second run changes nothing, then passes the 52-check verifier.
- Idempotent and network-tolerant. Every stage is safe to re-run — the managed
~/.bashrcblock is replaced (not duplicated) between markers, and a flaky network on any single download degrades to a warning instead of aborting the run.
- Windows 10 version 2004 (build 19041) or later, or Windows 11
- Virtualization enabled in firmware (for WSL2)
- Administrator access for Stage 1
New to WSL2, or want the claims-you-can-verify summary? Start with docs/OVERVIEW.md. Full reference — every setting, the staging rationale, and troubleshooting — lives in docs/DOCUMENTATION.md. Version history is in CHANGELOG.md.
PRs welcome — see CONTRIBUTING.md for the ground rules (idempotency is CI-enforced) and local checks. Security issues go through private reporting, not the issue tracker.
Built with ❤️ by Eliran Cohen