Windows Agents
Crow can execute pipelines on Windows hosts using the Docker backend in Windows-container mode. This page covers the architecture, host requirements, recommended images, and known caveats.
Backend Support
Section titled “Backend Support”| Backend | Windows | Notes |
|---|---|---|
docker | ✅ | Container steps (incl. clone); see below |
local | ⚠️ | Works if everything you run is a native Windows executable |
kubernetes | ❌ | Pod scheduling onto Windows nodes is not implemented yet |
podman | ❌ | Podman doesn’t run on Windows in the way Crow expects |
The rest of this page assumes the docker backend.
Linux Docker vs Windows Docker
Section titled “Linux Docker vs Windows Docker”Docker on Linux and Docker on Windows share a CLI but run different container runtimes with different constraints. Understanding these differences explains most of the Windows-specific behavior on this page.
| Concern | Linux Docker | Windows Docker (Windows-container mode) |
|---|---|---|
| Containers it can run | Linux containers only | Windows containers only — Linux images fail at docker pull |
| Image manifest tag | linux/amd64, linux/arm64, … | windows/amd64 matching the host build (LTSC2022, etc.) |
| Base image size | Tens of MB (alpine ~5 MB) | Hundreds of MB to multi-GB (nanoserver ~290 MB, servercore ~3 GB) |
| Step entrypoint (Crow) | /bin/sh against the container | pwsh directly — cmd.exe and Windows PowerShell 5.1 don’t work as entrypoint |
| Clone step (Crow) | Linux clone plugin container (crow-plugins/clone) | Windows variant of the clone image (…-windows-ltsc2022) |
| Host OS requirement | Any Linux distro with Docker CE | Windows Server 2022+ with Docker CE in Windows-container mode |
The key consequence: image manifests don’t cross OS boundaries.
A Linux image manifest cannot be pulled on a Windows daemon, and vice versa.
This is why every workflow in a mixed pool needs explicit labels: platform: — the scheduler must not put a Linux job on a Windows agent or it will fail at docker pull.
It is also why the clone step needs a Windows-specific image (see below).
How It Works
Section titled “How It Works”Every step on a Windows agent — including the clone — runs as a normal Windows container via docker run.
Crow’s standard clone image (crow-plugins/clone) is published as a Linux image, which cannot run on a Windows daemon, so a separate Windows image is published with a -windows-ltsc2022 tag suffix.
On a Windows agent the docker backend automatically rewrites the clone step’s image tag to that Windows variant and always re-pulls it:
| Configured clone image | Image actually used on Windows |
|---|---|
codefloe.com/crow-plugins/clone:1.1.0 | codefloe.com/crow-plugins/clone:1.1.0-windows-ltsc2022 |
The rewrite appends -windows-ltsc2022 to the existing tag (a digest-pinned reference is left unchanged) and forces a pull, so a reused agent VM never runs a stale cached image.
The clone runs in the container with the workflow volume mounted at the workspace path, so subsequent steps (which mount the same named volume) see the cloned source — standard Docker volume sharing, identical to Linux.
Host Requirements
Section titled “Host Requirements”| Requirement | Notes |
|---|---|
| Windows Server 2022+ | LTSC builds. Earlier versions lack the HCS features Crow relies on. |
| Docker CE | In Windows-container mode (the default on Windows Server). Tested on Docker 25.x. |
| Network egress | The agent needs outbound HTTPS to your forge, to MCR (mcr.microsoft.com), and to your container registry. |
git is not required on the host — cloning happens inside the clone container.
AWS’s Windows_Server-2022-English-Full-ECS_Optimized AMI matches all of these out of the box (Docker 25.x pre-installed) and is the recommended starting point if you’re using the autoscaler.
Recommended Container Images
Section titled “Recommended Container Images”Step images must have pwsh (PowerShell 7+) on PATH.
Crow invokes pwsh directly as the container entrypoint to sidestep cmd.exe’s argument-quoting quirks, which silently corrupt our launcher when interleaved with Docker’s standard argv escaping.
Windows PowerShell 5.1 (powershell.exe) is not supported as an entrypoint.
| Image | Works | Approx. size on disk | Notes |
|---|---|---|---|
mcr.microsoft.com/powershell:nanoserver-ltsc2022 | ✅ | ~290 MB | Default. Smallest image with PowerShell 7 on PATH. |
mcr.microsoft.com/powershell:windowsservercore-ltsc2022 | ✅ | ~3 GB | Full Server Core APIs plus both PowerShell editions. |
mcr.microsoft.com/windows/servercore:ltsc2022 | ❌ | ~2 GB | Only ships powershell.exe (5.1), no pwsh. Use the powershell:windowsservercore-* variant instead. |
mcr.microsoft.com/windows/nanoserver:ltsc2022 | ❌ | ~120 MB | Only ships cmd.exe. Use the powershell:nanoserver-* variant instead. |
The clone image must be servercore-based
Section titled “The clone image must be servercore-based”git submodule is the one git operation that shells out to a POSIX helper run via the bundled MSYS2 sh.exe.
That shell cannot start on nanoserver (it fails with STATUS_ENTRYPOINT_NOT_FOUND because nanoserver lacks Win32 APIs the MSYS2 runtime needs).
The published Windows clone image is therefore servercore-based.
This only affects the clone image — your step images can still be nanoserver-based as long as they don’t run git submodule themselves.
Building Windows container images in pipelines
Section titled “Building Windows container images in pipelines”Windows images must be built on a Windows host, and the Docker buildx multi-arch flow used for Linux doesn’t apply.
The pattern is docker-out-of-docker: a step mounts the host Docker daemon’s named pipe and runs docker build/docker push:
The build context is sent to the daemon by the in-container Docker client, so a normal . context works as long as the workspace is populated (i.e. the clone succeeded).
Routing Workflows
Section titled “Routing Workflows”Once you have a mix of Linux and Windows agents, every workflow needs explicit labels so the scheduler picks the right host.
Windows-only workflows
Section titled “Windows-only workflows”Use the built-in platform label:
Or filter per-step with when::
Cross-platform workflows
Section titled “Cross-platform workflows”Linux-only workflows
Section titled “Linux-only workflows”If a Windows agent is in the pool, every existing Linux workflow must also have explicit labels — otherwise the scheduler may put a Linux-only job onto a Windows agent and it will fail at docker pull (Linux image manifest on a Windows daemon).
Autoscaler Integration
Section titled “Autoscaler Integration”The Crow Autoscaler can provision Windows VMs on demand. The configuration shape is identical to a Linux autoscaler with two key differences:
| Setting | Linux | Windows |
|---|---|---|
CROW_AGENT_IMAGE | Container image reference | URL to the crow-agent_windows_amd64.zip artifact — the autoscaler downloads it onto the VM. |
| Provider OS field | linux (provider-default) | Set the provider’s Windows flag (e.g. CROW_AWS_OS=windows). |
Minimal AWS Windows-autoscaler config:
See Autoscaler configuration for the full surface.
Caveats
Section titled “Caveats”First-step image pull is slow
Section titled “First-step image pull is slow”A fresh Windows VM has Docker installed but no images pre-pulled.
The first step that uses mcr.microsoft.com/powershell:nanoserver-ltsc2022 will pull ~290 MB; windowsservercore-based images (including the clone image) can take several minutes to pull on first use.
Pull progress goes to the agent’s stdout, not the step output in the UI, so the workflow may appear to hang. Subsequent runs on the same VM are instant.
Mitigations:
- Pre-pull common images in user-data when provisioning the VM.
- Bake a custom AMI with the images already present (e.g. with Packer).
- Run a registry pull-through cache in the same region.
The clone image is always re-pulled
Section titled “The clone image is always re-pulled”Because the Windows clone tag is mutable, the agent forces a pull of the clone image on every clone step so a reused VM can’t run a stale copy. This adds the (cached after first use) pull cost per fresh VM.