openclaw/skills/openclaw-desktop/SKILL.md
Use when working with the openclaw-desktop box — the all-in-one CachyOS power box that fuses the selkies streaming desktop, the openclaw-full gateway + AI CLIs (claude-code/codex/gemini), a CPU ollama, and the full nested charly toolchain (build boxes / run nested rootless pods / launch rootless libvirt VMs from a terminal inside the browser-accessible desktop).
npx skillsauth add overthinkos/overthink-plugins openclaw-desktopInstall 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.
The all-in-one workstation box: a browser-accessible Wayland streaming
desktop that also runs the OpenClaw gateway + its full tool/skill stack,
a CPU Ollama inference server, and the complete charly toolchain — all as
uid 1000 user with no --privileged and no added capabilities. Open
https://localhost:3000, get a labwc desktop with Chrome, and from a terminal
inside it you can charly box build, run nested rootless pods, launch rootless
libvirt VMs, drive the OpenClaw gateway on :18789, and hit a local Ollama on
:11434.
openclaw-desktop:
base: cachyos.cachyos # Arch-derived, pacman/AUR, x86_64_v3 (via the `cachyos` import namespace)
build: [pac, aur] # required — selkies' chrome (AUR google-chrome) + wl-tools (AUR wlrctl)
candy:
- agent-forwarding
- selkies-desktop # full streaming desktop stack
- openclaw-full # gateway + 27 tools incl. claude-code/codex/gemini
- ollama # CPU ollama (GPU-agnostic layer)
- charly # the full toolchain: charly binary + virtualization + gocryptfs + socat
- container-nesting # nested rootless podman/buildah/skopeo
- golang
- gh
- dbus
- charly
port:
- "3000:3000" # Selkies web UI (Traefik HTTPS)
- "9222:9222" # Chrome DevTools Protocol (cdp-proxy)
- "9224:9224" # chrome-devtools-mcp (Streamable HTTP)
- "2222:2222" # sshd-wrapper
- "18789:18789" # OpenClaw gateway
- "11434:11434" # Ollama API
platform: [linux/amd64]
No uid:/gid:/user:/network: override — inherits 1000/1000/user and the
default charly bridge network. Rootless is the whole design.
base: cachyos.cachyos (/charly-distros:cachyos, reached via the cachyos import
namespace) is the Arch-derived x86_64_v3 base. The
box is CPU-only — there is no nvidia/cuda candy. Ollama auto-detects
the absence of a GPU and runs CPU inference; selkies streams via the CPU x264
encoder. build: [pac, aur] is mandatory (not inherited): selkies' chrome
candy compiles google-chrome from AUR and wl-tools builds wlrctl;
inheriting cachyos's bare [pac] would gate out the AUR builder and silently
drop the browser. The aur → arch-builder builder map comes from the cachyos
base.
| Field | Value |
|---|---|
| cap_add | (empty) |
| security_opt | [unmask=/proc/*] (from /charly-distros:container-nesting) |
| devices | [/dev/fuse, /dev/net/tun] (from /charly-distros:container-nesting) |
| shm_size | 1g (from /charly-selkies:chrome) |
| memory_max | 6g (from /charly-selkies:chrome) |
| privileged | false |
| Network | default charly bridge (NOT host) |
| UID / user | 1000 / user |
No --privileged. No cap_add: ALL. No seccomp=unconfined. No
label=disable. The only security relaxation is unmask=/proc/* — surgical,
documented in /charly-distros:container-nesting with the full kernel-level RCA.
| Stack | Candies | What it gives you |
|---|---|---|
| Streaming desktop | selkies-desktop (chrome, chrome-cdp, labwc, waybar, pipewire, swaync, pavucontrol, wl-tools, selkies, sshd, …) | labwc Wayland desktop streamed over HTTPS:3000; Chrome + CDP:9222 + chrome-devtools-mcp:9224; sshd:2222 |
| OpenClaw + tools | openclaw-full (openclaw gateway + claude-code, codex, gemini + 24 more tools) | AI gateway on :18789; claude / codex / gemini CLIs at ${HOME}/.npm-global/bin/; playwright now drives the desktop's real Chrome (synergy) |
| LLM inference | ollama | CPU Ollama API on :11434; ollama host alias; models volume at ~/.ollama |
| Nested charly toolchain | charly + container-nesting + golang + gh | charly box build, nested rootless podman/buildah/skopeo, rootless libvirt VMs, gocryptfs encrypted volumes, socat relays |
Browser synergy: openclaw-full ships playwright but deliberately omits a
system browser (it's normally headless). Fusing it with selkies-desktop's
chrome + chrome-cdp stack gives playwright a real browser + CDP on :9222 —
a pure enhancement, no conflict.
| Port | Service |
|---|---|
| 3000 | Selkies web UI (Traefik HTTPS, self-signed) |
| 9222 | Chrome DevTools Protocol (via cdp-proxy) |
| 9224 | chrome-devtools-mcp (Streamable HTTP) |
| 2222 | sshd-wrapper (supervisord-managed) |
| 18789 | OpenClaw gateway + Control UI |
| 11434 | Ollama API |
All six are distinct — no collisions. For multi-instance deployments alongside a
running selkies/openclaw instance holding these host ports, remap via
charly config openclaw-desktop -p 3010:3000 -p 9232:9222 -p 9242:9224 -p 2232:2222 -p 18790:18789 -p 11444:11434.
charly box build openclaw-desktop
charly config openclaw-desktop
charly start openclaw-desktop
# Desktop: https://localhost:3000 (accept the self-signed cert)
# Gateway: http://localhost:18789
# Ollama: curl http://localhost:11434/api/tags
charly shell openclaw-desktop -c "ollama pull llama3"
See /charly-distros:container-nesting for the full kernel-level RCA. The short
version: podman's rootless outer container injects linux.maskedPaths; the
kernel's mount_too_revealing() then refuses any fresh /proc mount from the
inner container. unmask=/proc/* tells podman not to emit those masks on the
outer, so the inner /proc mount has nothing to mismatch with. Verified:
charly shell openclaw-desktop -c 'podman run --rm quay.io/libpod/alpine:latest /bin/true'
# zero extra caps, uid 1000
See /charly-infrastructure:virtualization. virtqemud --timeout 0 +
virtnetworkd --timeout 0 run as supervisord programs at uid 1000; libvirt
qemu:///session keys off $XDG_RUNTIME_DIR and needs no CAP_SYS_ADMIN — only
/dev/kvm passthrough.
charly shell openclaw-desktop -c 'virsh -c qemu:///session list --all'
charly vm run-through)The full charly vm build/create/ssh/stop/destroy lifecycle completes inside the
rootless pod, two levels of KVM nesting deep:
charly-openclaw-desktop.charly vm build <bootc-image> --transport containers-storage
auto-falls back to engine.rootful=machine (no host sudo in reach), which
spawns a podman-machine VM (nested VM #1) via KVM passthrough and runs
bootc install to-disk.charly vm create <bootc-image> -i smoke --ssh-key generate boots the produced
qcow2 as a QEMU user-net VM (nested VM #2).charly vm ssh <bootc-image> -i smoke -- uname -a returns the guest kernel.charly vm destroy --disk cleans up.No --privileged, no cap_add, no seccomp relaxations beyond the baked
[unmask=/proc/*]. Only /dev/kvm passthrough.
The podman-machine in step 2 has its own rootful storage, separate from the outer container's nested rootless store. Load a private bootc image via the host:
# on host
podman save -o /tmp/bootc.tar ghcr.io/<registry>/<image>:latest
charly cp openclaw-desktop /tmp/bootc.tar :/tmp/bootc.tar
# inside the pod
podman load -i /tmp/bootc.tar # nested rootless store
podman --connection charly-root load -i /tmp/bootc.tar # podman-machine rootful store
charly vm build <image> --transport containers-storage
For nested test harnesses, prefer quay.io/libpod/alpine:latest (unmetered)
over docker.io/library/alpine — the baked nested-podman-run check already
uses this mirror.
Every charly verb family runs as uid 1000 inside the container sandbox:
charly box build/generate/validate/merge/inspect/list/pull,
charly check box/live/wl/libvirt (cdp/vnc/mcp/record/kube/adb/appium/spice/dbus are declarative out-of-process verbs),
charly config/deploy/start/stop/update/remove/shell/cmd/service/status/logs,
charly vm list/create/start/stop/ssh/destroy (rootless libvirt session),
charly doctor/secrets/settings/alias. The charly candy bakes only the binary — for
build-mode verbs that read charly.yml, mount or charly cp the project in.
chrome-data → ~/.chrome-debug (Chrome profile, from the chrome candy)selkies-config → ~/.config/selkiesmodels → ~/.ollama (Ollama model storage)charly status openclaw-desktop # all services RUNNING
curl -k https://localhost:3000 # selkies HTTPS 200
curl -s http://localhost:18789 # openclaw gateway
curl -s http://localhost:11434/api/tags # ollama API
charly shell openclaw-desktop -c 'podman run --rm quay.io/libpod/alpine:latest /bin/true'
A desktop screenshot is captured by a wl: screenshot step, run with
charly check live openclaw-desktop --filter wl.
The baked box-level check: carries the nested-rootless posture checks (subuid
two-ranges, newuidmap cap, policy.json, containers.conf userns=host,
_CONTAINERS_USERNS_CONFIGURED + BUILDAH_ISOLATION env), the deploy-scope
nested-toolchain checks (nested podman run, virsh session list, in-container
charly version/charly doctor), and the three fused services' liveness (gateway,
ollama API, chrome-devtools-mcp port). The R10 bed is
check-openclaw-desktop-pod (charly check run check-openclaw-desktop-pod).
/charly-selkies:selkies-desktop-layer — the streaming desktop metalayer/charly-openclaw:openclaw-full — gateway + 27 tools (claude-code/codex/gemini)/charly-ollama:ollama — CPU/GPU-agnostic Ollama candy (GPU is box-level)/charly-tools:charly — the full toolchain: charly binary + virtualization + gocryptfs + socat/charly-distros:container-nesting — rootless nested podman recipe (RCA for unmask=/proc/*)/charly-infrastructure:virtualization — supervisord-managed virtqemud/virtnetworkd/charly-distros:agent-forwarding — GPG/SSH/direnv agent sockets/charly-openclaw:openclaw-full — the headless gateway + tools WITHOUT the desktop / ollama / charly toolchain./charly-openclaw:openclaw — minimal gateway only./charly-selkies:selkies-labwc — the CPU streaming desktop WITHOUT openclaw / ollama / charly toolchain./charly-selkies:selkies-labwc-nvidia — GPU streaming desktop (base nvidia), no openclaw/ollama/charly toolchain./charly-distros:charly-fedora / /charly-coder:charly-arch — root-mode charly toolchain WITHOUT a streaming desktop.MUST be invoked when the task involves:
openclaw-desktop box.charly verbs (image build, nested pods, rootless VMs) from inside a
streaming desktop.--privileged rootless-in-rootless nesting path on a CachyOS desktop./charly-image:image — image family umbrella (candy: image entries with base:/from:, build/validate/inspect/list)/charly-check:check — declarative testing + the check-openclaw-desktop-pod R10 bed/charly-check:cdp, /charly-check:wl — desktop automation on this box/charly-core:charly-config — deploy setup (tunnel, port remapping, multi-instance, encrypted volumes)tools
Use when authoring or modifying a charly PLUGIN — a candy with a `plugin:` block that contributes Providers (verbs/kinds/deploy-targets/steps/builders/commands), its own CUE schema, builtin (compiled-in) or external (out-of-tree git repo). Covers the unified Provider model, the per-plugin CUE-schema contract (single source → Go params for dev + schema-over-Describe RPC for runtime), the SDK, and the loader.
tools
The CUE data-validation / configuration CLI (cue), pinned to v0.16.1. Use when working with the cue candy, installing the cue binary into a box or onto a target:local dev host, or running the offline schema-vendoring pipeline that feeds charly's egress validation.
tools
CUE EGRESS validation — validating (and, where it adds value, generating) the config files charly WRITES to a system BEFORE the bytes hit disk. MUST be invoked before working on charly/egress.go, the vendored schemas under candy/plugin-egress/egress-schemas/vendor/, the ValidateEgress / registerVendoredEgressKind path, the offline `task cue:vendor` pipeline, or adding an egress schema for any written artifact (cloud-init, k8s manifests, traefik routes, runtime config, install ledger, systemd/quadlet units, ssh_config, libvirt XML).
tools
Kubernetes cluster-probe declarative check verb — the `kube:` check verb (nodes, pods, ingress, storage class, addon health, apply/delete, and arbitrary resource GETs) served out-of-process by the candy/plugin-kube plugin (vendored client-go; no external kubectl required).