| id | GUIDE-TPL-WINDOWS-DEV-001 | |||||
|---|---|---|---|---|---|---|
| title | Windows Development Guide | |||||
| doc_type | how-to | |||||
| status | published | |||||
| audience | developers, windows-users | |||||
| tags |
|
|||||
| stories |
|
|||||
| requirements |
|
|||||
| acs |
|
|||||
| adrs |
|
|||||
| last_updated | 2025-11-26 |
Comprehensive guide to developing with the Rust-as-Spec Platform Cell on Windows.
This guide covers both WSL2 (recommended) and native Windows (Tier-2) development paths, with detailed troubleshooting, workarounds, and best practices.
Are you on a team?
→ Yes: Use WSL2 + Nix (Tier 1) ✅
→ No: Continue below
Do you need canonical validation (pre-commit, PRs, releases)?
→ Yes: Use WSL2 + Nix (Tier 1) ✅
→ No: Continue below
Can you install WSL2?
→ Yes: Use WSL2 + Nix (Tier 1) ✅
→ No: Use native Windows (Tier 2) ⚠️
Want fastest iteration for solo dev?
→ Yes: Native Windows (Tier 2) acceptable ⚠️
→ No: WSL2 + Nix recommended ✅
Bottom Line:
- Team/CI/Production: WSL2 + Nix (Tier 1) mandatory
- Solo rapid prototyping: Native Windows (Tier 2) acceptable with caveats
Why this is the recommended path:
- Full Tier 1 validation (all selftest steps pass)
- Matches CI environment exactly
- No Windows file locking issues
- Faster builds (native Linux filesystem performance)
- Team consistency (same environment across all developers)
- Windows 10 version 2004+ or Windows 11
- Admin rights (for initial WSL2 installation)
- ~5GB free disk space
# PowerShell as Administrator
wsl --install
wsl --set-default-version 2If WSL is already installed:
# Check WSL version
wsl --list --verbose
# If showing WSL 1, upgrade to WSL 2
wsl --set-version Ubuntu-22.04 2Reboot if prompted.
# Install Ubuntu 22.04 (recommended)
wsl --install -d Ubuntu-22.04
# Or list available distributions
wsl --list --onlineFirst-time setup:
- WSL will prompt for a username and password
- This is your Linux user account (independent from Windows)
- Choose a simple username (e.g., your Windows username)
# Start WSL2
wsl
# Update Ubuntu packages (optional but recommended)
sudo apt update && sudo apt upgrade -y
# Install Nix with Determinate Systems installer
curl --proto '=https' --tlsv1.2 -sSf -L \
https://install.determinate.systems/nix | \
sh -s -- install --determinate
# Restart shell to load Nix
exit
wslVerify Nix installation:
nix --version
# Expected: nix (Nix) 2.18.x or later/mnt/c/
# ✅ CORRECT: WSL2 native filesystem (fast)
cd ~
git clone https://github.com/EffortlessMetrics/Rust-Template.git
cd Rust-Template
# ❌ WRONG: Windows filesystem via WSL2 (slow)
cd /mnt/c/Users/YourName/Code
git clone ... # DON'T DO THISWhy location matters:
| Location | Performance | Why |
|---|---|---|
/home/username/ |
✅ Fast (native Linux I/O) | Direct ext4 filesystem access |
/mnt/c/Code/... |
❌ 10-50x slower | 9P network protocol overhead |
Impact:
- Native filesystem: 2-5 minute builds
- Windows filesystem via
/mnt/c/: 10-30 minute builds
# Enter devshell (downloads packages on first run, ~5-10 minutes)
nix develop
# Verify environment
cargo xtask doctor
# Run full selftest (Tier 1 canonical validation)
cargo xtask selftestExpected output:
✅ [1/7] Core checks (fmt, clippy, tests)
✅ [2/7] BDD acceptance tests
✅ [3/7] AC status mapping & ADR references
✅ [4/7] LLM context bundler
✅ [5/7] Policy tests
✅ [6/7] DevEx contract
✅ [7/7] Graph invariants
🎉 All selftest phases passed!
Install VS Code on Windows:
# Download from https://code.visualstudio.com/
# Or via winget
winget install Microsoft.VisualStudioCodeInstall WSL Extension:
- Open VS Code
- Install "Remote - WSL" extension (ms-vscode-remote.remote-wsl)
- Restart VS Code
Open project in WSL:
# Inside WSL2
cd ~/Rust-Template
code .This opens VS Code with:
- Files accessed directly from WSL2 (fast)
- Terminal runs in WSL2 (Linux shell)
- Extensions run in WSL2 context
- Rust Analyzer works natively
Recommended VS Code Extensions (install in WSL context):
- rust-analyzer
- Even Better TOML
- Cucumber (Gherkin) Full Support
- EditorConfig
Daily development:
# Start WSL2
wsl
# Navigate to project
cd ~/Rust-Template
# Enter devshell
nix develop
# Start service
cargo run -p app-http
# Run tests
cargo test
# Before commit
cargo xtask selftestHybrid workflow (Windows + WSL2):
# Edit files in Windows IDE (files stored in WSL2)
# VS Code with Remote-WSL handles this transparently
# Validate in WSL2 before commit
wsl -e bash -c "cd ~/Rust-Template && nix develop -c cargo xtask selftest"Cause: Repository cloned in /mnt/c/ (Windows filesystem)
Fix:
# Move to WSL2 native filesystem
cd ~
git clone https://github.com/EffortlessMetrics/Rust-Template.git
cd Rust-TemplateCause: Docker Desktop WSL2 integration not enabled
Fix:
- Install Docker Desktop for Windows
- Open Docker Desktop settings
- General → Enable "Use the WSL 2 based engine"
- Resources → WSL Integration → Enable for Ubuntu-22.04
- Restart Docker Desktop
Verify:
# Inside WSL2
docker --version
docker psCause: Shell profile not reloaded
Fix:
# Source Nix profile
source ~/.nix-profile/etc/profile.d/nix.sh
# Or restart WSL
exit
wslCause: WSL2 default memory limit (50% of total RAM)
Fix: Create .wslconfig to limit memory:
# In Windows PowerShell
notepad $env:USERPROFILE\.wslconfigAdd:
[wsl2]
memory=4GB
processors=4Restart WSL:
wsl --shutdown
wslWindows files are mounted at /mnt/c/:
# Access Windows C:\Users\YourName\Documents
cd /mnt/c/Users/YourName/Documents
# Copy from Windows to WSL2
cp /mnt/c/Users/YourName/file.txt ~/Note: Editing Windows files from WSL2 is slow. Copy to WSL2 first.
When to use this path:
- Cannot install WSL2 (corporate restrictions, old Windows version)
- Solo development with fast iteration needs
- Acceptable to use WSL2 for final validation before PRs
- Steps 1-6 of selftest pass reliably
- Step 7 may intermittently fail with
os error 5(file locking) - Does NOT match CI environment (Tier 1 uses Nix)
- Requires manual tool installation
- Not recommended for team development
- Windows 10 version 2004+ or Windows 11
- Admin rights (for tool installation)
- ~3GB free disk space
Option A: rustup-init.exe (Recommended)
# Download from https://rustup.rs/
# Or via winget
winget install Rustlang.Rustup
# Follow installer prompts
# Choose default options when asked
# Verify installation
rustc --version
cargo --versionExpected output:
rustc 1.91.x or later
cargo 1.91.x or later
Option B: Manual installation
- Download rustup-init.exe from https://rustup.rs/
- Run as Administrator
- Follow prompts (default options)
- Restart PowerShell/terminal
# Via winget
winget install Git.Git
# Or download from https://git-scm.com/download/winImportant: Git for Windows includes sh.exe, which is required for Git hooks to work.
Verify:
git --version
# Expected: git version 2.x.x or later# Install cargo-binstall for faster binary installations
cargo install cargo-binstall
# Install conftest
cargo binstall conftestVerify:
conftest --version
# Expected: Conftest: 0.x.xIf conftest installation fails:
- Download from https://github.com/open-policy-agent/conftest/releases
- Extract to
C:\Program Files\conftest\conftest.exe - Add to PATH: System Properties → Environment Variables → Path
# Clone to a path WITHOUT spaces
cd C:\Code
git clone https://github.com/EffortlessMetrics/Rust-Template.git
cd Rust-Template
# ❌ AVOID: Paths with spaces (causes issues)
# cd "C:\Users\Your Name\My Documents\Code"# Check environment
cargo run -p xtask -- doctor
# Run Tier 2 validation
cargo run -p xtask -- check
cargo test --workspace --exclude acceptanceExpected output from doctor:
- ✅ Rust toolchain detected
- ✅ Git detected
⚠️ Nix not available (expected on Tier 2)- ✅ conftest detected (if installed)
The Problem:
During cargo xtask selftest, xtask rebuilds itself. On Windows, if xtask.exe is locked by another process, the rebuild fails with:
error: failed to remove `target\debug\xtask.exe`
Access is denied. (os error 5)
This is NOT a test failure. It's a Windows platform limitation.
Root Cause:
Windows does not allow deleting or replacing an executable that is currently in use. Unix systems allow this (the file is unlinked but the running process continues).
Who locks the file:
- Antivirus (most common): Windows Defender or third-party AV scans new executables immediately
- File Explorer: Thumbnail generation or Windows Search indexing
- IDE: Rust Analyzer, VS Code background analysis
- Previous cargo process: Not fully terminated
Windows Defender (built-in):
# PowerShell as Administrator
Add-MpPreference -ExclusionPath "C:\Code\Rust-Template\target"Verify exclusion:
Get-MpPreference | Select-Object -ExpandProperty ExclusionPathThird-party antivirus:
- Open antivirus settings (e.g., Norton, McAfee, Kaspersky)
- Navigate to "Exclusions" or "Exceptions"
- Add
C:\Code\Rust-Template\target\as an excluded directory
Why this works:
- Antivirus no longer scans executables as they're built
- Eliminates ~90% of file locking issues
- Safe:
target/contains only build artifacts (not source code)
Security tradeoff:
- Executables in
target/are not scanned by antivirus - Acceptable for development (you control the source code)
- Do NOT exclude production binary directories
When to use:
- Before creating a PR
- Before merging to main
- For release preparation
- When selftest MUST pass cleanly
Workflow:
# Daily dev: native Windows (fast iteration)
cargo run -p app-http
cargo test
# Before commit: WSL2 (canonical validation)
wsl -e bash -c "cd ~/Rust-Template && nix develop -c cargo xtask selftest"Setup WSL2 alongside native Windows:
- Follow WSL2 setup steps above
- Keep both environments
- Use native Windows for speed, WSL2 for certainty
Quick fix for one-off validation:
# Close all running cargo and xtask processes
taskkill /F /IM cargo.exe
taskkill /F /IM xtask.exe
# Wait 5 seconds for processes to fully terminate
timeout /t 5
# Retry selftest
cargo run -p xtask -- selftestWhen to use:
- One-off validation when antivirus exclusion isn't possible
- Corporate policy prevents excluding directories
- WSL2 not available
Limitations:
- Not reliable for CI/automation
- May require multiple retries
- Doesn't fix root cause
For fast iteration (not for final validation):
# Run only specific checks (bypasses selftest rebuild)
cargo run -p xtask -- check
cargo test --workspace --exclude acceptance
cargo run -p xtask -- bddWhen to use:
- Daily development loop
- Quick feedback before full selftest
- Known file locking environment
Do NOT use:
- Before creating PR (run full selftest in WSL2)
- For canonical validation (use Tier 1)
Use this testing ladder on native Windows:
# 1. Fast checks (no rebuild issues)
cargo run -p xtask -- check
# 2. Run specific tests
cargo test -p app-http
# 3. BDD scenarios
cargo run -p xtask -- bdd
# 4. Full selftest (may hit file locking on step 7)
cargo run -p xtask -- selftest
# If step 7 fails with "os error 5":
# → This is file locking, NOT a test failure
# → Use WSL2 for canonical validationCause: File locking (see Windows File Locking Issue)
Fix: See Workarounds for File Locking
Cause: Line endings converted to CRLF
Symptom:
error: cannot spawn .git/hooks/pre-commit: No such file or directory
Fix:
# In Git Bash
dos2unix .git/hooks/pre-commit
# Or reinstall hooks
cargo run -p xtask -- install-hooksPrevention:
# Configure Git to use LF for shell scripts
git config --global core.autocrlf inputSymptom:
[5/7] Policy tests ⚠️ skipped (conftest not found)
Fix:
# Install conftest
cargo install cargo-binstall
cargo binstall conftest
# Verify
conftest --versionSymptom:
error: failed to run custom build command for `openssl-sys`
Cause: Windows doesn't ship OpenSSL
Fix (Option A): Use prebuilt OpenSSL (recommended)
# Install vcpkg (C++ package manager)
git clone https://github.com/microsoft/vcpkg.git C:\vcpkg
cd C:\vcpkg
.\bootstrap-vcpkg.bat
# Install OpenSSL
.\vcpkg install openssl:x64-windows-static
# Set environment variable
$env:OPENSSL_DIR = "C:\vcpkg\installed\x64-windows-static"Fix (Option B): Use rustls instead
- Some crates offer
rustlsfeature flag (pure Rust TLS) - Check
Cargo.tomlfordefault-features = false, features = ["rustls"]
Fix (Option C): Use WSL2
- WSL2 has OpenSSL via Nix devshell
- No Windows-specific setup required
Cause: Visual Studio Build Tools not installed
Fix:
# Download and install Visual Studio Build Tools
# https://visualstudio.microsoft.com/downloads/
# Or via winget
winget install Microsoft.VisualStudio.2022.BuildTools
# During installation, select:
# - "Desktop development with C++"
# - Windows 10/11 SDKAlternative: Install full Visual Studio Community (larger download)
Symptom:
error: could not execute process `cargo build`
The system cannot find the path specified.
Cause: Repository cloned to path with spaces (e.g., C:\Users\Your Name\Code\)
Fix:
# Move repository to path without spaces
cd C:\
mkdir Code
cd Code
git clone https://github.com/EffortlessMetrics/Rust-Template.git
cd Rust-TemplateGit hooks work identically on Windows, but there are platform-specific considerations.
Key Insight: Git for Windows includes a POSIX compatibility layer (sh.exe, bash.exe).
When you run cargo xtask install-hooks, it generates a POSIX shell script:
#!/usr/bin/env bash
cargo xtask checkOn Windows:
- Git automatically delegates hook execution to
sh.exe - Works from PowerShell, CMD, and Git Bash
- No
.bator.cmdversion needed
# Install pre-commit hook (works on all platforms)
cargo run -p xtask -- install-hooksVerify:
# Check hook exists
ls .git/hooks/pre-commit
# Check shebang
gc .git/hooks/pre-commit -Head 1
# Expected: #!/usr/bin/env bash| Shell | How Hook Runs | Expected Behavior |
|---|---|---|
| PowerShell | Git calls sh.exe internally |
✅ Works automatically |
| CMD | Git calls sh.exe internally |
✅ Works automatically |
| Git Bash | Direct POSIX execution | ✅ Works automatically |
You don't need to do anything special. Git for Windows handles POSIX hooks natively.
Diagnosis:
# Try manual execution
.\.git\hooks\pre-commitIf error: "command not found" or "No such file or directory":
# Check if Git for Windows is installed (includes sh.exe)
where sh.exe
# Expected: C:\Program Files\Git\usr\bin\sh.exe
# If not found, install Git for Windows
winget install Git.GitIf hook file doesn't exist:
# Reinstall hooks
cargo run -p xtask -- install-hooksCause: Cargo not in PATH when Git runs the hook
Fix:
# Check cargo PATH
where cargo
# Expected: C:\Users\YourName\.cargo\bin\cargo.exe
# If not found, add to PATH:
# 1. Open System Properties → Environment Variables
# 2. User Variables → Path → Edit
# 3. Add: C:\Users\YourName\.cargo\bin
# 4. Restart PowerShell/terminalSymptom:
error: cannot spawn .git/hooks/pre-commit
Cause: Git converted LF to CRLF (Windows default)
Fix:
# In Git Bash
dos2unix .git/hooks/pre-commit
# Or reinstall
cargo run -p xtask -- install-hooksPrevention:
# Configure Git to preserve LF for shell scripts
git config --global core.autocrlf inputTemporary bypass:
# Skip hook for one commit
git commit --no-verify -m "fix: emergency hotfix"--no-verify for emergencies. Fix the underlying issue afterward.
Proper fix:
- Investigate why hook is failing
- Run
cargo xtask checkmanually - Fix the failures
- Commit normally (without
--no-verify)
The template's CI pipeline treats Windows differently:
# .github/workflows/ci-template-selftest.yml
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
include:
- os: ubuntu-latest
tier: "Tier 1 (Linux + Nix)" # BLOCKING
- os: macos-latest
tier: "Tier 1 (macOS + Nix)" # BLOCKING
- os: windows-latest
tier: "Tier 2 (Windows native)" # INFORMATIONALLinux/macOS CI (Tier 1):
- name: Run selftest
run: nix develop -c cargo xtask selftest- All 7 selftest steps must pass
- Blocks PR merge if failing
- Matches local Tier 1 environment exactly
Windows CI (Tier 2):
- name: Build xtask
run: cargo build -p xtask
- name: Run checks
run: cargo run -p xtask -- check
- name: Run tests
run: cargo test --workspace --exclude acceptance --exclude xtask- Does NOT run full selftest (avoids file locking)
- Does NOT block PR merge
- Informational only (catches obvious Windows-specific breakage)
- File locking is non-deterministic: Same code can pass/fail based on antivirus timing
- No quality signal: File locking failure doesn't indicate code problems
- Tier 1 is canonical: If Tier 1 passes, the code is correct
If Windows CI fails:
- Check if it's file locking (
os error 5) → ignore - Check if it's a real test failure → investigate
- Real failures are rare (Tier 1 catches them first)
Required checks (blocks merge):
- ✅
tier1-selftest / selftest(Linux + Nix)
Optional checks (informational):
- ℹ️
template-selftest / Tier 2 (Windows native)
How to verify:
- GitHub repository → Settings → Branches
- Branch protection rule for
main - "Require status checks to pass before merging"
- Only
tier1-selftest / selftestis required
| Test/Command | Tier 1 (WSL2/Nix) | Tier 2 (Native Windows) |
|---|---|---|
cargo build |
✅ Always works | ✅ Always works |
cargo test |
✅ All tests pass | ✅ All tests pass |
cargo clippy |
✅ Matches CI | ✅ May have version drift |
cargo fmt |
✅ Matches CI | |
xtask check |
✅ Always passes | ✅ Always passes |
xtask bdd |
✅ Always passes | ✅ Always passes |
xtask policy-test |
✅ Always passes | ✅ If conftest installed |
xtask selftest (steps 1-6) |
✅ Always passes | ✅ Always passes |
xtask selftest (step 7) |
✅ Always passes | os error 5 |
| Git hooks | ✅ Always work | ✅ Always work (via Git for Windows) |
| Docker integration | ✅ Via Docker Desktop | ✅ Via Docker Desktop |
Legend:
- ✅ Fully supported, no issues
⚠️ Supported with known caveats- ℹ️ Informational, not blocking
Test: Clean build of workspace (cargo build --workspace --release)
| Environment | Time | Notes |
|---|---|---|
| WSL2 (native FS) | 2-5 min | Fastest, Tier 1 canonical |
| Native Windows (SSD) | 3-6 min | Slightly slower, Tier 2 |
WSL2 (/mnt/c/) |
10-30 min | ❌ Extremely slow, DO NOT USE |
| macOS (M1/M2) | 2-4 min | Fast, Tier 1 canonical |
| Linux (native) | 2-5 min | Fast, Tier 1 canonical |
Key Takeaway: WSL2 is as fast as native Linux IF you clone into WSL2 native filesystem (/home/).
Test: Full selftest (cargo xtask selftest)
| Environment | Time | Notes |
|---|---|---|
| Tier 1 (WSL2/Nix) | 5-10 min | All 7 steps, canonical |
| Tier 2 (Native Windows) | 5-12 min | May fail on step 7 (file locking) |
| Tier 1 (Linux CI) | 6-12 min | Includes Nix setup, caching helps |
Report these to the template maintainers:
- ✅ Tests that pass on Linux/macOS but fail on Windows (logic error)
- ✅ Windows-specific compilation errors (missing dependencies)
- ✅ Path handling bugs (backslash vs forward slash)
- ✅ Docs that are incorrect or incomplete for Windows
- ✅ Hook installation that fails on Windows (not CRLF issues)
These are expected Windows behavior, not bugs:
- ❌
os error 5during selftest step 7 (file locking) - ❌ Slower builds on Windows (inherent platform difference)
- ❌ Antivirus scanning binaries (configure exclusions)
- ❌ Nix not available on native Windows (use WSL2)
- ❌ CRLF line ending issues (configure Git:
core.autocrlf = input)
Use GitHub Issues with [windows] prefix:
Title: [windows] cargo test fails with "path not found" error
**Environment:**
- OS: Windows 11 Pro 23H2
- Rust: 1.91.0
- Tier: Native Windows (Tier 2)
- Antivirus: Windows Defender
**Steps to reproduce:**
1. Clone repository to C:\Code\Rust-Template
2. Run `cargo test -p app-http`
3. See error: ...
**Expected behavior:**
Tests should pass (they pass on WSL2/Linux)
**Actual behavior:**
Error: path not found ...
**Workaround attempted:**
- Tried WSL2: Tests pass there
- Tried excluding from antivirus: No changeInclude:
- Windows version (
winvercommand) - Rust version (
rustc --version) - Tier (native Windows or WSL2)
- Full error message
- Whether issue reproduces in WSL2 (if applicable)
Daily iteration:
# Fast feedback loop
cargo run -p app-http
cargo test
cargo run -p xtask -- checkBefore commit:
# Option A: Native Windows (may hit file locking)
cargo run -p xtask -- selftest
# Option B: WSL2 (canonical, always passes)
wsl -e bash -c "cd ~/Rust-Template && nix develop -c cargo xtask selftest"Recommended: Set up WSL2 alongside native Windows. Use native Windows for speed, WSL2 for certainty.
Setup:
- All team members use WSL2 + Nix
- Ensures consistency across team
- Matches CI exactly
Workflow:
# All work in WSL2
wsl
cd ~/Rust-Template
nix develop
# Daily dev
cargo run -p app-http
cargo test
# Before push
cargo xtask selftest
git pushResult:
- "Works on my machine" eliminated
- PRs rarely fail CI (local matches CI)
- No platform-specific debugging
Setup:
- Use native Windows for fast iteration
- Use WSL2 for canonical validation
Workflow:
# Daily dev (native Windows)
cd C:\Code\Rust-Template
cargo run -p app-http
cargo test
cargo run -p xtask -- check
# Before PR (WSL2)
wsl
cd ~/Rust-Template
nix develop
cargo xtask selftest
exit
# If green, push from Windows
git pushBenefits:
- Fast iteration (native Windows)
- Canonical validation (WSL2)
- Best of both worlds
| Aspect | WSL2 + Nix (Tier 1) | Native Windows (Tier 2) |
|---|---|---|
| Setup time | 10 min | 15 min |
| Selftest guarantee | All 7 steps ✅ | Steps 1-6 ✅, step 7 |
| CI match | Exact | Partial |
| Build speed | Fast (native FS) | Moderate |
| File locking | Never | Occasionally |
| Nix available | ✅ | ❌ |
| Team recommended | ✅ Yes | ❌ No |
| Solo acceptable | ✅ Yes | |
| Git hooks | ✅ | ✅ |
| Docker | ✅ | ✅ |
Use WSL2 + Nix (Tier 1) if:
- ✅ You're on a team
- ✅ You need canonical validation
- ✅ You're contributing to the template
- ✅ You want to match CI exactly
- ✅ You can install WSL2
Use native Windows (Tier 2) if:
⚠️ You're doing solo rapid prototyping⚠️ You can't install WSL2 (corporate restrictions)⚠️ You're willing to use WSL2 for final validation⚠️ You accept file locking risk
- For teams: Always use Tier 1 (WSL2 + Nix)
- For CI/CD: Only Tier 1 is canonical
- For solo dev: Tier 2 acceptable for daily work; validate in WSL2 before PR
- For production releases: Tier 1 mandatory
- Platform Support Reference - Complete platform support matrix
- MISSING_MANUAL.md - Operational realities, including Windows specifics
- ADR-0017: Tier-1 Selftest Gate - Why Tier 1 is canonical
- Development Environment Setup - General setup guide
- CI Coverage Reference - What CI validates
Last Updated: 2025-11-30 (v3.3.6)