selkies/skills/labwc/SKILL.md
Lightweight Wayland compositor (wlroots-based) for nested desktop inside pixelflux. MUST be invoked when working with: the labwc candy, Wayland compositor config in selkies boxes, or labwc-wrapper.
npx skillsauth add overthinkos/overthink-plugins labwcInstall 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.
Lightweight Wayland compositor (wlroots-based) for use as a nested desktop inside pixelflux's Wayland capture compositor.
labwc runs as a nested compositor inside pixelflux's wayland-1 display. It creates its own wayland-0 socket for desktop applications (Chrome, Waybar, foot, thunar). This is the same approach used by the LinuxServer.io Selkies base image.
wayland-1 (pixelflux) via WAYLAND_DISPLAY=wayland-1 in the labwc-wrapperwayland-0 for its clientsWAYLAND_DISPLAY=wayland-0 ensures apps connect to labwc, not pixelfluxdbuslabwc — Wayland compositorfoot — Terminal emulatorxorg-x11-server-Xwayland — X11 compatibilitythunar — File manager| Variable | Value | Purpose |
|----------|-------|---------|
| WAYLAND_DISPLAY | wayland-0 | labwc's client socket (global default for apps) |
| XDG_RUNTIME_DIR | /tmp | Runtime directory |
labwc-wrapper exports all XKB environment variables with defaults, making keyboard layout configurable at deploy time:
| Variable | Default | Purpose |
|----------|---------|---------|
| XKB_DEFAULT_LAYOUT | us | Keyboard layout (us, de, fr, gb, es, no, etc.) |
| XKB_DEFAULT_VARIANT | (empty) | Layout variant (dvorak, nodeadkeys, etc.) |
| XKB_DEFAULT_MODEL | pc105 | Keyboard model (pc105, pc104, chromebook) |
| XKB_DEFAULT_OPTIONS | (empty) | XKB options (compose:ralt, caps:escape) |
| XKB_DEFAULT_RULES | evdev | XKB rules (always evdev, not configurable) |
All except RULES are declared as env_accept — override via charly config -e:
# German QWERTZ layout
charly config selkies-desktop -e XKB_DEFAULT_LAYOUT=de
# French AZERTY with no dead keys
charly config selkies-desktop -e XKB_DEFAULT_LAYOUT=fr -e XKB_DEFAULT_VARIANT=nodeadkeys
The compositor and selkies input handler both read XKB_DEFAULT_LAYOUT from the environment, ensuring the scancode map matches the compositor's layout. See /charly-selkies:selkies for the keyboard input pipeline details.
| Service | Priority | Purpose |
|---------|----------|---------|
| labwc | 12 | Desktop compositor (after selkies at priority 8) |
labwc-wrapper — Waits for pixelflux's wayland-1 socket, exports XKB_DEFAULT_* from env with defaults, then starts labwcrc.xml — labwc configuration: server-side decorations, maximize-all window rule, keyboard shortcuts (Alt+F4 close, Super+E terminal)autostart — Does NOT launch Chrome. Chrome is launched + supervised by the
[program:chrome] service in the selkies-core candy (shared by both selkies
flavors). CDP: internal 9223, external 9222 via cdp-proxy.Chrome is owned by a supervised [program:chrome] service declared in the
selkies-core candy (candy/selkies-core/charly.yml service: block) — NOT by the
labwc candy and NOT by labwc's autostart. Both selkies flavors (labwc via
selkies-desktop, KDE Plasma via selkies-kde-desktop) compose selkies-core and get the
same supervised browser. The per-flavor compositor autostart (labwc's autostart,
KDE's kde-selkies-session) does not start Chrome.
The supervised service uses:
restart: always → autorestart=true. The selkies flavors nest the compositor inside
pixelflux's wayland-1; a Chrome started during the nested compositor's startup-race
self-exits once (clean exit 0, the window-less browser's sole window going away on the
early color-manager re-init). autorestart=true relaunches it post-settle, where it
stays up indefinitely.autostart=true (default) and self-synchronizing: chrome-wrapper itself polls for
the wayland-0 client socket (created by the nested compositor), so no per-flavor
handoff is needed.start_secs: 5 + start_retries: 3: the single startup-race self-exit runs longer than
start_secs, so it resets the retry budget and never trips FATAL.priority: 30, env WAYLAND_DISPLAY=wayland-0.There is no Chrome eventlistener and no PROCESS_STATE_FATAL circuit breaker — relaunch is
handled entirely by restart: always on the supervised service. The chrome candy's cgroup
resource caps (memory_max/memory_high/memory_swap_max/shm_size) still apply. See
/charly-selkies:selkies-desktop-layer and /charly-infrastructure:supervisord for the
supervised-service pattern, and /charly-selkies:chrome for the resource caps.
sway-browser-vnc is unaffected: it launches Chrome via the chrome-sway candy (not selkies-core), is not pixelflux-nested, and does not hit the startup-race.
All windows open maximized (ideal for streaming desktop):
<windowRule identifier="*" serverDecoration="yes">
<action name="Maximize" />
</windowRule>
/charly-selkies:selkies-labwc (via selkies-desktop metalayer)/charly-selkies:selkies-labwc-nvidia (via selkies-desktop metalayer)/charly-selkies:selkies — pixelflux streaming engine (provides wayland-1 that labwc connects to)/charly-selkies:selkies-desktop-layer — desktop metalayer that composes labwc + chrome + waybar + selkies/charly-selkies:waybar-labwc — status bar configured for labwc/charly-selkies:chrome — Chrome browser (supervised by the selkies-core [program:chrome] service)/charly-check:wl — Wayland automation commands (screenshots, input, window management). Supports KWin (KDE Plasma) in addition to wlroots (sway/labwc); on labwc it uses the wlroots backends (wlrctl pointer/toplevel, wlr-randr, wtype, wl-clipboard, pixelflux-screenshot)MUST be invoked when the task involves the labwc candy, Wayland compositor configuration in selkies boxes, the labwc-wrapper script, window rules, or the nested compositor architecture (pixelflux → labwc → apps).
/charly-image:layer — candy authoring reference (charly.yml schema, task verbs, service declarations)/charly-check:check — declarative testing (check: block, charly check box, charly check live)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).