WSL Agent Skills & AI Rules

GitHub

Windows Subsystem for Linux

33,381 stars C++ C++ 1 file Β· ~6,773 tokens
RAW Rules
6 Discovered Rules β€’ ~11,250 Estimated Tokens
Loading skill content...

GitHub Copilot Instructions

.github/copilot-instructions.md copilot-instructions ~4,986 tokens
Raw
# Windows Subsystem for Linux (WSL)

**ALWAYS reference these instructions first and fallback to search or bash commands only when you encounter unexpected information that does not match the info here.**

WSL is the Windows Subsystem for Linux - a compatibility layer for running Linux binary executables natively on Windows. This repository contains the core Windows components that enable WSL functionality.

## Coding Conventions

### Naming

- **Classes/Structs**: `PascalCase` (e.g., `ConsoleProgressBar`, `DeviceHostProxy`)
- **Functions/Methods**: `PascalCase()` (e.g., `GetFamilyName()`, `MultiByteToWide()`)
- **Member variables**: `m_camelCase` (e.g., `m_isOutputConsole`, `m_outputHandle`)
- **Local variables**: `camelCase` (e.g., `distroGuidString`, `asyncResponse`)
- **Constants**: `c_camelCase` with `constexpr` (e.g., `constexpr size_t c_progressBarWidth = 58;`)
- **Namespaces**: lowercase with `::` nesting (e.g., `wsl::windows::common::registry`)
- **Enums**: `PascalCaseValue` (e.g., `LxssDistributionStateInstalled`)
- **Windows types**: Keep as-is (`LPCWSTR`, `HRESULT`, `DWORD`, `ULONG`, `GUID`)

### Error Handling

Use WIL (Windows Implementation Libraries) macros β€” **never** bare `if (FAILED(hr))`:
- `THROW_IF_FAILED(hr)` β€” throw on HRESULT failure
- `THROW_HR_IF(hr, condition)` β€” conditional throw
- `THROW_HR_IF_MSG(hr, condition, fmt, ...)` β€” conditional throw with message
- `THROW_IF_NULL_ALLOC(ptr)` β€” throw on null allocation
- `THROW_LAST_ERROR_IF(condition)` β€” throw last Win32 error
- `RETURN_IF_FAILED(hr)` β€” return HRESULT on failure (no throw)
- `RETURN_LAST_ERROR_IF_EXPECTED(condition)` β€” expected failure path
- `LOG_IF_FAILED(hr)` β€” log but don't throw
- `CATCH_LOG()` β€” catch and log exceptions

For user-facing errors, set a localized message before throwing:
```cpp
THROW_HR_WITH_USER_ERROR(E_INVALIDARG, Localization::MessageConfigInvalidBoolean(name, value));
```

At API boundaries (COM interfaces), return `HRESULT` with out params. Internal code throws exceptions.

### Memory Management and RAII

Use WIL smart pointers β€” **never** raw `CloseHandle()` or manual cleanup:
- `wil::unique_handle` β€” kernel handles
- `wil::com_ptr<T>` β€” COM objects
- `wil::unique_hfile` β€” file handles
- `wil::unique_hkey` β€” registry keys
- `wil::unique_event` β€” events
- `wil::unique_hlocal_string` β€” HLOCAL strings
- `wil::unique_cotaskmem_string` β€” CoTaskMem strings

For non-standard resource types, use `wil::unique_any<Type, Deleter, Fn>`.

For cleanup scopes, use `wil::scope_exit`:
```cpp
auto cleanup = wil::scope_exit([&] { registry::DeleteKey(LxssKey, guid.c_str()); });
// ... work ...
cleanup.release(); // dismiss on success
```

### Synchronization

Use `wil::srwlock` (Slim Reader/Writer locks) with SAL annotations:
```cpp
mutable wil::srwlock m_lock;
_Guarded_by_(m_lock) std::vector<Entry> m_entries;
```

### Strings

- `std::wstring` / `std::wstring_view` are dominant throughout the codebase
- Use `MultiByteToWide()` / `WideToMultiByte()` from `stringshared.h` for conversions
- Use `std::format()` for formatting (the repo defines `std::formatter<std::wstring, char>` for wide-to-narrow support)
- The `STRING_TO_WIDE_STRING()` macro handles compile-time conversion

### Copy/Move Semantics

