A WinUI 3 desktop app for managing WSL containers, Kubernetes (k3s), and container registries — community project, not a Microsoft product.
C#
157
190 commits
updated Oct 1, 2026
A native WinUI 3 / .NET 10 desktop application for managing WSL containers — the Linux container engine built into the Windows Subsystem for Linux (wslc.exe, generally available since WSL 3.0.1). It looks and feels like Docker Desktop or Podman Desktop, with a Fluent design, live performance metrics, a built-in Kubernetes (k3s) manager, container-registry management (including one-click Azure Container Registry sign-in), optional AI diagnostics and an in-app assistant, and a system-tray presence.
[!NOTE] WSL containers are generally available. Microsoft announced general availability on September 29, 2026 — read WSL containers is now generally available on the Windows Developer Blog, and the WSL containers architecture deep dive. Starting with this release, WSL Container Desktop requires WSL 3.0.1 or later (the GA release); the 2.9.x preview builds are no longer supported. See Getting started.
[!IMPORTANT] This is an independent, community project. It is not a Microsoft product, and it is not affiliated with, endorsed by, or supported by Microsoft. See the Disclaimer below before you build or run it.
wslc command set, including native restart, --mount, --stop-timeout, and network connect/disconnect.docker-compose.yml and bring a whole multi-service stack up / down / restart as a unit, with dependency ordering, health/exit gating, and auto-heal. The desktop app acts as the orchestration layer above wslc — see Docker Compose compatibility for exactly what is and isn't supported.localhost links that open in your browser or copy to the clipboard.wslc events (start/stop/create/destroy, network connect/disconnect, pull/build, engine up/down) so you can see what happened and when. Live events also refresh the UI immediately instead of waiting for the next poll..wslconfig limits, and installed distributions.

