Reference · reference

Guest OS profile files

7 min read · 2026-09-02 · vmlab 0.9

A guest OS profile is a named bundle of known-good hardware defaults. It is the floor of the hardware resolution chain: a value not set on the VM and not recorded by its template comes from the profile. Profiles are data, shipped as WCL and extensible from a directory in your config. Guest OS profiles explains when to write one; this chapter lists the fields, the shipped set and where user files go.

Where profiles live

The shipped profiles are compiled into the binary. User profiles are *.wcl files in the profiles directory of vmlab's XDG config directory, ~/.config/vmlab/profiles/ by default; see Files and directories. Every file there is loaded in sorted filename order after the shipped set, and a profile whose name matches a shipped one replaces it entirely rather than merging with it. A file must start with import <vmlab-profile.wcl>; one without the import is rejected, and so is any file with an unknown field, a bad keyword or a wrong type, with the line named.

~/.config/vmlab/profiles/mine.wclwcl
import <vmlab-profile.wcl>

profile "freebsd" {
  description = "FreeBSD 14: q35, SeaBIOS, virtio disk and NIC"
  machine     = "q35"
  firmware    = "seabios"
  disk_bus    = "virtio"
  nic_model   = "virtio-net-pci"
  display     = "std"
  cpus        = 2
  memory      = 2GiB
}

profile {}

One profile. Every field is optional. A field left unset means the QEMU default applies for that device, which is what the shipped custom profile relies on.

wcl
profile "<name>" {
  description     = "…"
  machine         = "q35"
  firmware        = "ovmf"
  secure_boot     = false
  tpm             = false
  disk_bus        = "virtio"
  nic_model       = "virtio-net-pci"
  display         = "virtio-vga"
  cpus            = 2
  memory          = 4GiB
  agent_transport = "virtio-serial"
  input_transport = "qmp"
  virtiofs        = false
  workspace_guest = "/src"
}
FieldTypeDefaultMeaning
nameutf8 (label)requiredProfile name, what a vm, container or template names in profile =; the inline block label.
descriptionutf8noneHuman-readable summary. Parsed and kept; no verb surfaces it yet.
machineutf8QEMU defaultMachine type: q35, or pc for i440fx.
firmwareutf8QEMU defaultFirmware: ovmf or seabios.
secure_bootboolunsetEnable secure boot; OVMF only.
tpmboolunsetAttach a swtpm 2.0 device.
disk_busutf8QEMU defaultPrimary disk bus: virtio, ide or sata.
nic_modelutf8QEMU defaultNIC device model, for example virtio-net-pci, e1000, rtl8139 or pcnet.
displayutf8QEMU defaultDisplay device, for example virtio-vga, qxl, std or cirrus-vga.
cpusi64unsetDefault vCPU count, at least 1.
memoryByteSizeunsetDefault RAM, for example 4GiB.
agent_transportutf8virtio-serialThe guest agent channel's device: virtio-serial, isa-serial (a 16550 on COM1 for the legacy agent; the serial log moves to COM2), or none (no agent; never ready by handshake).
agent_channelboolunsetSuperseded by agent_transport; still accepted: true reads as virtio-serial, false as none, and agent_transport wins when both are present.
input_transportutf8qmpHow scripted input reaches the guest: qmp send-key, or vnc for guests that ignore the PS/2 path.
virtiofsboolfalseThe guest mounts virtiofs natively, so transport = "auto" shares use it instead of SMB.
workspace_guestutf8unsetGuest path an @dev workspace lands at when the decorator names none.

The parser enforces the keyword sets above for machine, firmware, disk_bus and input_transport, cpus at least 1, and a non-negative memory. nic_model and display are passed to QEMU as written. A profile that sets no workspace_guest still hosts a dev machine; the floor of /src applies. On a non-x86 virt machine a virtio-vga display is downgraded to virtio-gpu-pci, which has no legacy VGA.

The profile a machine resolves against is the one it names, else the one its template recorded, else the default. Validation reports an unknown profile name on the block that names it. A login {} block's family rules read the resolved profile's name: windows* is Windows, linux* is Linux, and any other name is unknown and gets neither rule.