Use macros from `defs.h` to declare copy/move behavior:
```cpp
NON_COPYABLE(MyClass);
NON_MOVABLE(MyClass);
DEFAULT_MOVABLE(MyClass);
```

### Headers

- Use `#pragma once` (no traditional `#ifndef` include guards)
- In Windows C++ components, every `.cpp` file must start with `#include "precomp.h"`
- Linux-side code (`src/linux/`) does not use precompiled headers
- Use `.h` for C-compatible headers, `.hpp` for C++-only headers
- Include order is enforced by `.clang-format` (precomp first, then system, then project)

### Copyright Headers

Use this single-line format for new files:
```cpp
// Copyright (C) Microsoft Corporation. All rights reserved.
```

Some older files use the block format (`/*++ Copyright (c) Microsoft. All rights reserved. ... --*/`). Match the surrounding files in the same directory when editing.

### Localization

- Use `wsl::shared::Localization::MessageXxx()` static methods for user-facing strings
- Use `EMIT_USER_WARNING(Localization::MessageXxx(...))` for non-fatal config warnings
- All new user-facing strings must have entries in `localization/strings/en-US/Resources.resw`
- In Resources.resw comments, use `{Locked="..."}` to prevent translation of `.wslconfig` property key names
- Localized files are generated by a separate localization team and regenerated downstream, so translation edits in a GitHub PR cannot be merged (they would be overwritten). This covers the per-locale `localization/strings/<locale>/Resources.resw` UI strings and the per-locale `intune/<locale>/WSL.adml` policy templates (anything other than the `en-US` sources and the neutral `intune/WSL.admx`). Filing a GitHub issue is the correct path for contributors; see `CONTRIBUTING.md`. Ignore this guidance for automated localization-service PRs that are generated by that pipeline.
- Community localization reports come in as **both GitHub issues and pull requests** - when triaging, look for both and file a tracking Bug for each. These are tracked via Bugs in the GCS Azure DevOps project, not merged directly. See `.github/copilot/localization-bugs.md` for the project coordinates, required fields, and `az boards` workflow.

### Telemetry and Logging

- `WSL_LOG(Name, ...)` β€” standard trace event
- `WSL_LOG_DEBUG(Name, ...)` β€” debug-only (compiled out in release via `if constexpr`)
- `WSL_LOG_TELEMETRY(Name, Tag, ...)` β€” metrics with privacy tag and version info
- Provider: `g_hTraceLoggingProvider`, initialized via `WslTraceLoggingInitialize()`

### Platform Conditionals

Prefer `constexpr` checks over `#ifdef` where possible:
```cpp
if constexpr (wsl::shared::Debug) { /* debug-only code */ }
if constexpr (wsl::shared::Arm64) { /* ARM64-specific code */ }
```

For compiler-specific code, use `#ifdef _MSC_VER` (Windows) / `#ifdef __GNUC__` (Linux).

### Formatting

Enforced by `.clang-format`:
- 130 character column limit
- 4-space indentation, no tabs
- Allman-style braces (opening brace on new line for classes, functions, structs, control statements)
- Left-aligned pointers (`int* ptr`, not `int *ptr`)
- `InsertBraces: true` β€” all control statements must have braces

### IDL / COM Conventions

When modifying service interfaces (`src/windows/service/inc/`):
- Interface attributes on separate lines: `[uuid(...), pointer_default(unique), object]`
- String params: `[in, unique] LPCWSTR` with `[string]` for marshaled strings
- Handle params: `[in, system_handle(sh_file)] HANDLE`
- User-facing errors: pass `[in, out] LXSS_ERROR_INFO* Error`
- **ABI stability applies only to SDK-facing and public surfaces.** `WSLCCompat.idl` (the WSLC SDK-facing layer) and the public plugin API (`WslPluginApi.h`) must stay backward compatible: do not add, remove, or reorder methods on their existing interfaces, and do not change struct layouts. Introduce a new versioned interface with a new IID instead. Every other interface (`IWSLCSession` in `wslc.idl`, the interfaces in `wslservice.idl`, etc.) is internal and non-stable: rebuilt and shipped in lockstep with its only clients, so appending new methods to those is fine.
- Custom error codes: `WSL_E_xxx` via `MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, WSL_E_BASE + N)`

### Config File (.wslconfig) Conventions

