internals/skills/ovmf/SKILL.md
UEFI firmware (OVMF_CODE + OVMF_VARS) path resolution for VMs. Covers the per-distro path table (Fedora vs Arch vs Debian/Ubuntu), per-VM NVRAM copies pattern, secure-boot variants, and the "empty strings = skip loader/nvram" contract for firmware: bios. Source: charly/ovmf_paths.go. MUST be invoked before editing UEFI firmware resolution.
npx skillsauth add overthinkos/overthink-plugins ovmfInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Per-distro UEFI firmware path resolution for VMs. ResolveOvmfPaths picks the correct OVMF_CODE + OVMF_VARS pair for the host distro + secure-boot setting; EnsurePerVmNvram copies the shared OVMF_VARS template to a per-VM writable NVRAM file on first use. ResolveOvmfForSpec is the convenience wrapper that reads spec.Firmware and dispatches.
Key contract: when spec.Firmware == "bios" or empty, ResolveOvmfForSpec returns ("", "", nil) — no OVMF package dependency, no per-VM NVRAM file, no <loader>/<nvram> emission. The libvirt renderer uses these empty strings as a sentinel to skip UEFI entirely.
charly/ovmf_paths.go — ~185 LOC; standalone, no other dependencies inside charly/.
Fedora / CentOS / RHEL / Rocky / Alma:
insecure: /usr/share/OVMF/OVMF_CODE.fd + /usr/share/OVMF/OVMF_VARS.fd
secure: /usr/share/OVMF/OVMF_CODE.secboot.fd + /usr/share/OVMF/OVMF_VARS.secboot.fd
(fallback): /usr/share/edk2/ovmf/... — pre-F40
Arch / Manjaro / EndeavourOS:
insecure: /usr/share/edk2/x64/OVMF_CODE.4m.fd + /usr/share/edk2/x64/OVMF_VARS.4m.fd
secure: /usr/share/edk2/x64/OVMF_CODE.secboot.4m.fd + (same VARS template)
(fallback): /usr/share/edk2-ovmf/x64/... — pre-edk2-ovmf-202411 repackage
Debian / Ubuntu:
insecure: /usr/share/OVMF/OVMF_CODE_4M.fd + /usr/share/OVMF/OVMF_VARS_4M.fd
secure: /usr/share/OVMF/OVMF_CODE_4M.ms.fd + /usr/share/OVMF/OVMF_VARS_4M.ms.fd
(fallback): /usr/share/OVMF/OVMF_CODE.fd — older non-4M paths
Multiple candidates per distro handle historical path drift. ResolveOvmfPaths returns the first candidate pair where both files exist. Clean error when no candidate matches, with a distro-appropriate install hint:
| Distro family | Install hint |
|---|---|
| Fedora / CentOS / RHEL | sudo dnf install edk2-ovmf |
| Arch | sudo pacman -S edk2-ovmf |
| Debian / Ubuntu | sudo apt-get install ovmf |
EnsurePerVmNvram(templatePath, perVmDir) copies the OVMF_VARS template to <perVmDir>/nvram.fd on first use. Idempotent: if the per-VM file already exists, it's preserved (the guest has accumulated UEFI variables into it — boot entries, secure-boot state, etc., which must survive reboot).
The shared template stays read-only. Every VM that boots with UEFI gets its own NVRAM copy; no two VMs share NVRAM state.
Per-VM NVRAM path convention: ~/.local/share/charly/vm/charly-<vm-name>/nvram.fd.
firmware: uefi-secure hard-wires the VM to Microsoft UEFI CA keys (enrolled in the secure-boot OVMF_VARS template). Unsigned EFI binaries fail to boot; dual-booting unsigned kernels or self-built EFI loaders requires enrolling custom keys through the OVMF console. Not reversible without a fresh per-VM NVRAM.
firmware: uefi-insecure uses the same OVMF binary but boots any EFI payload. Most cloud images ship signed BOOTX64.EFI binaries that work under either mode; test before committing.
From /charly-vm:arch Finding B: UEFI boot with a stale BOOTX64.EFI (embedded grub.cfg older than the image's on-disk /boot/grub/grub.cfg) is a common failure mode for distribution cloud images. BIOS boot sidesteps it entirely — GRUB reads /boot/grub/grub.cfg from the root filesystem, which is always current.
When spec.Firmware == "bios":
func ResolveOvmfForSpec(spec *VmSpec, vmStateDir string) (codePath, nvramPath string, err error) {
if spec.Firmware == "" || spec.Firmware == "bios" {
return "", "", nil // ← the sentinel
}
// ... UEFI path below
}
The libvirt renderer's RenderDomain checks for codePath == "" and skips <loader> + <nvram> emission. QEMU then boots via SeaBIOS (shipped with QEMU itself, no separate package). No OVMF on the host package-manager list. No per-VM NVRAM file. No Secure Boot lock-in.
When to pick BIOS:
When to pick UEFI:
/charly-internals:vm-spec — spec.Firmware field/charly-internals:libvirt-renderer — RenderDomain consumer; <loader>/<nvram> emission conditions/charly-vm:vm — command-family; BIOS vs UEFI decision matrix/charly-vm:arch — live-test RCA showing why firmware: bios is the right default for Arch cloud imagetools
OpenCharly CLI (charly) binary installed into container/VM images for in-container use. Use when working with charly binary deployment inside containers, native D-Bus support, or the full charly toolchain (charly binary + virtualization + gocryptfs + socat).
development
Operator CachyOS workstation profile — a kind:local template + target:local deploy that installs the full dev stack (30 candies) onto a CachyOS host via ShellExecutor. Lives in the overthinkos/cachyos submodule. MUST be invoked before editing or applying the charly-cachyos workstation profile.
tools
Fedora box with the full charly toolchain using shared candies. Rootless-first — runs as uid=1000 with passwordless sudo (no root, no cap_add: ALL). Same candy list as charly-arch. Includes NVIDIA GPU runtime. MUST be invoked before building, deploying, configuring, or troubleshooting the charly-fedora box.
tools
Arch Linux box with the full charly toolchain. Rootless-first — runs as uid=1000 with passwordless sudo (no root, no cap_add: ALL). Composes /charly-coder:charly-mcp so the box is reachable as an MCP gateway on port 18765. NVIDIA GPU runtime composed in. MUST be invoked before building, deploying, configuring, or troubleshooting the charly-arch box.