Shipped profiles

The shipped set, with the values each one carries. A blank cell means the field is unset. Every Windows profile lands an @dev workspace at C:\src and every Linux one at /src.

ProfileMachineFirmwareSecure bootTPMDisk busNIC modelDisplayCPUsMemoryOther
windows-11q35ovmftruetruevirtiovirtio-net-pcivirtio-vga48GiB
windows-10q35ovmffalsefalsevirtiovirtio-net-pcivirtio-vga48GiB
windows-serverq35ovmffalsetruevirtiovirtio-net-pcivirtio-vga48GiB
windows-legacypcseabiosfalsefalseidee1000std22GiBXP, 7 and 2008-era guests with no virtio drivers.
windows-9xpcseabiosfalsefalseidepcnetcirrus-vga1256MiBinput_transport = "vnc". DOS, Windows 3.x to ME and 2000-era guests.
linux-modernq35ovmffalsefalsevirtiovirtio-net-pcivirtio-vga24GiBvirtiofs = true.
linux-genericq35seabiosfalsefalsevirtiovirtio-net-pcistd22GiBOlder or unusual distros.
container1256MiBMicro-VM size for an OCI container; nothing else applies to a container.
customNothing assumed; supply everything on the VM or template and in qemu_args.

The container profile carries only a size because a container micro-VM boots the guest asset directly and has no firmware, disk bus, display or NIC model to choose. Its floor is an order of magnitude below a VM's on purpose: the micro-VM runs one process, not an operating system. Raise it per container with cpus and memory, or drop your own container profile into the user directory to change the default for every lab.

Overriding replaces, it does not merge

A user profile named windows-11 replaces the shipped one completely. A file holding only profile "windows-11" { machine = "pc" } leaves that profile with no firmware, disk bus or memory. Copy the full shipped block and change the fields you need.

src/profiles/shipped.wclwcl
import <vmlab-profile.wcl>

// Shipped guest OS profiles (PRD §5.3). Known-good hardware defaults;
// values not set on the VM or template inherit from these. Override or
// extend by dropping `*.wcl` files into `~/.config/vmlab/profiles/`.
//
// No Windows profile sets `virtiofs`: virtio-win 0.1.302's VioFS driver fails
// large reads at random, so `transport = "auto"` shares on Windows ride SMB
// (§7.5).

profile "windows-11" {
  description = "Windows 11: q35, OVMF with secure boot, swtpm 2.0, virtio devices"
  machine     = "q35"
  firmware    = "ovmf"
  secure_boot = true
  tpm         = true
  disk_bus    = "virtio"
  nic_model   = "virtio-net-pci"
  display     = "virtio-vga"
  cpus        = 4
  memory      = 8GiB
  // Where an `@dev` workspace lands when the decorator names no
  // `workspace_guest` (§19.1) — the key is guest-OS-shaped, which is why it
  // is profile-sourced.
  workspace_guest = "C:\\src"
}

profile "windows-10" {
  description = "Windows 10: q35, OVMF, virtio devices (no TPM/secure boot required)"
  machine     = "q35"
  firmware    = "ovmf"
  secure_boot = false
  tpm         = false
  disk_bus    = "virtio"
  nic_model   = "virtio-net-pci"
  display     = "virtio-vga"
  cpus        = 4
  memory      = 8GiB
  workspace_guest = "C:\\src"
}

profile "windows-server" {
  description = "Windows Server: q35, OVMF, swtpm 2.0, virtio devices"
  machine     = "q35"
  firmware    = "ovmf"
  secure_boot = false
  tpm         = true
  disk_bus    = "virtio"
  nic_model   = "virtio-net-pci"
  display     = "virtio-vga"
  cpus        = 4
  memory      = 8GiB
  workspace_guest = "C:\\src"
}