When adding settings to `src/shared/configfile/`:
- Format is `.gitconfig`-style INI: `[section]`, `key = value`, `#` comments, `\` line continuation
- Use the `ConfigKey` template class for type-safe parsing
- Supported types: `bool`, `int` (hex/octal), `std::string`, `std::wstring`, `MemoryString`, `MacAddress`, enum maps
- Report invalid values with `EMIT_USER_WARNING(Localization::MessageConfigXxx(...))`
- New settings require a corresponding localization string in Resources.resw

## Architecture

- `wsl.exe` is a thin entry point into `src/windows/common/WslClient.cpp`. Client commands reach the SYSTEM `wslservice.exe` through the internal COM interfaces in `src/windows/service/inc/wslservice.idl`; `LxssUserSession` owns per-user distribution operations.
- For WSL2, the service creates/manages the VM through HCS in `WslCoreVm.cpp` and communicates over hvsockets with Linux `mini_init`. `mini_init` configures the VM, starts `gns` for networking, and launches a per-distribution `init`; the service's `WslCoreInstance` talks to that `init` to launch sessions. The session leader launches a relay and the requested Linux process; Windows client I/O is relayed over hvsockets. Shared wire messages live in `src/shared/inc/lxinitshared.h` and use `SocketChannel`.
- `src/windows/wslc/` contains the container CLI, `src/windows/wslcsession/` the container session process, and the service hosts its session manager; their internal interface is `wslc.idl`. The SDK-facing compatibility contract is separate (`WSLCCompat.idl`). See `doc/docs/technical-documentation/index.md` and `boot-process.md` for the process and boot diagrams.

## Repository Navigation

### Key Directories
- `src/windows/` β€” Main Windows WSL service components
- `src/linux/` β€” Linux-side WSL components
- `src/shared/` β€” Shared code between Windows and Linux
- `test/windows/` β€” Windows-based tests (TAEF framework): `common/`, `wsl/`, `wslc/`, `testplugin/`
- `test/linux/unit_tests/` β€” Linux unit test suite
- `doc/` β€” Documentation source (MkDocs)
- `tools/` β€” Build and deployment scripts
- `distributions/` β€” Distribution validation and metadata
- `localization/` β€” Localized string resources

### Namespace β†’ Directory Map

| Namespace | Location |
|---|---|
| `wsl::shared::` | `src/shared/` |
| `wsl::windows::common::` | `src/windows/common/` |
| `wsl::windows::service::` | `src/windows/service/exe/` |
| `wsl::core::` | `src/windows/service/exe/` |
| `wsl::core::networking::` | `src/windows/common/` + `src/windows/service/exe/` |
| `wsl::linux::` | `src/linux/init/` |

### Key Files
- `src/shared/inc/defs.h` β€” Shared platform definitions (NON_COPYABLE, Debug, Arm64, etc.)
- `src/shared/inc/stringshared.h` β€” String conversion utilities
- `src/windows/common/WslTelemetry.h` β€” Telemetry macros
- `src/windows/common/ExecutionContext.h` β€” Error context and user-facing error macros
- `src/windows/service/inc/wslservice.idl` β€” Main service COM interface definitions
- `src/windows/service/inc/wslc.idl` β€” Container COM interface definitions
- `src/windows/inc/WslPluginApi.h` β€” Plugin API header
- `src/shared/configfile/configfile.h` β€” Config file parser
- `.clang-format` β€” Code formatting rules (130 col, 4-space indent, Allman braces)

## Building and Deploying

### Critical Platform Requirements
- **Full builds ONLY work on Windows** with Visual Studio and Windows SDK 26100
- **DO NOT attempt to build the main WSL components on Linux** β€” they require Windows-specific APIs, MSBuild, and Visual Studio toolchain
- Many validation and development tasks CAN be performed on Linux (documentation, formatting, Python validation scripts)

### Windows Build Requirements
- CMake >= 3.25 (`winget install Kitware.CMake`)
- Visual Studio with these components:
  - Windows SDK 26100
  - MSBuild
  - Universal Windows platform support for v143 build tools (X64 and ARM64)
  - MSVC v143 - VS 2022 C++ ARM64 build tools (Latest + Spectre) (X64 and ARM64)
  - C++ core features
  - C++ ATL for latest v143 tools (X64 and ARM64)
  - C++ Clang compiler for Windows
  - .NET desktop development
  - .NET WinUI app development tools
- Enable Developer Mode in Windows Settings OR run with Administrator privileges (required for symbolic link support)

### Building WSL (Windows Only)
1. Install prerequisites with `tools\setup-dev-env.ps1` (or follow `doc/docs/dev-loop.md` and `.vsconfig`)
2. Generate Visual Studio solution: `cmake .`
3. Build: `cmake --build . -- -m` OR open `wsl.sln` in Visual Studio

Build parameters:
- `cmake . -A arm64` β€” Build for ARM64
- `cmake . -DCMAKE_BUILD_TYPE=Release` β€” Release build
- `cmake . -DBUILD_BUNDLE=TRUE` β€” Build bundle MSIX package (requires ARM64 built first)

### Deploying WSL (Windows Only)
- Install MSI: `bin\<platform>\<target>\wsl.msi`
- OR use script: `powershell tools\deploy\deploy-to-host.ps1`
- For Hyper-V VM: `powershell tools\deploy\deploy-to-vm.ps1 -VmName <vm> -Username <user> -Password <pass>`

## Testing

### Writing Tests (TAEF Framework)

Tests use TAEF. See `.github/copilot/test.md` for detailed patterns and macros.

Key points:
- Use `WSL_TEST_CLASS(Name)` β€” not raw `BEGIN_TEST_CLASS`
- Use `VERIFY_*` macros for assertions (`VERIFY_ARE_EQUAL`, `VERIFY_IS_TRUE`, etc.)
- Skip macros: `WSL1_TEST_ONLY()`, `WSL2_TEST_ONLY()`, `SKIP_TEST_ARM64()`
- Test infrastructure is in `test/windows/common/Common.h` (include it as `"Common.h"`)
- Test layout under `test/windows/`:
  - `common/` β€” shared fixtures and helpers, plus unit tests for `src/windows/common`
  - `wsl/` β€” WSL tests
  - `wslc/` β€” WSLC tests
  - `testplugin/` β€” test plugin used by the plugin tests

### Running Tests (Windows Only)

**CRITICAL: ALWAYS build the ENTIRE project before running tests:**
```powershell
cmake --build . -- -m
bin\<platform>\<target>\test.bat
```

**Why full build is required:**
- Tests depend on multiple components (libwsl.dll, wsltests.dll, wslservice.exe, etc.)
- Partial builds will cause test failures
- **DO NOT skip the full build step even if only one file changed**

Test execution:
- Run all tests: `bin\<platform>\<target>\test.bat`
- Run subset: `bin\<platform>\<target>\test.bat /name:*UnitTest*`
- Run specific test: `bin\<platform>\<target>\test.bat /name:<class>::<test>` (for example, `bin\x64\debug\test.bat /name:UnitTests::UnitTests::ModernInstall`)
- WSL1 tests: Add `-Version 1` flag
- Fast mode (after first run): Add `-f` flag (requires `wsl --set-default test_distro`)
- **Requires Administrator privileges**

Test debugging:
- Attach WinDbgX automatically: `/attachdebugger`
- Wait for debugger (manual attach): `/waitfordebugger`
- Break on failure: `/breakonfailure`
- Run in-process: `/inproc`

### Linux Unit Tests (Linux Only)
- Location: `test/linux/unit_tests/`
- Build script: `test/linux/unit_tests/build_tests.sh`
- **Note**: Requires specific Linux build environment setup not covered in main build process

## Cross-Platform Validation Tasks

### Documentation (Works on Linux/Windows)
- Install tools: `pip install mkdocs-mermaid2-plugin mkdocs --break-system-packages`
- Build docs: `mkdocs build -f doc/mkdocs.yml`
- Output location: `doc/site/`
- **Note**: May show warnings about mermaid CDN access on restricted networks

### Code Formatting and Validation
- Format modified source (Windows, requires `cmake .` first): `.\FormatSource.ps1`
- Format all source: `.\FormatSource.ps1 -ModifiedOnly $false`; format/check files touched by the branch: `.\FormatSource.ps1 -Branch` / `.\FormatSource.ps1 -Branch -Verify $true` (defaults to local `master`; use `-BaseBranch` if needed)
- Format check (Linux/cross-platform): `clang-format --dry-run --style=file <files>`
- Validate copyright headers: `python3 tools/devops/validate-copyright-headers.py`
  - **Note**: Will report missing headers in generated/dependency files (`_deps/`), which is expected
- Validate localization: `python3 tools/devops/validate-localization.py`
  - **Note**: Only works after Windows build (requires `localization/strings/en-US/Resources.resw`)

### Distribution Validation (Limited on Linux)
- Validate distribution info: `python3 distributions/validate.py distributions/DistributionInfo.json`
- **Note**: May fail on Linux due to network restrictions accessing distribution URLs

### Pre-commit Checklist
Always run before committing:
1. `.\FormatSource.ps1 -Verify $true` to check formatting on changed C++ files
2. `python3 tools/devops/validate-copyright-headers.py` (ignore `_deps/` warnings)
3. `mkdocs build -f doc/mkdocs.yml` if documentation changed
4. Full Windows build if core components changed

**Note**: The `.gitignore` properly excludes build artifacts (`*.sln`, `*.dll`, `*.pdb`, `obj/`, `bin/`, etc.) β€” do not commit these files.

## Frequently Used Commands

### Windows Development
```powershell
# Initial setup
cmake .
cmake --build . -- -m

