About
This skill creates and manages a headless Windows 11 virtual machine running in Docker with KVM acceleration. It provides SSH access for command-line control without requiring RDP or a GUI interface. Developers can use it to quickly spin up, stop, restart, or connect to a Windows VM for testing or development tasks.
Quick Install
Claude Code
Recommendednpx skills add obra/superpowers-lab -a claude-code/plugin add https://github.com/obra/superpowers-labgit clone https://github.com/obra/superpowers-lab.git ~/.claude/skills/windows-vmCopy and paste this command in Claude Code to install this skill
Documentation
Headless Windows 11 VM
Manage a headless Windows 11 VM running via dockur/windows in Docker with KVM acceleration. The VM is accessible via SSH only — no RDP or GUI required.
Host prerequisites
- Docker
- KVM support (
/dev/kvmmust exist — check withls /dev/kvm) sshpass(sudo apt install sshpass)imagemagick(optional, for screenshot debugging:sudo apt install imagemagick)
Configuration
- Container name:
windows11 - VM directory:
$HOME/windows-vm/storage/— VM disk image (managed by dockur, wiped on recreate)iso/win11x64.iso— cached Windows ISO (7.3GB, persists across recreates)oem/install.bat— post-install script (installs OpenSSH Server)
- Credentials: user / password
- SSH:
localhost:2222(bound to 127.0.0.1 only) - RDP:
localhost:3389(bound to 127.0.0.1 only, fallback) - Web console:
localhost:8006(VNC in browser, for debugging) - Resources: 8GB RAM, 4 CPU cores, 64GB disk
Actions
create — First-time setup or full recreate
-
Ensure directories exist:
mkdir -p "$HOME/windows-vm/oem" "$HOME/windows-vm/storage" "$HOME/windows-vm/iso" -
Ensure
$HOME/windows-vm/oem/install.batexists with OpenSSH setup:@echo off echo Installing OpenSSH Server... powershell -Command "Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0" 2>nul powershell -Command "Get-WindowsCapability -Online -Name OpenSSH.Server* | Add-WindowsCapability -Online" 2>nul dism /Online /Add-Capability /CapabilityName:OpenSSH.Server~~~~0.0.1.0 2>nul powershell -Command "Start-Service sshd" 2>nul powershell -Command "Set-Service -Name sshd -StartupType Automatic" powershell -Command "New-ItemProperty -Path 'HKLM:\SOFTWARE\OpenSSH' -Name DefaultShell -Value 'C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe' -PropertyType String -Force" powershell -Command "New-NetFirewallRule -Name 'OpenSSH-Server' -DisplayName 'OpenSSH Server' -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22" powershell -Command "Get-Service sshd" 2>nul echo Done. -
If recreating, remove the old container and disk:
docker stop windows11 && docker rm windows11 rm -f "$HOME/windows-vm/storage/data.img" -
Launch the container. There are two cases:
If cached ISO exists (
$HOME/windows-vm/iso/win11x64.iso):docker run -d \ --name windows11 \ -p 127.0.0.1:3389:3389 \ -p 127.0.0.1:2222:22 \ -p 127.0.0.1:8006:8006 \ -e RAM_SIZE="8G" \ -e CPU_CORES="4" \ -e DISK_SIZE="64G" \ -e USERNAME="user" \ -e PASSWORD="password" \ --cap-add NET_ADMIN \ --device /dev/kvm \ -v "$HOME/windows-vm/storage:/storage" \ -v "$HOME/windows-vm/oem:/oem" \ -v "$HOME/windows-vm/iso/win11x64.iso:/boot.iso" \ dockurr/windowsFirst time (no cached ISO) — omit the
/boot.isomount and addVERSION:docker run -d \ --name windows11 \ -p 127.0.0.1:3389:3389 \ -p 127.0.0.1:2222:22 \ -p 127.0.0.1:8006:8006 \ -e RAM_SIZE="8G" \ -e CPU_CORES="4" \ -e DISK_SIZE="64G" \ -e VERSION="win11" \ -e USERNAME="user" \ -e PASSWORD="password" \ --cap-add NET_ADMIN \ --device /dev/kvm \ -v "$HOME/windows-vm/storage:/storage" \ -v "$HOME/windows-vm/oem:/oem" \ dockurr/windowsAfter the ISO downloads and Windows boots, immediately copy the ISO out before the container is ever stopped (dockur wipes
/storageon recreate):cp "$HOME/windows-vm/storage/win11x64.iso" "$HOME/windows-vm/iso/win11x64.iso" -
Wait for Windows install + OpenSSH setup to complete. This takes 20-30 minutes for a fresh install (the OEM install.bat runs at the end of Windows OOBE and downloads OpenSSH from Microsoft, which is slow). Monitor with:
docker logs -f windows11You can also watch the VM screen via the web console at
http://localhost:8006.To check if SSH is up:
sshpass -p 'password' ssh -o StrictHostKeyChecking=no -o ConnectTimeout=5 -p 2222 user@localhost "whoami" -
Once SSH is responding, install Node.js and Claude Code by piping a setup script via stdin (avoids PowerShell escaping hell over SSH):
cat << 'PS' | sshpass -p 'password' ssh -o StrictHostKeyChecking=no -p 2222 user@localhost "powershell -ExecutionPolicy Bypass -Command -" # Download and install Node.js silently Invoke-WebRequest -Uri 'https://nodejs.org/dist/v22.14.0/node-v22.14.0-x64.msi' -OutFile 'C:\Users\user\node-install.msi' Start-Process msiexec.exe -ArgumentList '/i C:\Users\user\node-install.msi /qn /norestart' -Wait -Verb RunAs Write-Host "Node.js installed" # Install Claude Code globally & 'C:\Program Files\nodejs\npm.cmd' install -g @anthropic-ai/claude-code Write-Host "Claude Code installed" # Add npm global bin to SYSTEM PATH (user PATH is not read by sshd) $systemPath = [Environment]::GetEnvironmentVariable('Path', 'Machine') $additions = @() if ($systemPath -notlike '*AppData*npm*') { $additions += 'C:\Users\user\AppData\Roaming\npm' } if ($systemPath -notlike '*Git\cmd*') { $additions += 'C:\Program Files\Git\cmd' } if ($additions.Count -gt 0) { [Environment]::SetEnvironmentVariable('Path', $systemPath + ';' + ($additions -join ';'), 'Machine') Write-Host "Added to system PATH: $($additions -join ', ')" } # Set execution policy machine-wide (required for claude.ps1) Set-ExecutionPolicy RemoteSigned -Scope LocalMachine -Force -ErrorAction SilentlyContinue # Create system-wide PowerShell profile that rebuilds PATH from registry on login. # Without this, interactive SSH sessions don't pick up the full system PATH. $profileDir = Split-Path $PROFILE.AllUsersAllHosts if (-not (Test-Path $profileDir)) { New-Item -ItemType Directory -Path $profileDir -Force } @' $machinePath = [Environment]::GetEnvironmentVariable('Path', 'Machine') $userPath = [Environment]::GetEnvironmentVariable('Path', 'User') $env:Path = "$machinePath;$userPath" '@ | Set-Content -Path $PROFILE.AllUsersAllHosts -Force Write-Host "PowerShell profile created" # Restart sshd so it picks up the new PATH Restart-Service sshd -Force PSNote: the connection will drop when sshd restarts — that's expected.
-
Clear the stale host key (new VM = new host key) and verify:
ssh-keygen -f ~/.ssh/known_hosts -R '[localhost]:2222' sshpass -p 'password' ssh -o StrictHostKeyChecking=no -p 2222 user@localhost "claude --version"
start — Start a stopped VM
docker start windows11
stop — Stop the VM
docker stop windows11
restart — Restart the VM
docker restart windows11
status — Check VM status
docker ps -f name=windows11 --format "table {{.Status}}\t{{.Ports}}"
docker logs windows11 2>&1 | tail -5
ssh — Connect to the VM
ssh -p 2222 user@localhost
screenshot — See what's on the VM screen (for debugging)
docker exec windows11 bash -c "echo 'screendump /tmp/screen.ppm' | nc -w 2 localhost 7100" > /dev/null 2>&1
sleep 1
docker cp windows11:/tmp/screen.ppm /tmp/screen.ppm
convert /tmp/screen.ppm /tmp/screen.png
Important Notes
- ISO caching: The
/storagevolume is managed by dockur and gets wiped on recreate. Store the ISO separately in$HOME/windows-vm/iso/and mount it as/boot.isoto skip the 7.3GB download. --cap-add NET_ADMINis required for port forwarding to work. Without it, QEMU falls back to user-mode networking and port forwarding silently fails.--device /dev/kvmis required for hardware acceleration.- Boot time: Fresh install takes 20-30 min (Windows install + OpenSSH download from Microsoft). Subsequent boots from existing
data.imgare fast (~2 min). - Ports are bound to
127.0.0.1only — not exposed to the network. - Do NOT use
-e VERSION="win11"when mounting/boot.iso— the version is auto-detected from the ISO.
Post-install gotchas
- Node.js is not pre-installed — the Claude Code install script (
irm https://claude.ai/install.ps1 | iex) will report success butclaudewon't work without Node. Install Node.js via MSI first. - npm global bin not in PATH — Node's MSI adds
C:\Program Files\nodejsto PATH but notC:\Users\user\AppData\Roaming\npm(wherenpm install -gputs binaries). Must add it to the system PATH (not user PATH) because OpenSSH's sshd only reads system PATH. After changing system PATH, restart sshd. - PowerShell execution policy — Default policy is
Restricted, which blocksclaude.ps1. Must set toRemoteSignedat LocalMachine scope (not CurrentUser) for it to take effect in SSH sessions. - Escaping hell — Running PowerShell commands over SSH with nested quotes is unreliable. Pipe scripts via stdin using
powershell -ExecutionPolicy Bypass -Command -instead. - Interactive SSH sessions don't get full PATH — Windows OpenSSH sshd doesn't properly propagate the system PATH to interactive PowerShell sessions. Fix: create a system-wide PowerShell profile (
$PROFILE.AllUsersAllHosts) that rebuilds$env:Pathfrom the registry on every login. - winget may not work — The Microsoft Store certificate can fail in a VM. Use direct MSI/installer downloads instead.
- Host key changes — Each recreated VM gets new SSH host keys. Run
ssh-keygen -R '[localhost]:2222'to clear the old one.
GitHub Repository
Frequently asked questions
What is the windows-vm skill?
windows-vm is a Claude Skill by obra. Skills package instructions and resources that Claude loads on demand, so Claude can perform windows-vm-related tasks without extra prompting.
How do I install windows-vm?
Use the install commands on this page: add windows-vm to Claude Code as a plugin, or clone its repository into your skills directory, then restart Claude so it picks up the skill.
What category does windows-vm belong to?
windows-vm is in the Meta category.
Is windows-vm free to use?
Yes. windows-vm is listed on AIMCP and free to install.
Related Skills
This skill provides a production-tested setup for Content Collections, a TypeScript-first tool that transforms Markdown/MDX files into type-safe data collections with Zod validation. Use it when building blogs, documentation sites, or content-heavy Vite + React applications to ensure type safety and automatic content validation. It covers everything from Vite plugin configuration and MDX compilation to deployment optimization and schema validation.
This skill enables developers to build applications with the Polymarket prediction markets platform, including API integration for trading and market data. It also provides real-time data streaming via WebSocket to monitor live trades and market activity. Use it for implementing trading strategies or creating tools that process live market updates.
This skill helps developers create OpenCode plugins that hook into 25+ event types like commands, files, and LSP operations. It provides the plugin structure, event API specifications, and implementation patterns for JavaScript/TypeScript modules. Use it when you need to intercept, monitor, or extend the OpenCode AI assistant's lifecycle with custom event-driven logic.
SGLang is a high-performance LLM serving framework that specializes in fast, structured generation for JSON, regex, and agentic workflows using its RadixAttention prefix caching. It delivers significantly faster inference, especially for tasks with repeated prefixes, making it ideal for complex, structured outputs and multi-turn conversations. Choose SGLang over alternatives like vLLM when you need constrained decoding or are building applications with extensive prefix sharing.
