selkies/skills/selkies-desktop-bootc/SKILL.md
Bootable (bootc) VM image combining the selkies-desktop streaming desktop with Tailscale (mesh VPN) and KeePassXC (password manager). Fedora 43 base. Boots under libvirt/QEMU as a full OS. Canonical worked example of the external-base-bootc + explicit-distro pattern. MUST be invoked before building, deploying, or troubleshooting selkies-desktop-bootc.
npx skillsauth add overthinkos/overthink-plugins selkies-desktop-bootcInstall 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.
Bootable container image: Fedora 43 bootc + Selkies browser-streamed desktop + Tailscale + KeePassXC. Ships as a QCOW2 disk suitable for libvirt/QEMU/bare-metal.
| Property | Value |
|----------|-------|
| Location | overthinkos/bootc submodule (image/bootc) — composed by @github ref |
| Base | quay.io/fedora/fedora-bootc:43 |
| Bootc | true |
| Distro tags | ["fedora:43", fedora] (must be declared — external bases do not inherit) |
| Layers | agent-forwarding, bootc-base, rpmfusion, selkies-desktop, tailscale, keepassxc, dbus, ov |
| Platforms | linux/amd64 |
| Ports (host → container) | 13000 → 3000, 19222 → 9222, 19224 → 9224 |
| VM entity / ssh_port | selkies-desktop-bootc-bootc / host 2250 → VM:22 |
| Status | enabled — canonical worked example + R10 build target for the bootc submodule |
| Registry | ghcr.io/overthinkos |
| Setting | Value | Rationale |
|---------|-------|-----------|
| SSH port | 2250 | Non-default to avoid colliding with ov-selkies-desktop* containers that claim host :2222 |
| Disk size | 40 GiB | Selkies + Chrome + PipeWire + toolchain transitives need a roomy rootfs |
| RAM | 8 G | Chrome + compositor + recorder want headroom |
| CPUs | 4 | Matches 8 G/4 rule of thumb for a streaming desktop VM |
| Rootfs | ext4 | Default (fallback when image.yml omits rootfs:) |
fedora-bootc:43 (external bootc base)/ov-distros:agent-forwarding — SSH/GPG agent socket plumbing/ov-distros:bootc-base — sshd + qemu-guest-agent + /ov-distros:bootc-config/ov-distros:rpmfusion — free + nonfree repos (required for ffmpeg in selkies-desktop)/ov-selkies:selkies-desktop — 19-sublayer metalayer (pipewire, chrome, labwc, waybar-labwc, swaync, selkies, desktop-fonts, wl-tools, a11y-tools, xterm, tmux, asciinema, fastfetch, wl-overlay, wl-record-pixelflux, wl-screenshot-pixelflux, pavucontrol, swaync, sshd)/ov-infrastructure:tailscale — systemd-enabled tailscaled/ov-infrastructure:keepassxc — GUI password manager/ov-infrastructure:dbus-layer — session bus/ov-tools:ov — ov CLI in-imageHost ports are intentionally shifted into 13xxx/19xxx so the VM can run alongside active ov-selkies-desktop containers that already hold 3000/9222/9224/2222.
| Host port | VM port | Service | Protocol |
|-----------|---------|---------|----------|
| 13000 | 3000 | Traefik → selkies-fileserver | HTTPS (self-signed) |
| 19222 | 9222 | cdp-proxy → Chrome DevTools | HTTP |
| 19224 | 9224 | chrome-devtools-mcp | HTTP (MCP Streamable HTTP) |
| 2250 | 22 | system sshd | TCP |
There is no 2222:2222 publish on this image. Non-bootc selkies-desktop publishes 2222 for its supervisord-managed sshd-wrapper; under bootc, sshd runs as a system systemd unit on port 22 (via /ov-coder:sshd's service: entry with use_packaged: sshd.service), so 2222 is dead weight and would collide with vm.ssh_port. See /ov-coder:sshd for the dual-mode story.
# 1. Build the image (from the bootc submodule).
ov -C image/bootc image build selkies-desktop-bootc
# 2. Refresh rootful podman storage (ov vm build uses sudo podman).
podman save ghcr.io/overthinkos/selkies-desktop-bootc:latest -o /tmp/sdb.tar
sudo podman load -i /tmp/sdb.tar
rm -f /tmp/sdb.tar
# 3. Build the bootc disk image (QCOW2, via bootc install to-disk).
# The kind:vm entity is selkies-desktop-bootc-bootc.
ov -C image/bootc vm build selkies-desktop-bootc-bootc --transport containers-storage
# 4. Create + start the VM (injects your ~/.ssh/id_*.pub via SMBIOS credentials).
ov -C image/bootc vm create selkies-desktop-bootc-bootc
# 5. SSH into the running VM.
ssh -p 2250 root@localhost
Prerequisites: rootful podman reachable via passwordless sudo (ov settings set engine.rootful sudo), kernel+modules consistent (ls /lib/modules/$(uname -r) must exist — reboot after kernel updates), and ~/.ssh/*.pub present.
# Inside the VM:
systemctl --failed --no-pager # must be empty
systemctl is-active sshd tailscaled # both active
runuser -l user -c 'supervisorctl status' # all programs RUNNING (chrome STOPPED is intended)
# From the host:
curl -skI https://127.0.0.1:13000/ # HTTP 200, selkies HTML
curl -sS -X POST http://127.0.0.1:19224/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"probe","version":"1"}}}'
# → returns serverInfo.name=chrome_devtools with a real version
77 declarative checks · 0 failing · 0 skipped under ov eval image. Includes binary/package/service checks for every layer plus image-level composition checks (labwc + chrome + tailscale + keepassxc executables, bootc container lint sanity). The sshd layer's NOPASSWD-sudo check uses a runuser -l user wrapper to work under bootc's USER=root default as well as non-bootc's USER=1000 — see /ov-coder:sshd.
distro:base: "quay.io/fedora/fedora-bootc:43" is an external base (URL, not the name of another image in image.yml). Unlike internal bases, it does not inherit distro tags. Without distro: ["fedora:43", fedora], ov image inspect shows "Distro": null, the generator skips every layer's rpm: install (the install_template's Phase-2 branch requires img.DistroDef != nil), and the final image has zero packages installed from layer rpm: sections. See /ov-image:image for the resolution chain. The sibling bootc images (/ov-distros:bazzite, /ov-distros:aurora) all declare distro: for the same reason; all four bootc images live in the overthinkos/bootc submodule (image/bootc).
dnf5-plugins prepend is required for URL reposquay.io/fedora/fedora-bootc:43 strips dnf5-plugins (the package that provides dnf5 config-manager) from the default install. The generator's install_template now prepends dnf install -y dnf5-plugins whenever any layer rpm.repos: entry has a url: (via the anyRepoHasURL template helper in ov/format_template.go). Without it, /ov-selkies:ffmpeg — which adds negativo17's fedora-multimedia repo — fails with Unknown argument "config-manager" for command "dnf5". See /ov-build:generate for the generator change.
vm.ssh_port is honoured end-to-endOlder ov binaries hardcoded the QEMU hostfwd / libvirt portForward SSH mapping to 2222. Current ov plumbs vm.ssh_port (from the OCI Vm label) through createQemu, createLibvirt, and buildDomainXML. If your VM creates with SSH on 2222 even though vm.ssh_port: 2250 is set, the installed ov binary is stale — run task build:ov. See /ov-vm:vm.
labwc-wrapper (inside selkies-desktop) blocks on /tmp/wayland-1 (pixelflux's socket) at startup, but pixelflux is itself started by selkies (another supervisord program). With startsecs=2, supervisord marks labwc RUNNING before the socket appears, then both processes exit-status-1 and restart in lockstep every ~15 s before converging. The dependent services (selkies-fileserver, chrome-devtools-mcp, traefik, cdp-proxy) run stably throughout. Does not affect container-mode selkies-desktop (different entrypoint path). See /ov-selkies:selkies-desktop "Known bootc caveat" for fix options.
qemu-guest-agent is enabled/inactive under QEMU user-netExpected. The agent needs a virtio-serial channel that ov's QEMU backend doesn't expose under user-net. Switch to the libvirt backend (ov settings set vm.backend libvirt) to activate it.
/ov-distros:bootc-configNon-bootc selkies-desktop runs supervisord as container PID 1 via ENTRYPOINT. Under bootc there's no such entrypoint — systemd is PID 1. The /ov-distros:bootc-config layer ships a systemd user unit /etc/systemd/user/supervisord.service that runs /usr/bin/supervisord -c /etc/supervisord.conf -n and is systemctl --global enabled. It needs StandardOutput=file:/tmp/supervisord-stdout.log so the per-program stdout_logfile=/dev/fd/1 entries (inherited from every selkies-desktop sublayer) resolve to an openable file rather than a journal pipe (which would ENXIO). This is the bootc-side wiring for the desktop. See /ov-distros:bootc-config.
The 13000/19222/19224 ports chosen here are specifically to coexist with running ov-selkies-desktop* container instances. If you're running the VM in isolation and prefer the standard ports, edit image.yml:
selkies-desktop-bootc:
ports:
- "3000:3000"
- "9222:9222"
- "9224:9224"
vm:
ssh_port: 2222
Rebuild + redeploy the VM.
/ov-selkies:selkies-desktop — non-bootc container sibling (cachyos base, supervisord as PID 1)/ov-selkies:selkies-desktop-nvidia — GPU-accelerated container sibling (nvidia base)/ov-openclaw:openclaw-desktop — the CachyOS/CPU all-in-one container sibling: full ov toolchain (nested rootless podman + rootless libvirt VMs) + openclaw gateway + ollama. The non-bootc counterpart of this bootc image when you want the desktop to itself build images / launch pods / spawn VMs./ov-distros:bazzite — ublue-based bootc template/ov-distros:aurora — ublue-based bootc template/ov-selkies:selkies-desktop — the metalayer composition (19 sublayers)/ov-infrastructure:tailscale — mesh VPN (this image's standalone tailscaled)/ov-infrastructure:keepassxc — password manager/ov-distros:bootc-base — sshd + guest-agent + bootc-config/ov-distros:bootc-config — bootc boot wiring (tty1 autologin, graphical target, systemd-user supervisord)/ov-distros:rpmfusion — the nonfree-codec layer needed by selkies-desktop/ffmpeg/ov-vm:vm — VM build + lifecycle + engine.rootful modes + the /dev:/dev mount explanation/ov-build:build — container image build (also covers the stale-ov-binary and buildah-cache-mount caveats)/ov-build:generate — Containerfile generation (empty-systemd-services-stage fix, anyRepoHasURL, export BUILD_ARCH gotcha)/ov-image:image — the distro: field semantics + external-base caveat/ov-eval:eval — declarative testing (including the USER-context gotcha for dual-mode images)MUST be invoked when the task involves:
selkies-desktop-bootc image/ov-distros:bootc-config and /ov-infrastructure:supervisord on bootcdevelopment
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.