selkies
| Version | 2026.184.2020 |
| Repo | superproject |
Browser-accessible desktop streaming over HTTPS via pixelflux Wayland capture and a Traefik reverse proxy selkies installs a Python streaming server (the launch wrapper, the capture-bridge server, and a static web-UI fileserver), a Traefik reverse proxy with a self-signed cert for the WebCodecs secure context, and the pre-built web UI bundle. pixelflux creates the nested wayland-1 compositor and streams H.264 to the browser; Traefik terminates TLS on :3000 and proxies the web UI plus the /websockets backend. Each step below asserts a real installed file or a live HTTPS endpoint, so every scenario fails if the candy installed nothing.
Services
Section titled “Services”traefikselkies-fileserverselkies
Acceptance plan
Section titled “Acceptance plan”This candy’s plan: — the runnable spec charly check executes against a live deployment. check: steps are idempotent probes; run: steps change state.
| Intent | Step |
|---|---|
run |
command=SRCH=“$(getent passwd 1000 | cut -d: -f6)” mkdir -p /usr/local/share/selkies/web cp -r “$SRCH”/.local/share/selkies-build/web/* /usr/local/share/selkies/web/ rm -rf “$SRCH”/.local/share/selkies-build |
run |
download=https://github.com/traefik/traefik/releases/download/${TRAEFIK_VERSION}/traefik_${TRAEFIK_VERSION}_linux_${ARCH}.tar.gz |
run |
mkdir=/usr/local/share/selkies/certs |
run |
command=openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 \ -keyout /usr/local/share/selkies/certs/selkies.key \ -out /usr/local/share/selkies/certs/selkies.crt \ -days 3650 -nodes \ -subj “/CN=selkies” \ -addext “subjectAltName=DNS:localhost,DNS:selkies.localhost,DNS:*.localhost,DNS:charly-selkies-desktop,IP:127.0.0.1” chmod 644 /usr/local/share/selkies/certs/selkies.crt /usr/local/share/selkies/certs/selkies.key |
run |
copy=traefik.yml |
run |
copy=traefik-dynamic.yml |
run |
mkdir=${HOME}/.local/bin |
run |
mkdir=${HOME}/.config/selkies |
run |
mkdir=${HOME}/.local/share/selkies |
run |
copy=selkies-wrapper |
run |
copy=selkies-capture-server |
run |
copy=selkies-fileserver |
check |
the selkies launch wrapper is installed and executable |
check |
the capture-bridge server script is installed |
check |
the static web-UI fileserver script is installed |
check |
the Traefik reverse-proxy binary is installed |
check |
the self-signed TLS certificate for the WebCodecs secure context exists |
check |
the matching private key for the certificate exists |
check |
the pre-built Selkies web UI is staged into the system share directory |
check |
the streaming endpoint serves the web UI over HTTPS on the published port |
agent-check |
a connected browser shows the live desktop rendering, not a black or frozen frame |
check |
command=ldd ${HOME}/.pixi/envs/default/lib/python3./site-packages/pixelflux/pixelflux_wayland.so |
check |
service=selkies |
check |
command=d=“$XDG_RUNTIME_DIR”; [ -n “$d” ] || d=/tmp test -e “$d/wayland-1” |
check |
service=traefik |
check |
addr=127.0.0.1:${HOST_PORT:3000} |
check |
command=node=“$DRINODE” [ -n “$node” ] || node=$(ls -1 /dev/dri/renderD* 2>/dev/null | head -1) [ -n “$node” ] || node=/dev/dri/renderD128 vendor=$(cat /sys/class/drm/$(basename “$node”)/device/vendor 2>/dev/null) if vainfo –display drm –device “$node” 2>/dev/null | grep -q “VAProfileH264.*VAEntrypointEncSlice”; then echo “VAAPI-ENCODE-CAPABLE ($node vendor=$vendor)” elif [ “$vendor” = “0x1002” ] || [ “$vendor” = “0x8086” ]; then echo “FAIL: AMD/Intel GPU ($vendor) at $node but no VAAPI H264 encode — DRINODE misconfig / broken libva (CPU x264 fallback)”; exit 1 else echo “VAAPI-N/A (no VAAPI-encode GPU at $node vendor=${vendor:-none} — NVENC/x264 path)” fi |
check |
command=rm -f /tmp/charly-frame.png pixelflux-screenshot > /tmp/charly-frame.png 2>/dev/null [ -s /tmp/charly-frame.png ] || { echo “no PNG captured yet”; exit 1; } out=$(ffmpeg -hide_banner -i /tmp/charly-frame.png -vf “signalstats,metadata=print” -f null - 2>&1) ymin=$(printf “%s” “$out” | grep -oE “YMIN=[0-9]+” | grep -oE “[0-9]+” | head -1); ymin=${ymin:-0} ymax=$(printf “%s” “$out” | grep -oE “YMAX=[0-9]+” | grep -oE “[0-9]+” | head -1); ymax=${ymax:-0} sp=$((ymax - ymin)) [ “$sp” -gt 24 ] && { echo “FRAME-NOT-BLACK (luma spread=$sp ymin=$ymin ymax=$ymax)”; exit 0; } echo “frame still uniform (spread=$sp ymin=$ymin ymax=$ymax)”; exit 1 |
check |
command=home=“$HOME” [ -n “$home” ] || home=$(getent passwd “$(id -u)” 2>/dev/null | cut -d: -f6) log=“$home/.local/share/selkies/selkies.log” [ -f “$log” ] || { echo “selkies log not present yet”; exit 1; } node=“$DRINODE” [ -n “$node” ] || node=$(ls -1 /dev/dri/renderD* 2>/dev/null | head -1) # Only trust a render node actually present in THIS container: a # GPU-less (CPU) pod can still carry an injected DRINODE for a host # device that was never mapped in — selkies itself then falls to # software too, so treat it as no-GPU (the clean CPU x264 path). [ -n “$node” ] && [ ! -e “$node” ] && node=“” vendor=“” [ -n “$node” ] && vendor=$(cat /sys/class/drm/$(basename “$node”)/device/vendor 2>/dev/null) if grep -qiE “Failed to init NVENC|Falling back to CPU|Using CPU Software Encoding|Mode: H264 (CPU)” “$log”; then cpu_fallback=1 else cpu_fallback=0 fi case “$vendor” in 0x10de) [ “$cpu_fallback” = “1” ] && { echo “FAIL: NVIDIA GPU ($node) but pixelflux fell back to CPU — NVENC not active. log tail:”; grep -iE “NVENC|CUDA|CPU|encoder” “$log” | tail -8; exit 1; } grep -qiE “NVENC” “$log” || { echo “NVENC not initialized yet”; exit 1; } echo “ENCODER-OK: NVENC active on NVIDIA $node”; exit 0 ;; 0x1002|0x8086) [ “$cpu_fallback” = “1” ] && { echo “FAIL: AMD/Intel GPU ($node) but pixelflux fell back to CPU — hardware encode not selected. log tail:”; grep -iE “VAAPI|VA-API|CPU|encoder” “$log” | tail -8; exit 1; } echo “ENCODER-OK: hardware encode selected on $node (VAAPI capability asserted by selkies-vaapi-encode)”; exit 0 ;; *) echo “ENCODER-OK: CPU x264 (no GPU render node — vendor=${vendor:-none})”; exit 0 ;; esac |