winkit

package module
v0.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 9, 2026 License: Apache-2.0 Imports: 15 Imported by: 0

README

go-winkit

A disposable Windows machine with a Linux shell, from one YAML file, in minutes, on your Mac or Linux box.

winkit builds Windows VM images without anyone clicking through an installer. It fetches the media, writes the answer file, drives the install in QEMU, runs your scripts, and hands back a disk image you can boot or throw away. It is the Windows layer behind devcell, and it works on its own.

Try it

brew install qemu wimlib      # Docker Desktop running for the rootfs build
task install                  # builds ./bin/winkit and copies it to ~/.local/bin

winkit build --file examples/pe-wsl1-alpine winkit-core.qcow2
winkit start winkit-core.qcow2
winkit ssh winkit-core -- 'wsl -d winkit --exec cat /etc/alpine-release'
winkit stop winkit-core

The first build downloads Windows media and builds an Alpine rootfs with Docker, so it takes a while. After that everything is cached and start is the only wait. start holds the terminal until the guest answers SSH, then prints how to reach it.

Who this is for

  • You develop on Apple Silicon and need a Windows box that appears and disappears on command. Native ARM64, HVF or Virtualization.framework, no Parallels license.
  • You run CI that touches Windows drivers, installers, or WIM files and do not want to babysit a licensed VM. Build the image once and boot it for each job.
  • You maintain a dev environment tool and want Windows as a target without owning the install pipeline. Use the Go API; devcell does.

If you want a Windows desktop to use by hand, UTM or dockur/windows is a better fit. winkit is for the unattended path.

Three ways to build

Mode winkit.yaml What you get Disk
Core pe: true + wsl: WinPE boot volume with WSL1 Alpine or Nix, SSH, drvfs to Windows paths. Fresh on every boot, state on a data disk. ~4 GB
PE pe: true WinPE alone, with gosshd as the shell. For driver tests and media validation. ~4 GB
Full neither A real Windows 11 install with OpenSSH and RDP, optionally with WSL1. For things that need a desktop or Windows services. ~64 GB

Output is qcow2 by default, or --image-type utm for UTM and box for a Vagrant box with a vagrant-qemu Vagrantfile.

Why WSL1 and not WSL2: WSL1 is a syscall layer, not a VM. It needs no nested virtualization, shares the Windows network stack, and reads host files through drvfs. That is what makes a Linux shell inside WinPE under QEMU possible at all. Microsoft does not support this combination. winkit ships the runtime and has end to end tests that boot it.

The config

from: windows/11-pro-arm64
pe: true
wsl:
  image: alpine          # or nix, any docker ref, a .wsl URL, a local tarball
  services: ./s6         # s6 service dirs supervised inside the distro
commands:
  boot:
    - powershell C:/scripts/tools.ps1
hostname: winkit
ports:
  gossh: 20022
  rdp: 23389

winkit init writes a fully commented template. Hooks run per Windows setup pass (specialize, oobe, boot, wsl) with per command timeout, retries, and reboot control.

Examples

Each directory is a complete winkit.yaml plus a README. They are load tested in CI so they cannot drift from the schema.

Beyond build and start

winkit status, logs, and stop manage running VMs; winkit cp pushes a file into one (winkit cp tool.exe E:\apps\tool.exe). winkit export exposes the pieces on their own: render and validate autounattend.xml, build and inspect bootable ISOs, inject a payload into boot.wim, or assemble a standalone WinPE ISO. winkit debug fetch pre-caches media for CI, debug diag reads Windows Setup logs off the guest, and debug features shows what a WIM has baked in. --debug traces every file, WIM, and download operation.

As a library

go get github.com/devcell-sh/go-winkit

