openclaw-desktop
Recipe card from the charly-openclaw plugin (Images — the deployable catalog).
openclaw-desktop
Section titled “openclaw-desktop”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.
Definition
Section titled “Definition”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, CPU
Section titled “Base — CachyOS, CPU”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.
Resolved security posture (OCI label)
Section titled “Resolved security posture (OCI label)”| 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.
The four fused stacks
Section titled “The four fused stacks”| 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 CLI at /usr/local/bin/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.
Quick Start
Section titled “Quick Start”charly box build openclaw-desktopcharly config openclaw-desktopcharly start openclaw-desktop# Desktop: https://localhost:3000 (accept the self-signed cert)# Gateway: http://localhost:18789# Ollama: curl http://localhost:11434/api/tagscharly shell openclaw-desktop -c "ollama pull llama3"Nested rootless podman — how it works here
Section titled “Nested rootless podman — how it works here”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 1000Nested rootless VMs — how it works here
Section titled “Nested rootless VMs — how it works here”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'Two-level nested-virtualization (end-to-end charly vm run-through)
Section titled “Two-level nested-virtualization (end-to-end 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:
- Host (rootless podman, uid 1000) runs
charly-openclaw-desktop. - Inside it,
charly vm build <bootc-image> --transport containers-storageauto-falls back toengine.rootful=machine(no hostsudoin reach), which spawns a podman-machine VM (nested VM #1) via KVM passthrough and runsbootc install to-disk. charly vm create <bootc-image> -i smoke --ssh-key generateboots the produced qcow2 as a QEMU user-net VM (nested VM #2).charly vm ssh <bootc-image> -i smoke -- uname -areturns the guest kernel.charly vm destroy --diskcleans up.
No --privileged, no cap_add, no seccomp relaxations beyond the baked
[unmask=/proc/*]. Only /dev/kvm passthrough.
Cross-storage loading for private bootc images
Section titled “Cross-storage loading for private bootc images”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 hostpodman save -o /tmp/bootc.tar ghcr.io/<registry>/<image>:latestcharly cp openclaw-desktop /tmp/bootc.tar :/tmp/bootc.tar# inside the podpodman load -i /tmp/bootc.tar # nested rootless storepodman --connection charly-root load -i /tmp/bootc.tar # podman-machine rootful storecharly vm build <image> --transport containers-storageDocker Hub rate-limit note
Section titled “Docker Hub rate-limit note”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.
What works from inside the desktop
Section titled “What works from inside the desktop”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.
Volumes
Section titled “Volumes”chrome-data→~/.chrome-debug(Chrome profile, from the chrome candy)selkies-config→~/.config/selkiesmodels→~/.ollama(Ollama model storage)
Verification
Section titled “Verification”charly status openclaw-desktop # all services RUNNINGcurl -k https://localhost:3000 # selkies HTTPS 200curl -s http://localhost:18789 # openclaw gatewaycurl -s http://localhost:11434/api/tags # ollama APIcharly 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).
Key Candies
Section titled “Key Candies”/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 forunmask=/proc/*)/charly-infrastructure:virtualization— supervisord-managed virtqemud/virtnetworkd/charly-distros:agent-forwarding— GPG/SSH/direnv agent sockets
Related Boxes
Section titled “Related Boxes”/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.
When to Use This Skill
Section titled “When to Use This Skill”MUST be invoked when the task involves:
- Building, deploying, or troubleshooting the
openclaw-desktopbox. - Running
charlyverbs (image build, nested pods, rootless VMs) from inside a streaming desktop. - The OpenClaw gateway, AI CLIs, or a CPU Ollama running alongside a Wayland streaming desktop in one box.
- The non-
--privilegedrootless-in-rootless nesting path on a CachyOS desktop.
Related
Section titled “Related”/charly-image:image— image family umbrella (candy:image entries withbase:/from:, build/validate/inspect/list)/charly-check:check— declarative testing + thecheck-openclaw-desktop-podR10 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)