# Deploy and test
powershell tools\deploy\deploy-to-host.ps1
wsl --version

# Run tests
bin\x64\debug\test.bat
```

### Cross-Platform Validation
```powershell
# Documentation
mkdocs build -f doc/mkdocs.yml

# Code formatting (Windows)
.\FormatSource.ps1

# Copyright header validation (reports expected issues in _deps/)
python3 tools/devops/validate-copyright-headers.py

# Distribution validation (may fail on networks without external access)
python3 distributions/validate.py distributions/DistributionInfo.json
```

## Debugging and Logging

### ETL Tracing (Windows Only)
```powershell
# Collect traces
wpr -start diagnostics\wsl.wprp -filemode
# [reproduce issue]
wpr -stop logs.ETL

# Available profiles:
# - WSL (default) - General WSL tracing
# - WSL-Storage - Enhanced storage tracing
# - WSL-Networking - Comprehensive networking tracing
# - WSL-HvSocket - HvSocket-specific tracing
# Example: wpr -start diagnostics\wsl.wprp!WSL -filemode
```

### Log Analysis Tools
- Use WPA (Windows Performance Analyzer) for ETL traces
- Key providers: `Microsoft.Windows.Lxss.Manager`, `Microsoft.Windows.Subsystem.Lxss`
- For graphical/audio (WSLg) issues, see `.github/copilot/wslg-logs.md`. `collect-wsl-logs.ps1` gathers WSLg logs (`/mnt/wslg`: weston.log, pulseaudio.log, wlog.log, stderr.log, versions.txt) into a `wslg/` folder using `wsl.exe --system --user root`; crash dumps (`%TEMP%\wsl-crashes`, legacy `/mnt/wslg/dumps`) are only collected with `-Dump`. WSLg code lives in https://github.com/microsoft/wslg, not this repo.

### Debug Console (Linux)
Add to `%USERPROFILE%\.wslconfig`:
```ini
[wsl2]
debugConsole=true
```

### Common Debugging Commands
- Debug shell: `wsl --debug-shell`
- Collect WSL logs: `powershell diagnostics\collect-wsl-logs.ps1`
- Network logs: `powershell diagnostics\collect-wsl-logs.ps1 -LogProfile networking`

## Timing and Timeout Guidelines

**NEVER CANCEL these operations β€” always wait for completion:**

| Operation | Typical Duration | Minimum Timeout |
|---|---|---|
| Full Windows build | 20-45 minutes | 60+ minutes |
| Full test suite | 30-60 minutes | 90+ minutes |
| Unit test subset | 5-15 minutes | 30+ minutes |
| Documentation build | ~0.5 seconds | 5+ minutes |
| Distribution validation | 2-5 minutes | 15+ minutes |

## CI/CD Integration

### GitHub Actions
- **distributions.yml** β€” Validates distribution metadata (Linux)
- **documentation.yml** β€” Builds and deploys docs (Linux)
- **modern-distributions.yml** β€” Tests modern distribution support

## Development Environment Setup

### Windows (Full Development)
1. Install Visual Studio with required components (listed above)
2. Install CMake 3.25+
3. Enable Developer Mode
4. Clone repository
5. Run `cmake .` to generate solution

### Linux (Documentation/Validation Only)
1. Install Python 3.8+
2. Install docs tools: `pip install mkdocs-mermaid2-plugin mkdocs`
3. Clone repository
4. Run validation commands as needed

Remember: **This is a Windows-focused project**. While some tasks can be performed on Linux, full WSL development requires Windows with Visual Studio.