build is the entry point: one call from install media to a disk image. vm boots it, with vm/qemu and vm/vz backends. media/* fetches Windows builds from the Microsoft Update Catalog and UUP dump plus the virtio-win drivers. winpe prepares and provisions the image, wsl turns Docker images into WSL rootfs tarballs, unattend renders answer files, and gosshd is a small SSH server cross compiled into guests that have no OpenSSH. What winkit owns and what it leaves to consumers is written down in ARCHITECTURE.md.

There is no v1 tag yet. Pin a version if you depend on it.

Limits

  • QEMU on Linux (KVM) and macOS (HVF), plus Virtualization.framework on macOS 13+. No Hyper-V.
  • Windows media licensing is yours. winkit downloads public media from Microsoft and does not activate anything.
  • WIM modifying commands need a build with libwim linked, which is what task install does.

Testing

Tiers by what they need. Only the first runs anywhere.

Tier Command Needs
Unit task test nothing
WIM go test -tags wimlib ./winpe/ libwim
Real media go test ./winpe/ ./test/e2e/ seeded cache
Boot task test:integration seeded cache, libwim, QEMU

Tiers past the first read install media from a cache, so a boot test reruns in minutes instead of repaying a multi gigabyte download. Seed it once with task test:seed; task test:seed:where prints the paths and what is missing. Unseeded tests skip and name the path they wanted. The cache lives under the user cache dir (~/.cache/winkit on Linux); WINKIT_CACHE_DIR overrides it for both the CLI and the tests.

Documentation

Overview

Package winkit builds Windows VM images from code. This root package is the library entry point consumers embed (devcell, CI pipelines): fill a build.Config, call Build, get a disk image. The winkit CLI is a thin frontend over the same call.

The contract: winkit owns the verbs (fetch, service, install, import, execute hooks, package); the consumer owns the nouns (which WSL image, which services, which packages) via buildopts.BuildOpts and hooks. See the examples/ directory for both YAML and library consumers.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Build

func Build(ctx context.Context, cfg build.Config) error

Build produces a Windows image from cfg, dispatching on cfg.Opts: PE mode assembles a WinPE boot volume, a WSL config runs a full install with the distro imported, otherwise a base install runs. cfg.Opts may be nil (defaults apply). Dest, WindowsISO and VirtIOISO are required; an empty WorkDir gets a temp dir that is removed when Build returns.

func Start

func Start(ctx context.Context, opts StartOpts) (vm.VM, error)

Start boots a previously built image and registers it in the state dir so Status and the winkit CLI can manage it. The returned handle exposes Stop, Wait, Done, SSHAddr, PID. This is the library form of `winkit start`; devcell's engine adapter wraps it.

func Status

func Status(stateDir string) ([]*vmstate.State, error)

Status lists the VMs registered in stateDir (default ~/.winkit/run) as saved by Start / `winkit start`. Dead entries are included; vmstate.IsAlive distinguishes them.

Types

type StartOpts

type StartOpts struct {
	// Image is the built disk image to boot (qcow2 for QEMU).
	Image string
	// Name identifies the VM in state/status; defaults to the image
	// filename without extension.
	Name string
	// Hostname is applied as the guest computer name via the SMBIOS
	// serial on next boot; defaults to the unattend default.
	Hostname string
	// Accel selects the accelerator (kvm, hvf, tcg); default: best for
	// the host.
	Accel string
	// StateDir holds running-VM state for Status/stop; default
	// ~/.winkit/run.
	StateDir string
	CPUs     uint
	MemoryGB uint64
	// SSHPort forwards to the guest provisioning SSH (gosshd, :2222).
	// The delivered Windows OpenSSH lands on SSHPort+100.
	SSHPort uint16
	RDPPort uint16
	// Foreground keeps the VM attached to the calling process; the
	// default detaches it so the handle outlives the caller.
	Foreground bool
	// VNCPort selects the host VNC port (default 5900). VNC is always enabled.
	VNCPort uint16
	// Forwards are extra host→guest TCP forwards (winkit.yaml ports.forward,
	// `winkit start --forward host:guest`).
	Forwards []vm.PortForward
	// Logger receives host-side events; nil logs to run.jsonl in the
	// VM's output directory.
	Logger *slog.Logger
}

StartOpts configures Start. Only Image is required; zero values get the CLI's defaults (4 vCPUs, 6 GB, SSH 20022, RDP 23389, backend auto-detected).

Directories

Path Synopsis
Package build orchestrates full unattended Windows image builds: media prep, answer volume, VM install, provisioning over gosshd, verification, and clean shutdown.
Package build orchestrates full unattended Windows image builds: media prep, answer volume, VM install, provisioning over gosshd, verification, and clean shutdown.
Package cache resolves where winkit stores large downloaded artifacts: installer ISOs, driver ISOs and the ESD files they are assembled from.
Package cache resolves where winkit stores large downloaded artifacts: installer ISOs, driver ISOs and the ESD files they are assembled from.
cmd
winkit command
Command winkit is the host-side CLI over the go-winkit packages: fetch Windows install media, build bootable and WinPE ISOs, generate and validate autounattend answer files, patch WIMs, and read guest diagnostics.
Command winkit is the host-side CLI over the go-winkit packages: fetch Windows install media, build bootable and WinPE ISOs, generate and validate autounattend answer files, patch WIMs, and read guest diagnostics.
winkit-service command
Command winkit-service wraps an arbitrary command as a system service.
Command winkit-service wraps an arbitrary command as a system service.
examples
library-consumer command
Command library-consumer is the devcell-shaped reference consumer of winkit's Go API: no winkit.yaml, everything programmatic.
Command library-consumer is the devcell-shaped reference consumer of winkit's Go API: no winkit.yaml, everything programmatic.
Package gosshd is an SSH server for WinPE guests.
Package gosshd is an SSH server for WinPE guests.
cmd/gosshd command
Command gosshd is the SSH server staged into a guest.
Command gosshd is the SSH server staged into a guest.
internal
cli
Package cli implements the winkit command tree.
Package cli implements the winkit command tree.
iotrace
Package iotrace records the IO a build performs: files opened and written, WIM images exported, images mastered, bytes downloaded.
Package iotrace records the IO a build performs: files opened and written, WIM images exported, images mastered, bytes downloaded.
templates
Package templates holds the guest PowerShell scripts shipped by winkit.
Package templates holds the guest PowerShell scripts shipped by winkit.
Package media is winkit's install-media fetch policy: which source serves the Windows installer ISO, in what order, and with what fallback.
Package media is winkit's install-media fetch policy: which source serves the Windows installer ISO, in what order, and with what fallback.
virtio
Package virtio downloads the virtio-win driver ISO, the source of the storage, serial and network drivers WinPE needs to see a QEMU guest's devices.
Package virtio downloads the virtio-win driver ISO, the source of the storage, serial and network drivers WinPE needs to see a QEMU guest's devices.
Package s6 models s6 service directories: the unit of supervision under an s6-svscan scan dir (in winkit's WSL distro, /etc/s6/services).
Package s6 models s6 service directories: the unit of supervision under an s6-svscan scan dir (in winkit's WSL distro, /etc/s6/services).
Package sftpshare serves a host directory to VM guests over SFTP.
Package sftpshare serves a host directory to VM guests over SFTP.
tools
renderps1 command
renderps1 renders the embedded PowerShell templates with representative sample data so PSScriptAnalyzer can lint the actual scripts a consumer ships.
renderps1 renders the embedded PowerShell templates with representative sample data so PSScriptAnalyzer can lint the actual scripts a consumer ships.
seedstatus command
Command seedstatus prints the cache paths the real-media tests read and whether each one is seeded.
Command seedstatus prints the cache paths the real-media tests read and whether each one is seeded.
vmkey command
Command vmkey drives a running QEMU guest's keyboard over its QMP socket, so you can interact with a VM that has no working network yet (e.g.
Command vmkey drives a running QEMU guest's keyboard over its QMP socket, so you can interact with a VM that has no working network yet (e.g.
vm
Package vm is the backend-agnostic VM layer: the VM and VMBackend interfaces, install/run configuration, and disk-format types.
Package vm is the backend-agnostic VM layer: the VM and VMBackend interfaces, install/run configuration, and disk-format types.
vmstate
Package vmstate tracks running winkit VMs via JSON state files.
Package vmstate tracks running winkit VMs via JSON state files.
vz
Package wsl builds WSL 1-compatible rootfs tarballs (.wsl) from Docker images.
Package wsl builds WSL 1-compatible rootfs tarballs (.wsl) from Docker images.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL