eval/skills/libvirt/SKILL.md
libvirt-RPC test commands — `ov eval libvirt <vm> …` for VM info, framebuffer screenshots, send-key, passwd, QMP, qemu-guest-agent client, snapshots, events.
npx skillsauth add overthinkos/overthink-plugins libvirtInstall 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.
MUST be invoked before any work involving: ov eval libvirt commands,
libvirt RPC-based VM inspection/management, qemu-guest-agent probing,
VM snapshots, domain event watching, or any task that needs
VM-introspection surfaces beyond what ov vm (lifecycle) provides.
Top-level:
ov eval libvirt list # all domains on the session
ov eval libvirt info <vm> # state + graphics + uptime + agent
ov eval libvirt screenshot <vm> [FILE] [--screen N] # libvirt DomainScreenshot → PNG
ov eval libvirt send-key <vm> KEYS… # keyboard injection (Linux keycode set)
ov eval libvirt passwd <vm> [PASSWORD] # live graphics password patch
ov eval libvirt qmp <vm> COMMAND [JSON_ARGS] # QMP passthrough
ov eval libvirt domain-xml <vm> # dump live XML
ov eval libvirt console <vm> # (stub) serial console — use `virsh console`
ov eval libvirt events [<vm>] # poll lifecycle state transitions
Remote libvirt via --uri. Every verb accepts --uri qemu+ssh://[user@]host/session (also honored as OV_LIBVIRT_URI). When
set, ov opens an SSH connection to the remote host, discovers the
remote virtqemud session socket via id -u, and forwards it over the
SSH channel — so DomainScreenshot, DomainSendKey, QMP, etc. all
work against the remote hypervisor. Example:
ov eval libvirt info arch --uri qemu+ssh://o.atrawog.org/session
ov eval libvirt screenshot arch --uri qemu+ssh://o.atrawog.org/session - > /tmp/shot.png
<file> args accept - for stdout. Alternatively, run ov on the
remote machine with the top-level --host flag: ov --host o test libvirt info arch.
guest subgroup — qemu-guest-agent client:
ov eval libvirt guest ping <vm>
ov eval libvirt guest info <vm> # agent capability list
ov eval libvirt guest os-info <vm> # distro/kernel
ov eval libvirt guest time <vm> # guest clock + host delta
ov eval libvirt guest hostname <vm>
ov eval libvirt guest users <vm>
ov eval libvirt guest interfaces <vm> # IPs + MACs + stats
ov eval libvirt guest disks <vm> # block devices
ov eval libvirt guest fsinfo <vm> # mounted filesystems
ov eval libvirt guest vcpus <vm> # guest-side online state
ov eval libvirt guest exec <vm> -- CMD ARGS…
ov eval libvirt guest file read <vm> PATH # cat a guest file
ov eval libvirt guest file write <vm> PATH # read stdin, write to guest
ov eval libvirt guest fsfreeze status|freeze|thaw <vm>
ov eval libvirt guest fstrim <vm>
snapshot subgroup:
ov eval libvirt snapshot list <vm>
ov eval libvirt snapshot create <vm> NAME [--desc] [--disk-only]
ov eval libvirt snapshot info <vm> NAME
ov eval libvirt snapshot revert <vm> NAME
ov eval libvirt snapshot delete <vm> NAME
Every verb maps to one go-libvirt RPC (plus, for guest *, the
QEMUDomainAgentCommand passthrough). The command name mirrors the
libvirt/virsh vocabulary so skills translate cleanly. Design
choices:
ov eval spice: vm.yml entity
name → libvirt domain → live XML via libvirtxml.Domain. Errors
are the same across both commands.DomainScreenshot —
QEMU's VNC framebuffer capture, returned as PPM, decoded in-process
and re-encoded as PNG. Independent of whichever graphics protocol
(SPICE or VNC) the VM exposes on the wire.DomainSendKey. Friendly
keyname map in ov/libvirt_ops.go covers letters/digits/modifiers/
arrows/function keys. Supports chord notation ("ctrl+alt+F2").<graphics type="spice|vnc" passwd="…">
attribute via libvirtxml, then calls
DomainUpdateDeviceFlags(LIVE). --persistent also writes to the
inactive config.guest-exec + polls guest-exec-status until
exit. stdout/stderr are base64-decoded from the agent reply and
written to the CLI's stdout/stderr.# Sanity.
ov eval libvirt list
ov eval libvirt info arch
# Framebuffer capture (independent of SPICE wire state).
ov eval libvirt screenshot arch /tmp/fb.png
# Keyboard injection via libvirt (alternate path to `ov eval spice key`).
ov eval libvirt send-key arch ctrl+alt+F2
# Live graphics password update.
ov eval libvirt passwd arch hunter2
# QMP escape hatch.
ov eval libvirt qmp arch query-status
# qemu-guest-agent (only if the guest has qemu-guest-agent installed).
ov eval libvirt guest ping arch
ov eval libvirt guest exec arch -- uname -a
# Transactional testing: freeze → snapshot → thaw.
ov eval libvirt guest fsfreeze freeze arch
ov eval libvirt snapshot create arch pre-exp
ov eval libvirt guest fsfreeze thaw arch
# … exercise something destructive …
ov eval libvirt snapshot revert arch pre-exp
ov eval libvirt snapshot delete arch pre-exp
guest * subcommands require qemu-guest-agent installed and
running in the guest AND a <channel type='unix' ... name='org.qemu.guest_agent.0'/>
in the domain XML. The overthink layer qemu-guest-agent drops
this in for bootc VMs; cloud-image VMs need to add it to
cloud_init.packages: explicitly.
Use ov eval libvirt info <vm> — if Agent: false, the agent is
not reachable.
portaudioWhen a cloud-image VM uses ov_install.strategy: auto (the modern
default), VmDeployTarget scps the host ov binary into the guest
post-boot. The host binary is built with cgo (the
gordonklaus/portaudio binding for SPICE audio — see
pkg/arch/PKGBUILD depends=()), so the guest needs
libportaudio.so.2 available before the binary runs. Without it,
ov version exits 127 with error while loading shared libraries: libportaudio.so.2: cannot open shared object file.
Minimum cloud-image package list for full eval-live coverage:
cloud_init:
packages:
- sudo
- spice-vdagent # for spice-vdagentd
- qemu-guest-agent # for `ov eval libvirt guest *` probes
- portaudio # for libportaudio.so.2 (host ov binary dep)
Every ov eval libvirt … and ov eval spice … probe routes through
the libvirt user-session daemon socket. The daemon must be running as
a user-service:
systemctl --user enable --now virtqemud.service # libvirt ≥ 8 (modular)
# OR (older monolithic):
systemctl --user enable --now libvirtd.service
ov vm create best-effort starts these units before resolving the
VM backend (see /ov-vm:vm "Prereq"). The ov eval run <bed> path
for VM-targeting beds (e.g. eval-k3s-vm) invokes the same hook. If the
unit doesn't exist (libvirt not installed), the explicit-backend
gate in resolveVmBackend() surfaces a clear error pointing at the
remediation.
ov eval spice)ov eval libvirt — libvirt RPC only. Every byte goes to
libvirtd. Works regardless of the VM's graphics protocol.ov eval spice — SPICE wire only. Proves the SPICE protocol
path is alive end-to-end.For ambiguous tests, run both and diff the results.
ov/libvirt_cmd.go — Kong command tree + all verb implementations.ov/libvirt_ops.go — shared helpers (screenshot PPM→PNG decode,
key-name → Linux keycode map).ov/libvirt_guest_agent.go — typed client over
QEMUDomainAgentCommand with methods for every QGA command in use.ov/vm_target.go — shared target resolution; VmTarget.XML
gives you the live libvirtxml.Domain for fast field lookups.github.com/digitalocean/go-libvirt — pure-Go libvirt RPC client.libvirt.org/go/libvirtxml — typed domain XML parsing/generation.libvirt Arch package (libvirtd, session socket) is already a
hard dep of the overthink-git PKGBUILD.development
Claude Code multi-agent support in Overthink — sub-agents, dynamic workflows, and agent teams, and how each drives the existing `ov eval` disposable beds to test and verify. MUST be invoked before authoring or invoking an ov sub-agent / dynamic workflow / agent team, wiring agent-lifecycle hooks, or asking "which primitive should drive the R10 beds?".
tools
Mounts a virtiofs share tagged `workspace` at /workspace inside a VM guest via a systemd .mount unit. Use when a kind:vm entity shares a host directory into the guest and you need it auto-mounted (and re-mounted at every boot).
development
MUST be invoked before any work involving: the `kind: android` schema kind, a `target: android` deploy, the `apk:` layer package format (installing Android apps declaratively), AndroidDeployTarget, an in-pod emulator OR a remote/physical adb-endpoint device, or nested `pod → android` deployment. The first-class Android device + app surface that sits above `ov eval adb`/`appium`.
tools
Use when committing, branching, pushing, merging, tagging, creating PRs, or approving/merging PRs with gh — the feat/-branch, R10-gated, never-force-push landing workflow across the main repo + the plugins submodule + image/<distro> submodules. Covers sync-to-upstream, branch/worktree pruning, the fork+PR path for contributors without write access, and cross-repo @github landing order.