Dashboard — summary cards, a total-CPU meter, and a live per-container performance table.
![]() Containers — live, color-coded list with Compose grouping and inline actions; click any row for a full detail view. |
![]() Filesystem changes — a docker diff–style view of every file added, changed, or deleted versus the image.
|
![]() Templates — curated one-click stacks, grouped by category and configurable before launch. |
![]() Images — pull, build, tag, push, inspect, and prune, with update-available badges. |
![]() Docker Compose — bring a whole multi-service stack up / down / restart as a unit, with dependency ordering and auto-heal. |
![]() Kubernetes — install and manage a single-node k3s cluster right inside the app, with a metrics dashboard and "Apply YAML". |
![]() Container AI Assistant (optional) — a permissioned, tool-calling chat that manages containers, Compose, and k3s; shown here answering a question via a fully local Ollama model. |
![]() AI settings (opt-in) — choose GitHub Copilot, Ollama, Azure OpenAI, or any OpenAI-compatible endpoint; recognized secrets are masked, but review shared data for unrecognized sensitive content. |
![]() Container logs — live streaming output in the order it was written, with search, filter, error highlighting, timestamps, wrap, and export. |
![]() Container stats — live CPU and memory meters plus network I/O, block I/O, and PID count. |
![]() Endpoints — every published port across all running containers, with clickable localhost links.
|
![]() Activity — a persisted, filterable timeline of engine, container, and image events. |
![]() Registries — manage public and private registries with a live login-status indicator and one-click Add from Azure. |
![]() Kubernetes deployments — a Podman-style resource explorer across nodes, deployments, pods, and services. |
![]() Volumes — named and anonymous volumes with the containers using each; create, inspect, remove, and prune. |
![]() Networks — which containers use each network; list, create, inspect, remove, and prune alongside the built-in bridge, host, and none networks.
|
![]() Disk usage — what images, containers, and volumes consume, what's reclaimable, and one-click Reclaim all. |
![]() Settings — point at wslc.exe, tune tray/startup behavior, toggle notifications per category, and switch theme.
|
[!IMPORTANT] WSL Container Desktop requires WSL 3.0.1 or later — the release in which WSL containers became generally available. The 2.9.x preview builds are no longer supported. Check the installed version:
wsl --versionIf it is older than 3.0.1, update from the regular (stable) channel — the
--pre-releaseflag is no longer needed:wsl --updateWhen the app finds an older WSL, no
wslc.exe, or WSL containers turned off by your organization's policy, it shows a WSL 3.0.1 or later is required screen with Update WSL and Re-check buttons instead of the container pages. Settings, the WSL engine page, About, and Kubernetes stay available.
Prebuilt, signed packages are published on the Releases page.
Downloaded files are flagged "from the internet" (Mark of the Web), so Windows' default RemoteSigned
execution policy blocks the unsigned Install.ps1 with "…is not digitally signed." The most reliable
install is to run the two underlying steps yourself — interactive commands are not subject to
script-signing policy.
Open the latest release and download these assets into the same folder:
WSLContainerDesktop_<version>_x64.msix — the app (self-contained; it bundles the .NET and Windows App SDK runtimes).WSLContainerDesktop-Signing.cer — the publisher certificate.Open that folder, then open an elevated PowerShell (Run as administrator) and cd into it.
Run (adjust the file names to the release you downloaded):
Import-Certificate -FilePath .\WSLContainerDesktop-Signing.cer -CertStoreLocation Cert:\LocalMachine\TrustedPeople
Add-AppxPackage -Path .\WSLContainerDesktop_<version>_x64.msix -ForceUpdateFromAnyVersion
Launch WSL Container Desktop from the Start menu.
The first command trusts the app's self-signed publisher certificate (CN=Michael Hacker) so Windows
accepts the sideloaded package; the second installs (or updates) the app.
Updating. Once installed, the app checks GitHub for a newer release each time it starts. When one is available it shows a bar at the top of the window and a Windows notification; choose Update now and it downloads the release, closes, installs it and reopens. It only installs a package that is a newer build of this app signed with the same certificate as the one you installed. Turn the check off, or check by hand, under Settings → About. You can also still update manually by repeating the steps above with a newer release — it updates in place.
Prefer the bundled Install.ps1 script? Download it too, then run it in a way that bypasses the
script-signing block — either from an elevated PowerShell in the download folder:
powershell -ExecutionPolicy Bypass -File .\Install.ps1
…or strip the Mark of the Web first and then right-click Install.ps1 → Run with PowerShell:
Unblock-File -Path .\*
[!NOTE] The package is self-signed. The steps above trust the included certificate so Windows will accept it; you can inspect the
.cerfirst (right-click → Open). You still need WSL 3.0.1 or later (below) installed for the app to do anything.
| Requirement | Notes |
|---|---|
| Windows 10 or Windows 11 | WSL containers run on both. The package targets Windows 10 version 1809 (build 17763) or later; development and testing happen mainly on Windows 11, so Windows 10 is less tested. |
| WSL 3.0.1 or later | The generally available release that provides wslc.exe (default path: C:\Program Files\WSL\wslc.exe; the container.exe alias next to it is also accepted). Install or update with wsl --update. The 2.9.x preview builds are not supported. |
| .NET 10 SDK | Needed to build and run from source. |
| Windows App SDK tooling | Installed with recent Visual Studio workloads. |
| Azure CLI (optional) | Only for the "Add from Azure" registry feature. |
| AI provider (optional) | Only for the AI assistant & diagnostics (off by default). Use GitHub Copilot CLI (signed in), an Azure OpenAI endpoint + API key, any OpenAI-compatible endpoint (configurable base URL; API key optional for local servers), or run locally with Ollama (Set up Ollama downloads the ollama/ollama:latest image if you don't have it). |
| GPU (optional) | Used automatically where it helps: Ollama setup and the Open WebUI template request GPU access (--gpus all). Requesting GPU access is not by itself proof of acceleration. |
Install or update WSL from an elevated PowerShell prompt:
wsl --update
Confirm WSL is version 3.0.1 or later and the engine is present:
wsl --version
& "C:\Program Files\WSL\wslc.exe" version
git clone <your-fork-or-repo-url> wslcontainerdesktop
cd wslcontainerdesktop
[!CAUTION] Before you build or run this, review the source code yourself to confirm it is safe and appropriate for your environment. You run it entirely at your own risk — see the Disclaimer.
From a developer PowerShell prompt:
cd src\WslContainerDesktop
dotnet run -c Debug -p:Platform=x64
Or open WslContainerDesktop.slnx in Visual Studio 2022/2026, select the x64 platform, and press F5.
[!NOTE] Why
dotnet runand not justdotnet build? This is a packaged (MSIX-identity) WinUI app.dotnet runperforms the full pipeline — build, refresh the packaged loose-layout, re-register the package, and launch. A plaindotnet buildupdates the binaries but leaves the registered app pointing at a stale layout, so you would keep launching the previous version.
tools\launcher\Build-And-Run.ps1 rebuilds, redeploys, and launches the app in one step. A desktop shortcut named WSL Container Desktop points at it, so you can double-click to run the latest code after making changes.
nginx:alpine).--rm, -d, -i, --gpus all, a stop timeout (--stop-timeout, -1 = wait indefinitely), and a custom command. A registry selector qualifies bare image names. Long-form mounts imported from docker run --mount … are passed to the engine as native --mount options.wslc restart, which also starts a stopped container), Kill, Remove, and Prune stopped. The terminal button opens a new shell in the container. Less common actions are in the ⋯ menu (on the container's page and on each row): Export filesystem… to a tar file, and — while the container is running — Attach to main process…, which connects a terminal to the container's main process instead of a new shell. Attach is confirmed first, because Ctrl+C there usually stops the container. Actions that can't work right now (for example Kill on a stopped container, or opening a port that isn't published) are hidden.CMD checks, TCP probes, and start_interval (not offered by WSL 3.0.1) use app probes. Native health does not imply auto-restart: watchdog restart decisions remain app-owned. Health appears in badges and the tray; desired settings persist, and editing an existing container never silently recreates it.wslc container cp, so they work without an in-container shell, including on stopped containers; downloading a symbolic link fetches the file it points to. Browsing, text preview, path editing and filesystem diff need a running container with suitable tools, so for a stopped container the tab explains that and offers Download by path… for a file or folder whose path you know (also in the file list's right-click menu).docker diff equivalent listing every file added (A), changed (C), or deleted (D) relative to the container's image, so you can see exactly what a running container has written. (Emulated by comparing the container's rootfs against a fresh walk of its image; needs a running container with a shell.)exec -it) or, when the container publishes a port, open it in the browser.File downloads and background drag-out staging reject Windows-unsafe filenames, traversal, and existing host symbolic links. Choose a destination below the drive or share root. Opened files remain untrusted; read-only marking does not make their contents safe.
docker-compose.yml (file picker) to create a Compose project — the app parses a large subset of the Compose spec into a service dependency graph.docker compose down --volumes).scale / deploy.replicas or a saved per-service UI count. Reconciliation preserves unchanged instances and applies ownership-safe scale changes. See the supported scaling subset, including port/name conflicts and replicated dependency behavior.Starting or rebuilding a single-container dev environment with initializeCommand requires a
separate confirmation showing the workspace and exact commands. These commands run on Windows
with your user permissions, not inside the container. Approval applies only to that operation;
declining stops it before host commands or container changes. Importing a workspace is not approval
to execute its host commands. Compose-backed host initialization remains blocked.
The review visibly escapes backslashes and hidden control/format characters; it is not copy-ready
shell text. Execution uses the original reviewed commands.
Host initialization requires a conventional drive-letter workspace path shorter than 260 characters.
UNC, device and extended-length paths are rejected because CMD can silently use a different working
directory. Workspaces without host initialization commands are unaffected.
.tar file, for example to move them to another PC or keep a backup. The Import menu brings images back in; each option describes what it does and which action makes its file, and after a save or export the status line says which option restores it:
wslc load) restores a file made with Save to file… (or docker save) exactly as it was — same names, tags, layers and start command.wslc import) makes a new image from a .tar of files, usually one made with a container's Export filesystem…. Only the files are kept: the new image has no start command, environment variables or ports, so give it a command when you run it. You can name the new image; without a name it is listed as <none>.bridge network.-o key=value), and labels. Networks use the bridge driver, the only one WSL provides.localhost:<port> address that opens in your browser (for TCP endpoints) or can be copied to the clipboard.wslc events: container create/start/stop/kill/destroy (with exit codes) and network create/connect/disconnect/destroy arrive as they happen, alongside engine up/down from the background monitor and image pull/build outcomes (successes and failures) recorded directly — independent of your toast-notification settings. When first opened it loads the last hour of engine events so the page isn't empty.az acr login --expose-token), so no admin username, password, or key is required.mysql-2), free host ports, and its own named volumes, so it runs alongside the first rather than disturbing it. The card shows how many deployments exist, and Remove deployment asks which one to remove.template-configs.json)./workspace volume; open the container's Terminal action for a shell.localhost.session.storagePath at an empty folder you choose (for example on a larger drive); Reset to default returns to %LOCALAPPDATA%\wslc\sessions. Existing images, containers, and volumes are not moved — they stay in the old location until you delete them — and the session restarts before the new location is used. Under Container session settings, the session's CPU, memory, maximum disk size, default port-binding address, and credential store are shown read-only; Edit settings file opens settings.yaml to change them..wslconfig.AI is entirely opt-in: nothing is enabled, and no data leaves your machine, until you turn it on in Settings → AI diagnostics and pick a provider.
https://api.openai.com/v1) to point at LM Studio (http://localhost:1234/v1), llama.cpp / vLLM (http://localhost:8000/v1), Ollama's OpenAI API, or an internal gateway. /chat/completions is appended automatically, the API key is optional for servers that don't need one, and Refresh lists the models the endpoint actually serves.127.0.0.1:11434, offers to download a model if you don't have one, selects it as your provider, and reports what the model actually supports. It manages only its own container and never adopts an unrelated Ollama just because the endpoint answers. If ollama/ollama:latest isn't on your machine yet, setup downloads it first (a few GB); an image you already have is used as is. Remove Ollama deletes the container, and optionally its model volume.[!IMPORTANT] Sanitization is a best-effort rule-based filter, not arbitrary secret detection. Recognized sensitive JSON fields, environment assignments, YAML blocks, auth headers, connection strings, URL credentials, and private-key blocks are masked before truncation — but unlabelled passwords, encoded values, and custom formats can still get through. Review diagnosis previews, and don't paste secrets into chat. Local inference stays local only when the configured endpoint is actually local.
Assistant chat sends sanitized text and tool evidence during a turn without a separate evidence-preview step; approval settings govern mutations, not data sharing. Logs and configuration are untrusted evidence, not instructions or approval. YAML filtering is conservative and is not a full YAML interpreter.
Raw approved values stay in execution memory and may be passed to workload services. Existing workload configuration (such as saved Compose projects) is not an assistant transcript and is not scrubbed by this boundary, and historical activity already on disk is not retroactively scrubbed. Remote endpoint and provider retention policies still apply. The conversation ceiling starts at 32,768 accounted UTF-8 JSON bytes and is raised when the provider reports a context window, through a deliberately pessimistic conversion (75% of the window at 2.5 bytes per token, capped at 262,144 bytes). A token window is never treated as a byte budget in its own right, and an explicitly byte-accounted observation always wins, because it is measured rather than inferred.
Foundry Local support exists in the codebase but is not currently exposed in the UI — the provider picker offers Copilot, Ollama, Azure OpenAI, and OpenAI-compatible only. See integration scope and prerequisites for what was implemented and what remains unverified.
wslc.exe (or its container.exe alias) with a Test connection button and engine version readout.WSL Container Desktop can import a docker-compose.yml and run the whole stack, but it is not a drop-in replacement for the docker compose CLI. Understanding the model below will tell you what to expect.
The versioned configuration corpus records tested subsets and known differences. Its 21 cases compare captured Docker Compose v2.39.4 config output against spec-derived expectations; a few differences remain explicit (unused nested required expressions, duplicate DNS entries, and equivalent mixed short/long port bindings). Configuration comparisons are not runtime certification, and the separate opt-in WSLC runtime harness is not run by normal tests.
The WSL container engine (wslc) has no built-in Compose command or restart-policy flag in WSL 3.0.1. Microsoft has announced wslc compose as its next focus, but it has not shipped yet. Until it does, WSL Container Desktop acts as the orchestration layer above wslc: it parses the Compose file, resolves dependencies, creates and connects each service to its networks and starts it, then supervises the result.
The single most important consequence:
[!IMPORTANT] App-owned probes, restart policies and auto-heal work only while WSL Container Desktop is running. Native health monitoring is a separate engine feature, not a restart policy: the engine keeps evaluating native health checks without the app, but an actual desktop close/reopen persistence trial has not been performed. Do not rely on this desktop tool for unattended recovery.
This makes it ideal for local development and testing of multi-container apps — spin a stack up, iterate, tear it down — rather than for unattended production hosting.
A large subset of the Compose spec is honored on up:
image, build (context/dockerfile/args/target/labels/pull), container_name, command, entrypoint, user, working_dir, hostname, labels.ports (short and long form), volumes (short form as -v, long form as native --mount), top-level networks: / volumes: creation (including network driver_opts, internal, and labels), service DNS aliases, secrets: / configs: (file-backed, best-effort), extra_hosts (best-effort), tmpfs, dns*. Multi-network services are created, connected to every required network, then started; per-network aliases and static IPv4 settings are retained (one IPAM subnet configuration).environment, env_file, nested Compose interpolation (default/required/alternative operators, unset versus empty and $$), YAML quoting/anchors/aliases/<< merge keys, folded/literal block scalars and chomping, sibling override merging with !reset / !override, and strict local include: / extends: graphs within the subset below.deploy.resources.limits.{cpus,memory}, cpus, mem_limit, ulimits, shm_size, stop_signal, stop_grace_period (passed to the engine as --stop-timeout, rounded up to whole seconds).deploy.resources.reservations.devices entries requesting the gpu capability map to all-GPU passthrough. A narrower count or device_ids still passes all GPUs and warns, because per-device selection isn't available.depends_on (including condition: service_healthy / service_completed_successfully), healthcheck, restart: (no/always/on-failure/unless-stopped), profiles:, and project up / down / restart with re-adoption on relaunch.Some of these are best-effort — e.g. secrets/configs are bind-mounted rather than stored in an engine secret store, extra_hosts is applied via exec after start, and restart backoff timing is not byte-for-byte identical to Docker.
command, entrypoint, and healthcheck.test replace rather than append. Mixed list/map
environment and label forms merge by key. !reset removes an attribute; !override replaces it..env; an empty value still wins. Substitution applies to YAML
values (not mapping keys), once per file before merging. Service env_file values do not
feed interpolation; later files win for container variables, with inline environment winning last.
An unset optional substitution becomes empty with a value-free warning.path lists, project_directory and include env_file are supported for local inputs.
Included paths use their project directory; child .env supplies defaults below the parent's
interpolation environment and cannot leak to siblings. Only an explicit include path list
loads child override layers. Extends has its own merge rules, detects cycles/missing services,
rebases inherited paths to their source file, and does not import that file's top-level resources.env_file.required: false permits absence only; existing
unreadable/malformed files still reject. File errors use logical source/key breadcrumbs, not
user-controlled paths or contents. Binary secret/config files are accepted without text parsing..env / env_file parsing
supports simple line-based assignments with outer-quote removal, not full dotenv multiline,
escape, inline-comment or interpolation semantics; malformed assignments reject.
Remote required inputs, unsupported include/extends forms and env-file format options reject.
There is no CLI --env-file/PWD selection emulation. The saved
command representation distinguishes null/empty, but clearing image defaults at engine runtime
is not certified. See parser limits, audit and contracts.Unimplemented Compose options are skipped with import warnings; invalid configuration and unsupported YAML syntax are rejected, not treated as a runnable partial project. CLI limitations below describe advertised help, not proof that hidden functionality is impossible:
cap_add / cap_drop, arbitrary devices, sysctls, privileged, root-filesystem read_only, init, pid / ipc, mac_address, and logging drivers are not offered by WSL 3.0.1. GPU support and read-only volume mounts are separate supported options.bind.create_host_path, volume.nocopy, and tmpfs.size are rejected by WSL 3.0.1's --mount, so they are ignored with an import warning; the rest of a long-form volume entry is passed through as a native --mount.scale / deploy.replicas is supported, not Swarm scheduling, placement, replicated jobs, rolling updates or ingress/VIP routing. Only deploy.mode: replicated is accepted. Fixed host ports, explicit container names and unsafe network configurations cannot be multiplied; see scaling limits.For the authoritative, line-by-line feature matrix (including exactly how each key is mapped), see the Compose feature support table in docs/ARCHITECTURE.md.
MVVM (CommunityToolkit.Mvvm) with dependency injection (Microsoft.Extensions.DependencyInjection).
| Layer | Responsibility |
|---|---|
Services/WslcService | Wraps wslc.exe, parses --format json output into typed models |
Services/KubernetesService | Manages a k3s cluster via wsl.exe -u root (install, resources, port-forward) |
Services/AzureCliService | Discovers and authenticates to Azure Container Registries via az |
Services/RegistryAuthRefresher | Keeps Azure-backed registry logins fresh (background + just-in-time) |
Services/ProcessRunner | Async process execution + interactive console launches |
Services/StatusMonitor | Background poller and single source of truth for engine, Kubernetes, and registry health |
Services/ContainerAssistantService | The AI assistant's tool-calling loop over a pluggable IAiChatProvider (Copilot / Azure OpenAI / OpenAI-compatible / Ollama), with per-tool permissions |
Services/SettingsService | JSON settings persisted under %LOCALAPPDATA% |
Tray/TrayIcon | Win32 Shell_NotifyIcon tray with a GDI+ status-dot icon and popup menu |
ViewModels/* | Observable state and commands |
Views/*, Dialogs/* | WinUI 3 pages and dialogs |
The tray is implemented directly against Win32 (Shell_NotifyIcon, a hidden message window, TrackPopupMenuEx) so it has no third-party UI dependencies and stays compatible with the latest Windows App SDK.
For a deeper contributor-oriented walkthrough — the process-execution strategy, the StatusMonitor model, the k3s status marker protocol, the installer trust model, and coding conventions — see docs/ARCHITECTURE.md.
For deterministic assistant/provider regression coverage, reusable test fixtures,
remaining contract gaps, and opt-in runtime smoke prerequisites, see
docs/AI-CONTRACT-TESTS.md.
Releases are cut by manually running the Build & Release (MSIX) workflow:
CHANGELOG.md with the new version's user-facing changes and commit it before cutting the release — the generated release notes link to the changelog at that release's tag.X.Y.Z, e.g. 1.2.0). Leave it blank to auto-derive 0.1.<run-number>. Optionally tick pre-release.v<version> with the .msix, the .cer, and Install.ps1 attached.Versioning: the version you supply becomes the MSIX identity version X.Y.Z.0 and the app's displayed version (read at runtime from the package identity, so it always matches the installed build). Bump it each release — the workflow refuses to reuse an existing tag, and Windows only treats a package as an in-place update when the version increases. The manifest version committed in source is just a placeholder; the release version overrides it at build time.
Signing details and how to rotate the certificate are documented in build/README-signing.md.
WSL containers became generally available in WSL 3.0.1 — see Microsoft's GA announcement and the architecture deep dive. WSL Container Desktop requires 3.0.1 or later and builds directly on the commands and flags that release provides; it no longer carries compatibility code for the 2.9.x preview builds.
wslc mirrors the Docker CLI, so commands map cleanly (list, images, run, pull, push, logs, exec, stats, volume, network, build, login, restart, events, save, load, …). A few details this app accounts for:
images reports 12-character short IDs rather than full digests. Mount sources may be a volume name or a host path. The app matches on all of these rather than assuming one shape.prune subcommands ask for confirmation unless given --force. The app has already asked you, so it always passes --force. volume prune needs --all to include named volumes.- (read from stdin) is refused.wslc events has no JSON output; the app parses its Docker-style text lines and skips any it can't read. Events speed up refreshes and feed the Activity page, but are never treated as proof of health.--health-start-interval (Compose start_interval) is not offered by WSL 3.0.1. The app still checks the engine's help for it, so a later WSL that adds it is used natively; until then such checks run as app probes.wslc has no --add-host, restart-policy, or Compose command: extra_hosts is applied after start, and restart policies and Compose orchestration are app-owned (see Docker Compose compatibility).pause command; Kill serves as a force-stop.Organization policies. Administrators can manage WSL containers through Intune or Group Policy
(HKLM\Software\Policies\WSL). The app reads these settings but never changes them:
| Policy | What the app does |
|---|---|
Allow WSL containers access (AllowWSLContainer) or WSL itself (AllowWSL) turned off | Shows disabled by your organization on the requirement screen instead of offering an update. |
WSL containers registry allow list (WSLContainerRegistryAllowlist) | Lists the approved registries on the Registries page and stops operations that reference any other registry before contacting it. Builds are disabled while an allow list is in effect, because WSL refuses them. |
Engine policy errors are shown in plain language wherever an operation fails. See the WSL enterprise documentation for how to configure the policies.
Not yet adopted: the Microsoft.WSL.Containers programming API (NuGet) that shipped with GA. The
app continues to drive wslc.exe; the API will be evaluated once the package has been published
long enough to meet this project's dependency-age policy.
This project is not a Microsoft product. It is an independent, community-developed application and is not affiliated with, endorsed by, sponsored by, or supported by Microsoft Corporation. "Windows", "WSL", "Azure", and related marks are trademarks of Microsoft; they are used here only to describe interoperability.
There is no support, no guarantee, and no warranty of any kind. This software is provided "AS IS", without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose, title, and non-infringement.
By building, installing, or running this software, you acknowledge and accept these terms. If you do not accept them, do not use this software.
This project is licensed under the GNU General Public License v3.0 — see the LICENSE file for the full text.
In short: you are free to use, study, modify, and share this software. If you distribute it — modified or not — you must make your version's complete source code available under the same GPLv3 terms. This keeps the project and any derivatives open; it prevents anyone from taking the code, making changes, and shipping it as a closed-source or proprietary commercial product. The GPLv3 also includes its own disclaimer of warranty and limitation of liability, which apply in addition to the Disclaimer above.
C#
99.5%
A WinUI 3 desktop app for managing WSL containers, Kubernetes (k3s), and container registries — community project, not a Microsoft product.
C#
157
190 commits
updated Oct 1, 2026
A native WinUI 3 / .NET 10 desktop application for managing WSL containers — the Linux container engine built into the Windows Subsystem for Linux (wslc.exe, generally available since WSL 3.0.1). It looks and feels like Docker Desktop or Podman Desktop, with a Fluent design, live performance metrics, a built-in Kubernetes (k3s) manager, container-registry management (including one-click Azure Container Registry sign-in), optional AI diagnostics and an in-app assistant, and a system-tray presence.
[!NOTE] WSL containers are generally available. Microsoft announced general availability on September 29, 2026 — read WSL containers is now generally available on the Windows Developer Blog, and the WSL containers architecture deep dive. Starting with this release, WSL Container Desktop requires WSL 3.0.1 or later (the GA release); the 2.9.x preview builds are no longer supported. See Getting started.
[!IMPORTANT] This is an independent, community project. It is not a Microsoft product, and it is not affiliated with, endorsed by, or supported by Microsoft. See the Disclaimer below before you build or run it.
wslc command set, including native restart, --mount, --stop-timeout, and network connect/disconnect.docker-compose.yml and bring a whole multi-service stack up / down / restart as a unit, with dependency ordering, health/exit gating, and auto-heal. The desktop app acts as the orchestration layer above wslc — see Docker Compose compatibility for exactly what is and isn't supported.localhost links that open in your browser or copy to the clipboard.wslc events (start/stop/create/destroy, network connect/disconnect, pull/build, engine up/down) so you can see what happened and when. Live events also refresh the UI immediately instead of waiting for the next poll..wslconfig limits, and installed distributions.

Dashboard — summary cards, a total-CPU meter, and a live per-container performance table.
![]() Containers — live, color-coded list with Compose grouping and inline actions; click any row for a full detail view. |
![]() Filesystem changes — a docker diff–style view of every file added, changed, or deleted versus the image.
|
![]() Templates — curated one-click stacks, grouped by category and configurable before launch. |
![]() Images — pull, build, tag, push, inspect, and prune, with update-available badges. |
![]() Docker Compose — bring a whole multi-service stack up / down / restart as a unit, with dependency ordering and auto-heal. |
![]() Kubernetes — install and manage a single-node k3s cluster right inside the app, with a metrics dashboard and "Apply YAML". |
![]() Container AI Assistant (optional) — a permissioned, tool-calling chat that manages containers, Compose, and k3s; shown here answering a question via a fully local Ollama model. |
![]() AI settings (opt-in) — choose GitHub Copilot, Ollama, Azure OpenAI, or any OpenAI-compatible endpoint; recognized secrets are masked, but review shared data for unrecognized sensitive content. |
![]() Container logs — live streaming output in the order it was written, with search, filter, error highlighting, timestamps, wrap, and export. |
![]() Container stats — live CPU and memory meters plus network I/O, block I/O, and PID count. |
![]() Endpoints — every published port across all running containers, with clickable localhost links.
|
![]() Activity — a persisted, filterable timeline of engine, container, and image events. |
![]() Registries — manage public and private registries with a live login-status indicator and one-click Add from Azure. |
![]() Kubernetes deployments — a Podman-style resource explorer across nodes, deployments, pods, and services. |
![]() Volumes — named and anonymous volumes with the containers using each; create, inspect, remove, and prune. |
![]() Networks — which containers use each network; list, create, inspect, remove, and prune alongside the built-in bridge, host, and none networks.
|
![]() Disk usage — what images, containers, and volumes consume, what's reclaimable, and one-click Reclaim all. |
![]() Settings — point at wslc.exe, tune tray/startup behavior, toggle notifications per category, and switch theme.
|
[!IMPORTANT] WSL Container Desktop requires WSL 3.0.1 or later — the release in which WSL containers became generally available. The 2.9.x preview builds are no longer supported. Check the installed version:
wsl --versionIf it is older than 3.0.1, update from the regular (stable) channel — the
--pre-releaseflag is no longer needed:wsl --updateWhen the app finds an older WSL, no
wslc.exe, or WSL containers turned off by your organization's policy, it shows a WSL 3.0.1 or later is required screen with Update WSL and Re-check buttons instead of the container pages. Settings, the WSL engine page, About, and Kubernetes stay available.
Prebuilt, signed packages are published on the Releases page.
Downloaded files are flagged "from the internet" (Mark of the Web), so Windows' default RemoteSigned
execution policy blocks the unsigned Install.ps1 with "…is not digitally signed." The most reliable
install is to run the two underlying steps yourself — interactive commands are not subject to
script-signing policy.
Open the latest release and download these assets into the same folder:
WSLContainerDesktop_<version>_x64.msix — the app (self-contained; it bundles the .NET and Windows App SDK runtimes).WSLContainerDesktop-Signing.cer — the publisher certificate.Open that folder, then open an elevated PowerShell (Run as administrator) and cd into it.
Run (adjust the file names to the release you downloaded):
Import-Certificate -FilePath .\WSLContainerDesktop-Signing.cer -CertStoreLocation Cert:\LocalMachine\TrustedPeople
Add-AppxPackage -Path .\WSLContainerDesktop_<version>_x64.msix -ForceUpdateFromAnyVersion
Launch WSL Container Desktop from the Start menu.
The first command trusts the app's self-signed publisher certificate (CN=Michael Hacker) so Windows
accepts the sideloaded package; the second installs (or updates) the app.
Updating. Once installed, the app checks GitHub for a newer release each time it starts. When one is available it shows a bar at the top of the window and a Windows notification; choose Update now and it downloads the release, closes, installs it and reopens. It only installs a package that is a newer build of this app signed with the same certificate as the one you installed. Turn the check off, or check by hand, under Settings → About. You can also still update manually by repeating the steps above with a newer release — it updates in place.
Prefer the bundled Install.ps1 script? Download it too, then run it in a way that bypasses the
script-signing block — either from an elevated PowerShell in the download folder:
powershell -ExecutionPolicy Bypass -File .\Install.ps1
…or strip the Mark of the Web first and then right-click Install.ps1 → Run with PowerShell:
Unblock-File -Path .\*
[!NOTE] The package is self-signed. The steps above trust the included certificate so Windows will accept it; you can inspect the
.cerfirst (right-click → Open). You still need WSL 3.0.1 or later (below) installed for the app to do anything.
| Requirement | Notes |
|---|---|
| Windows 10 or Windows 11 | WSL containers run on both. The package targets Windows 10 version 1809 (build 17763) or later; development and testing happen mainly on Windows 11, so Windows 10 is less tested. |
| WSL 3.0.1 or later | The generally available release that provides wslc.exe (default path: C:\Program Files\WSL\wslc.exe; the container.exe alias next to it is also accepted). Install or update with wsl --update. The 2.9.x preview builds are not supported. |
| .NET 10 SDK | Needed to build and run from source. |
| Windows App SDK tooling | Installed with recent Visual Studio workloads. |
| Azure CLI (optional) | Only for the "Add from Azure" registry feature. |
| AI provider (optional) | Only for the AI assistant & diagnostics (off by default). Use GitHub Copilot CLI (signed in), an Azure OpenAI endpoint + API key, any OpenAI-compatible endpoint (configurable base URL; API key optional for local servers), or run locally with Ollama (Set up Ollama downloads the ollama/ollama:latest image if you don't have it). |
| GPU (optional) | Used automatically where it helps: Ollama setup and the Open WebUI template request GPU access (--gpus all). Requesting GPU access is not by itself proof of acceleration. |
Install or update WSL from an elevated PowerShell prompt:
wsl --update
Confirm WSL is version 3.0.1 or later and the engine is present:
wsl --version
& "C:\Program Files\WSL\wslc.exe" version
git clone <your-fork-or-repo-url> wslcontainerdesktop
cd wslcontainerdesktop
[!CAUTION] Before you build or run this, review the source code yourself to confirm it is safe and appropriate for your environment. You run it entirely at your own risk — see the Disclaimer.
From a developer PowerShell prompt:
cd src\WslContainerDesktop
dotnet run -c Debug -p:Platform=x64
Or open WslContainerDesktop.slnx in Visual Studio 2022/2026, select the x64 platform, and press F5.
[!NOTE] Why
dotnet runand not justdotnet build? This is a packaged (MSIX-identity) WinUI app.dotnet runperforms the full pipeline — build, refresh the packaged loose-layout, re-register the package, and launch. A plaindotnet buildupdates the binaries but leaves the registered app pointing at a stale layout, so you would keep launching the previous version.
tools\launcher\Build-And-Run.ps1 rebuilds, redeploys, and launches the app in one step. A desktop shortcut named WSL Container Desktop points at it, so you can double-click to run the latest code after making changes.
nginx:alpine).--rm, -d, -i, --gpus all, a stop timeout (--stop-timeout, -1 = wait indefinitely), and a custom command. A registry selector qualifies bare image names. Long-form mounts imported from docker run --mount … are passed to the engine as native --mount options.wslc restart, which also starts a stopped container), Kill, Remove, and Prune stopped. The terminal button opens a new shell in the container. Less common actions are in the ⋯ menu (on the container's page and on each row): Export filesystem… to a tar file, and — while the container is running — Attach to main process…, which connects a terminal to the container's main process instead of a new shell. Attach is confirmed first, because Ctrl+C there usually stops the container. Actions that can't work right now (for example Kill on a stopped container, or opening a port that isn't published) are hidden.CMD checks, TCP probes, and start_interval (not offered by WSL 3.0.1) use app probes. Native health does not imply auto-restart: watchdog restart decisions remain app-owned. Health appears in badges and the tray; desired settings persist, and editing an existing container never silently recreates it.wslc container cp, so they work without an in-container shell, including on stopped containers; downloading a symbolic link fetches the file it points to. Browsing, text preview, path editing and filesystem diff need a running container with suitable tools, so for a stopped container the tab explains that and offers Download by path… for a file or folder whose path you know (also in the file list's right-click menu).docker diff equivalent listing every file added (A), changed (C), or deleted (D) relative to the container's image, so you can see exactly what a running container has written. (Emulated by comparing the container's rootfs against a fresh walk of its image; needs a running container with a shell.)exec -it) or, when the container publishes a port, open it in the browser.File downloads and background drag-out staging reject Windows-unsafe filenames, traversal, and existing host symbolic links. Choose a destination below the drive or share root. Opened files remain untrusted; read-only marking does not make their contents safe.
docker-compose.yml (file picker) to create a Compose project — the app parses a large subset of the Compose spec into a service dependency graph.docker compose down --volumes).scale / deploy.replicas or a saved per-service UI count. Reconciliation preserves unchanged instances and applies ownership-safe scale changes. See the supported scaling subset, including port/name conflicts and replicated dependency behavior.Starting or rebuilding a single-container dev environment with initializeCommand requires a
separate confirmation showing the workspace and exact commands. These commands run on Windows
with your user permissions, not inside the container. Approval applies only to that operation;
declining stops it before host commands or container changes. Importing a workspace is not approval
to execute its host commands. Compose-backed host initialization remains blocked.
The review visibly escapes backslashes and hidden control/format characters; it is not copy-ready
shell text. Execution uses the original reviewed commands.
Host initialization requires a conventional drive-letter workspace path shorter than 260 characters.
UNC, device and extended-length paths are rejected because CMD can silently use a different working
directory. Workspaces without host initialization commands are unaffected.
.tar file, for example to move them to another PC or keep a backup. The Import menu brings images back in; each option describes what it does and which action makes its file, and after a save or export the status line says which option restores it:
wslc load) restores a file made with Save to file… (or docker save) exactly as it was — same names, tags, layers and start command.wslc import) makes a new image from a .tar of files, usually one made with a container's Export filesystem…. Only the files are kept: the new image has no start command, environment variables or ports, so give it a command when you run it. You can name the new image; without a name it is listed as <none>.bridge network.-o key=value), and labels. Networks use the bridge driver, the only one WSL provides.localhost:<port> address that opens in your browser (for TCP endpoints) or can be copied to the clipboard.wslc events: container create/start/stop/kill/destroy (with exit codes) and network create/connect/disconnect/destroy arrive as they happen, alongside engine up/down from the background monitor and image pull/build outcomes (successes and failures) recorded directly — independent of your toast-notification settings. When first opened it loads the last hour of engine events so the page isn't empty.az acr login --expose-token), so no admin username, password, or key is required.mysql-2), free host ports, and its own named volumes, so it runs alongside the first rather than disturbing it. The card shows how many deployments exist, and Remove deployment asks which one to remove.template-configs.json)./workspace volume; open the container's Terminal action for a shell.localhost.session.storagePath at an empty folder you choose (for example on a larger drive); Reset to default returns to %LOCALAPPDATA%\wslc\sessions. Existing images, containers, and volumes are not moved — they stay in the old location until you delete them — and the session restarts before the new location is used. Under Container session settings, the session's CPU, memory, maximum disk size, default port-binding address, and credential store are shown read-only; Edit settings file opens settings.yaml to change them..wslconfig.AI is entirely opt-in: nothing is enabled, and no data leaves your machine, until you turn it on in Settings → AI diagnostics and pick a provider.
https://api.openai.com/v1) to point at LM Studio (http://localhost:1234/v1), llama.cpp / vLLM (http://localhost:8000/v1), Ollama's OpenAI API, or an internal gateway. /chat/completions is appended automatically, the API key is optional for servers that don't need one, and Refresh lists the models the endpoint actually serves.127.0.0.1:11434, offers to download a model if you don't have one, selects it as your provider, and reports what the model actually supports. It manages only its own container and never adopts an unrelated Ollama just because the endpoint answers. If ollama/ollama:latest isn't on your machine yet, setup downloads it first (a few GB); an image you already have is used as is. Remove Ollama deletes the container, and optionally its model volume.[!IMPORTANT] Sanitization is a best-effort rule-based filter, not arbitrary secret detection. Recognized sensitive JSON fields, environment assignments, YAML blocks, auth headers, connection strings, URL credentials, and private-key blocks are masked before truncation — but unlabelled passwords, encoded values, and custom formats can still get through. Review diagnosis previews, and don't paste secrets into chat. Local inference stays local only when the configured endpoint is actually local.
Assistant chat sends sanitized text and tool evidence during a turn without a separate evidence-preview step; approval settings govern mutations, not data sharing. Logs and configuration are untrusted evidence, not instructions or approval. YAML filtering is conservative and is not a full YAML interpreter.
Raw approved values stay in execution memory and may be passed to workload services. Existing workload configuration (such as saved Compose projects) is not an assistant transcript and is not scrubbed by this boundary, and historical activity already on disk is not retroactively scrubbed. Remote endpoint and provider retention policies still apply. The conversation ceiling starts at 32,768 accounted UTF-8 JSON bytes and is raised when the provider reports a context window, through a deliberately pessimistic conversion (75% of the window at 2.5 bytes per token, capped at 262,144 bytes). A token window is never treated as a byte budget in its own right, and an explicitly byte-accounted observation always wins, because it is measured rather than inferred.
Foundry Local support exists in the codebase but is not currently exposed in the UI — the provider picker offers Copilot, Ollama, Azure OpenAI, and OpenAI-compatible only. See integration scope and prerequisites for what was implemented and what remains unverified.
wslc.exe (or its container.exe alias) with a Test connection button and engine version readout.WSL Container Desktop can import a docker-compose.yml and run the whole stack, but it is not a drop-in replacement for the docker compose CLI. Understanding the model below will tell you what to expect.
The versioned configuration corpus records tested subsets and known differences. Its 21 cases compare captured Docker Compose v2.39.4 config output against spec-derived expectations; a few differences remain explicit (unused nested required expressions, duplicate DNS entries, and equivalent mixed short/long port bindings). Configuration comparisons are not runtime certification, and the separate opt-in WSLC runtime harness is not run by normal tests.
The WSL container engine (wslc) has no built-in Compose command or restart-policy flag in WSL 3.0.1. Microsoft has announced wslc compose as its next focus, but it has not shipped yet. Until it does, WSL Container Desktop acts as the orchestration layer above wslc: it parses the Compose file, resolves dependencies, creates and connects each service to its networks and starts it, then supervises the result.
The single most important consequence:
[!IMPORTANT] App-owned probes, restart policies and auto-heal work only while WSL Container Desktop is running. Native health monitoring is a separate engine feature, not a restart policy: the engine keeps evaluating native health checks without the app, but an actual desktop close/reopen persistence trial has not been performed. Do not rely on this desktop tool for unattended recovery.
This makes it ideal for local development and testing of multi-container apps — spin a stack up, iterate, tear it down — rather than for unattended production hosting.
A large subset of the Compose spec is honored on up:
image, build (context/dockerfile/args/target/labels/pull), container_name, command, entrypoint, user, working_dir, hostname, labels.ports (short and long form), volumes (short form as -v, long form as native --mount), top-level networks: / volumes: creation (including network driver_opts, internal, and labels), service DNS aliases, secrets: / configs: (file-backed, best-effort), extra_hosts (best-effort), tmpfs, dns*. Multi-network services are created, connected to every required network, then started; per-network aliases and static IPv4 settings are retained (one IPAM subnet configuration).environment, env_file, nested Compose interpolation (default/required/alternative operators, unset versus empty and $$), YAML quoting/anchors/aliases/<< merge keys, folded/literal block scalars and chomping, sibling override merging with !reset / !override, and strict local include: / extends: graphs within the subset below.deploy.resources.limits.{cpus,memory}, cpus, mem_limit, ulimits, shm_size, stop_signal, stop_grace_period (passed to the engine as --stop-timeout, rounded up to whole seconds).deploy.resources.reservations.devices entries requesting the gpu capability map to all-GPU passthrough. A narrower count or device_ids still passes all GPUs and warns, because per-device selection isn't available.depends_on (including condition: service_healthy / service_completed_successfully), healthcheck, restart: (no/always/on-failure/unless-stopped), profiles:, and project up / down / restart with re-adoption on relaunch.Some of these are best-effort — e.g. secrets/configs are bind-mounted rather than stored in an engine secret store, extra_hosts is applied via exec after start, and restart backoff timing is not byte-for-byte identical to Docker.
command, entrypoint, and healthcheck.test replace rather than append. Mixed list/map
environment and label forms merge by key. !reset removes an attribute; !override replaces it..env; an empty value still wins. Substitution applies to YAML
values (not mapping keys), once per file before merging. Service env_file values do not
feed interpolation; later files win for container variables, with inline environment winning last.
An unset optional substitution becomes empty with a value-free warning.path lists, project_directory and include env_file are supported for local inputs.
Included paths use their project directory; child .env supplies defaults below the parent's
interpolation environment and cannot leak to siblings. Only an explicit include path list
loads child override layers. Extends has its own merge rules, detects cycles/missing services,
rebases inherited paths to their source file, and does not import that file's top-level resources.env_file.required: false permits absence only; existing
unreadable/malformed files still reject. File errors use logical source/key breadcrumbs, not
user-controlled paths or contents. Binary secret/config files are accepted without text parsing..env / env_file parsing
supports simple line-based assignments with outer-quote removal, not full dotenv multiline,
escape, inline-comment or interpolation semantics; malformed assignments reject.
Remote required inputs, unsupported include/extends forms and env-file format options reject.
There is no CLI --env-file/PWD selection emulation. The saved
command representation distinguishes null/empty, but clearing image defaults at engine runtime
is not certified. See parser limits, audit and contracts.Unimplemented Compose options are skipped with import warnings; invalid configuration and unsupported YAML syntax are rejected, not treated as a runnable partial project. CLI limitations below describe advertised help, not proof that hidden functionality is impossible:
cap_add / cap_drop, arbitrary devices, sysctls, privileged, root-filesystem read_only, init, pid / ipc, mac_address, and logging drivers are not offered by WSL 3.0.1. GPU support and read-only volume mounts are separate supported options.bind.create_host_path, volume.nocopy, and tmpfs.size are rejected by WSL 3.0.1's --mount, so they are ignored with an import warning; the rest of a long-form volume entry is passed through as a native --mount.scale / deploy.replicas is supported, not Swarm scheduling, placement, replicated jobs, rolling updates or ingress/VIP routing. Only deploy.mode: replicated is accepted. Fixed host ports, explicit container names and unsafe network configurations cannot be multiplied; see scaling limits.For the authoritative, line-by-line feature matrix (including exactly how each key is mapped), see the Compose feature support table in docs/ARCHITECTURE.md.
MVVM (CommunityToolkit.Mvvm) with dependency injection (Microsoft.Extensions.DependencyInjection).
| Layer | Responsibility |
|---|---|
Services/WslcService | Wraps wslc.exe, parses --format json output into typed models |
Services/KubernetesService | Manages a k3s cluster via wsl.exe -u root (install, resources, port-forward) |
Services/AzureCliService | Discovers and authenticates to Azure Container Registries via az |
Services/RegistryAuthRefresher | Keeps Azure-backed registry logins fresh (background + just-in-time) |
Services/ProcessRunner | Async process execution + interactive console launches |
Services/StatusMonitor | Background poller and single source of truth for engine, Kubernetes, and registry health |
Services/ContainerAssistantService | The AI assistant's tool-calling loop over a pluggable IAiChatProvider (Copilot / Azure OpenAI / OpenAI-compatible / Ollama), with per-tool permissions |
Services/SettingsService | JSON settings persisted under %LOCALAPPDATA% |
Tray/TrayIcon | Win32 Shell_NotifyIcon tray with a GDI+ status-dot icon and popup menu |
ViewModels/* | Observable state and commands |
Views/*, Dialogs/* | WinUI 3 pages and dialogs |
The tray is implemented directly against Win32 (Shell_NotifyIcon, a hidden message window, TrackPopupMenuEx) so it has no third-party UI dependencies and stays compatible with the latest Windows App SDK.
For a deeper contributor-oriented walkthrough — the process-execution strategy, the StatusMonitor model, the k3s status marker protocol, the installer trust model, and coding conventions — see docs/ARCHITECTURE.md.
For deterministic assistant/provider regression coverage, reusable test fixtures,
remaining contract gaps, and opt-in runtime smoke prerequisites, see
docs/AI-CONTRACT-TESTS.md.
Releases are cut by manually running the Build & Release (MSIX) workflow:
CHANGELOG.md with the new version's user-facing changes and commit it before cutting the release — the generated release notes link to the changelog at that release's tag.X.Y.Z, e.g. 1.2.0). Leave it blank to auto-derive 0.1.<run-number>. Optionally tick pre-release.v<version> with the .msix, the .cer, and Install.ps1 attached.Versioning: the version you supply becomes the MSIX identity version X.Y.Z.0 and the app's displayed version (read at runtime from the package identity, so it always matches the installed build). Bump it each release — the workflow refuses to reuse an existing tag, and Windows only treats a package as an in-place update when the version increases. The manifest version committed in source is just a placeholder; the release version overrides it at build time.
Signing details and how to rotate the certificate are documented in build/README-signing.md.
WSL containers became generally available in WSL 3.0.1 — see Microsoft's GA announcement and the architecture deep dive. WSL Container Desktop requires 3.0.1 or later and builds directly on the commands and flags that release provides; it no longer carries compatibility code for the 2.9.x preview builds.
wslc mirrors the Docker CLI, so commands map cleanly (list, images, run, pull, push, logs, exec, stats, volume, network, build, login, restart, events, save, load, …). A few details this app accounts for:
images reports 12-character short IDs rather than full digests. Mount sources may be a volume name or a host path. The app matches on all of these rather than assuming one shape.prune subcommands ask for confirmation unless given --force. The app has already asked you, so it always passes --force. volume prune needs --all to include named volumes.- (read from stdin) is refused.wslc events has no JSON output; the app parses its Docker-style text lines and skips any it can't read. Events speed up refreshes and feed the Activity page, but are never treated as proof of health.--health-start-interval (Compose start_interval) is not offered by WSL 3.0.1. The app still checks the engine's help for it, so a later WSL that adds it is used natively; until then such checks run as app probes.wslc has no --add-host, restart-policy, or Compose command: extra_hosts is applied after start, and restart policies and Compose orchestration are app-owned (see Docker Compose compatibility).pause command; Kill serves as a force-stop.Organization policies. Administrators can manage WSL containers through Intune or Group Policy
(HKLM\Software\Policies\WSL). The app reads these settings but never changes them:
| Policy | What the app does |
|---|---|
Allow WSL containers access (AllowWSLContainer) or WSL itself (AllowWSL) turned off | Shows disabled by your organization on the requirement screen instead of offering an update. |
WSL containers registry allow list (WSLContainerRegistryAllowlist) | Lists the approved registries on the Registries page and stops operations that reference any other registry before contacting it. Builds are disabled while an allow list is in effect, because WSL refuses them. |
Engine policy errors are shown in plain language wherever an operation fails. See the WSL enterprise documentation for how to configure the policies.
Not yet adopted: the Microsoft.WSL.Containers programming API (NuGet) that shipped with GA. The
app continues to drive wslc.exe; the API will be evaluated once the package has been published
long enough to meet this project's dependency-age policy.
This project is not a Microsoft product. It is an independent, community-developed application and is not affiliated with, endorsed by, sponsored by, or supported by Microsoft Corporation. "Windows", "WSL", "Azure", and related marks are trademarks of Microsoft; they are used here only to describe interoperability.
There is no support, no guarantee, and no warranty of any kind. This software is provided "AS IS", without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose, title, and non-infringement.
By building, installing, or running this software, you acknowledge and accept these terms. If you do not accept them, do not use this software.
This project is licensed under the GNU General Public License v3.0 — see the LICENSE file for the full text.
In short: you are free to use, study, modify, and share this software. If you distribute it — modified or not — you must make your version's complete source code available under the same GPLv3 terms. This keeps the project and any derivatives open; it prevents anyone from taking the code, making changes, and shipping it as a closed-source or proprietary commercial product. The GPLv3 also includes its own disclaimer of warranty and limitation of liability, which apply in addition to the Disclaimer above.
C#
99.5%