profile "windows-legacy" {
  description = "Vista/7/2008-era guests with no virtio storage/net drivers at install time: i440fx, SeaBIOS, IDE disk, e1000 NIC, std VGA; virtio-serial agent channel (virtio-win covers this era)"
  machine     = "pc"
  firmware    = "seabios"
  secure_boot = false
  tpm         = false
  disk_bus    = "ide"
  nic_model   = "e1000"
  display     = "std"
  cpus        = 2
  memory      = 2GiB
  workspace_guest = "C:\\src"
}

profile "windows-xp" {
  description = "NT4 through XP/2003: i440fx, SeaBIOS, IDE disk, e1000 NIC, std VGA; no virtio drivers at all, so the agent channel is a 16550 on COM1 (the legacy agent)"
  machine     = "pc"
  firmware    = "seabios"
  secure_boot = false
  tpm         = false
  disk_bus    = "ide"
  nic_model   = "e1000"
  display     = "std"
  cpus        = 2
  memory      = 2GiB
  agent_transport = "isa-serial"
  workspace_guest = "C:\\src"
}

profile "windows-9x" {
  description = "DOS / Windows 3.x-ME / 2000-era PCs: i440fx, SeaBIOS, IDE disk, Cirrus VGA, AMD PCnet NIC (all drivable by these guests); cap RAM low per template"
  machine     = "pc"
  firmware    = "seabios"
  secure_boot = false
  tpm         = false
  disk_bus    = "ide"
  nic_model   = "pcnet"
  display     = "cirrus-vga"
  cpus        = 1
  memory      = 256MiB
  agent_transport = "isa-serial"
  // Real-mode DOS/9x TUIs (fdisk, setup) drop QMP send-key events between menu
  // redraws; drive their keyboard over VNC instead, which lands reliably.
  input_transport = "vnc"
  workspace_guest = "C:\\src"
}

profile "templeos" {
  description = "TempleOS: i440fx, SeaBIOS, IDE disk, std VGA (it drives VBE directly), no network by design; the agent channel is a 16550 on COM1 for the HolyC agent"
  machine     = "pc"
  firmware    = "seabios"
  secure_boot = false
  tpm         = false
  disk_bus    = "ide"
  nic_model   = "e1000"
  display     = "std"
  cpus        = 2
  memory      = 512MiB
  agent_transport = "isa-serial"
}

profile "linux-modern" {
  description = "Modern Linux: q35, OVMF, virtio everything"
  machine     = "q35"
  firmware    = "ovmf"
  secure_boot = false
  tpm         = false
  disk_bus    = "virtio"
  nic_model   = "virtio-net-pci"
  // VGA-compatible virtio GPU on x86; auto-downgrades to virtio-gpu-pci on the
  // non-x86 `virt` machine (no legacy VGA there). See display_device_name.
  display     = "virtio-vga"
  cpus        = 2
  memory      = 4GiB
  // Kernel ≥5.4 ships the virtiofs client — `transport = "auto"` shares
  // mount natively instead of over SMB (§7.5).
  virtiofs    = true
  workspace_guest = "/src"
}

profile "linux-generic" {
  description = "Older or unusual distros: q35, SeaBIOS, virtio disk/net, conservative elsewhere"
  machine     = "q35"
  firmware    = "seabios"
  secure_boot = false
  tpm         = false
  disk_bus    = "virtio"
  nic_model   = "virtio-net-pci"
  display     = "std"
  cpus        = 2
  memory      = 2GiB
  workspace_guest = "/src"
}

profile "container" {
  description = "Micro-VM defaults for an OCI container (PRD §18): the smallest shape that boots the guest asset and a typical service image"
  // A container micro-VM boots the guest asset directly — no firmware, disk
  // bus, display or NIC model to choose — so this profile carries only the
  // size, which is the whole reason a container names a profile. It is an
  // order of magnitude below the VM floor on purpose: the micro-VM runs one
  // process, not an operating system. Raise it per container with
  // `memory = …`, or drop your own `container` profile into
  // ~/.config/vmlab/profiles to change the default for every lab.
  cpus   = 1
  memory = 256MiB
  workspace_guest = "/src"
}

profile "custom" {
  description = "Nothing assumed — supply everything via VM/template attributes and qemu_args"
}