auv-wayland-rendering
Prepare, diagnose, and validate Linux GPU and Wayland environments for AUV rendering and capture through XDG Desktop Portal and PipeWire. Use when installing AUV desktop runtime dependencies, connecting from another machine over SSH, using an existing compositor or a headless wlr
Install
npx skills add https://github.com/moeru-ai/auv/tree/main/.agents/skills/auv-wayland-rendering
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install moeru-ai-auv@llmmart
git clone https://github.com/moeru-ai/auv.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole moeru-ai/auv collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
AUV Wayland Rendering
Build a reproducible Linux desktop session in which AUV can observe a Wayland display and persist capture artifacts. Treat environment validation as evidence, not as a change to AUV's public support claim.
Keep ownership explicit: the compositor renders application clients; AUV requests frames through the portal and records them. Do not imply that AUV ships the compositor or a Linux overlay renderer.
Read the relevant references
- Read setup.md before installing packages, creating a compositor session, or configuring remote viewing.
- Read troubleshooting.md when a probe or capture fails, the image is blank, or hardware rendering is uncertain.
- Check AUV's current support matrix before
describing a result as supported. A successful live probe is
live-validatedevidence for the named environment only.
Follow the workflow
1. Inspect before changing the host
Run the read-only probe in the target shell:
.agents/skills/auv-wayland-rendering/scripts/probe-wayland.sh
Add --require-gpu to make missing GPU prerequisites fatal when hardware
rendering is required. The flag does not replace compositor-log evidence.
Record:
- distribution and package manager;
- existing compositor and whether the session is local, nested, or headless;
WAYLAND_DISPLAY,XDG_RUNTIME_DIR, and the session D-Bus;- accessible
/dev/dri/renderD*nodes and the renderer reported by compositor logs oreglinfo/vulkaninfo; - ScreenCast portal and PipeWire readiness.
Do not infer GPU rendering from the presence of a GPU or render node. Require a
renderer log or renderer-tool result. Label pixman, llvmpipe, and similar
paths as software rendering.
2. Choose the session shape
Prefer the existing logged-in Wayland compositor when one is available. It already owns the seat, GPU, D-Bus activation environment, and user consent UI.
Use headless Sway when the host has no desktop session or the test must be
isolated. Start with wlroots renderer auto-selection. Force pixman only as an
explicit software fallback; doing so gives deterministic rendering but does
not validate the GPU path.
Use a nested compositor when isolation is needed inside an existing Wayland desktop and an extra window is acceptable. Do not point AUV at one compositor while its portal backend is attached to another.
3. Install the smallest capability set
Install or verify:
- a Wayland compositor such as Sway;
xdg-desktop-portaland the backend for that compositor;- PipeWire and WirePlumber;
wayland-infoandgrimfor independent diagnostics;- WayVNC only when a human needs to view the wlroots session remotely.
Request authorization before changing system packages, user services, group membership, login linger, or firewall state. Prefer distribution packages. Use a source build or patch only after reproducing a version-specific defect and recording the exact upstream revision and reason.
4. Keep one coherent user session
Run the compositor, portal backend, PipeWire, and AUV as the same unprivileged
user. They must agree on XDG_RUNTIME_DIR, WAYLAND_DISPLAY, and the session
bus. For a compositor started by a user service, import its generated variables
into the systemd user manager and retrieve them in SSH shells.
Use the helper to run a command with either the current environment or the variables published by the user manager:
.agents/skills/auv-wayland-rendering/scripts/with-wayland-session.sh \
auv invoke display.list --json
Do not run the compositor or AUV as root to work around device permissions. Fix seat, logind, container-device, or render-node access instead.
5. Validate from dependencies to AUV artifacts
Validate in this order so each failure has one clear owner:
Confirm the Wayland socket and compositor output with
wayland-infoor the compositor IPC.Confirm PipeWire and the
org.freedesktop.portal.ScreenCastinterface.Run the AUV Linux driver probe:
cargo run -p auv-driver-linux --example validate -- permissions displaysRun repeated product-surface captures:
.agents/skills/auv-wayland-rendering/scripts/verify-auv-capture.sh \ --auv target/debug/auv --repeat 3Open at least one emitted PNG. Verify that it contains the expected client, has the expected dimensions, and is not a blank or stale frame.
Repeated captures establish startup and first-frame reliability. To test freshness, visibly change a client between two capture passes and compare their artifacts; identical static frames do not prove that updates propagate.
The verification script checks AUV's JSON result, artifact purpose, PNG signature, and file existence. It does not prove semantic correctness of the rendered application; visual inspection or an app-specific assertion remains separate.
6. Report the boundary precisely
Report all of the following:
- OS, compositor, portal backend, output name and dimensions;
- renderer and whether it is hardware or software;
- portal frame transport when known (
dma-buf, shared memory, or fallback); - AUV revision and exact validation commands;
- successful run IDs and artifact paths;
- whether remote viewing was enabled and how it was secured;
- known warnings, fallbacks, and missing capabilities.
Do not turn compilation, a portal introspection result, or a single screenshot into a blanket Linux support claim.
Keep GPU compositor rendering, GPU-buffer transport, and correct AUV artifact output as three separate claims. None implies the other two.
Apply safety rules
- Bind WayVNC to loopback and use an SSH tunnel unless authenticated transport was explicitly configured.
- Do not expose an unauthenticated VNC port on
0.0.0.0. - Do not overwrite an existing desktop's portal selection without checking its current backend and other consumers.
- Do not persist services or enable login linger unless the user requested a durable session.
- Keep capture and input evidence separate. A rendered frame does not prove that input was delivered or that an application completed an operation.
Files (auv)
-
agents
-
openai.yaml 256 B
interface: display_name: "AUV Wayland Rendering" short_description: "Run and validate AUV capture on GPU Wayland hosts" default_prompt: "Use $auv-wayland-rendering to prepare and validate AUV rendering and capture in this Linux Wayland environment."
-
-
references
-
setup.md 5.4 KB
# Setup recipes Use this reference to select dependencies and session topology. Prefer the host's existing Wayland desktop. Use a headless compositor only when no desktop exists or isolation is required. ## Capability map | Capability | Typical component | Required for AUV capture | | --- | --- | --- | | Wayland compositor | Sway or the host desktop | Yes | | Portal frontend | `xdg-desktop-portal` | Yes | | wlroots portal backend | `xdg-desktop-portal-wlr` | For Sway/wlroots | | Frame transport | PipeWire | Yes for ScreenCast | | Session policy | WirePlumber | Normally yes | | Output inspection | `wayland-info`, compositor IPC | Diagnostic | | Independent screenshot | `grim` | Diagnostic on wlroots | | Remote human view | WayVNC | Optional on wlroots | | Test client | Foot or another Wayland app | Recommended | Do not install every portal backend. Match the backend to the compositor and inspect the current portal selection before changing it. ## Distribution examples Package names change. Confirm them with the distribution package index before installing. Debian or Ubuntu family: ```bash sudo apt install \ sway xdg-desktop-portal xdg-desktop-portal-wlr \ pipewire wireplumber wayland-utils grim foot sudo apt install wayvnc # optional ``` Arch Linux family: ```bash sudo pacman -S \ sway xdg-desktop-portal xdg-desktop-portal-wlr \ pipewire wireplumber wayland-utils grim foot sudo pacman -S wayvnc # optional ``` For AUV build dependencies, prefer the repository's `nix develop` shell. If using native packages, derive the current library set from `flake.nix` and CI rather than copying an old list. ## Existing desktop session Run AUV inside the session that already owns the Wayland socket and D-Bus. Over SSH, recover the compositor variables only if the desktop imported them into the systemd user manager: ```bash .agents/skills/auv-wayland-rendering/scripts/with-wayland-session.sh \ target/debug/auv invoke display.capture ``` If the helper cannot find a live socket, publish the variables from a process started by the compositor. For Sway, a configuration command can do this: ```text exec systemctl --user import-environment WAYLAND_DISPLAY SWAYSOCK XDG_CURRENT_DESKTOP ``` Restart the selected portal services after publishing a changed compositor environment. Avoid doing this when another live desktop session depends on the same user services. ## Headless Sway session Use a user service or another supervisor so the compositor and its children share a lifetime. Start with: ```text XDG_CURRENT_DESKTOP=sway XDG_SESSION_TYPE=wayland WLR_BACKENDS=headless WLR_HEADLESS_OUTPUTS=1 WLR_LIBINPUT_NO_DEVICES=1 ``` Do not set `WLR_RENDERER` for the first attempt. Inspect Sway's debug or journal logs to learn what wlroots selected. To require the GLES2 path, set `WLR_RENDERER=gles2` and do not set `WLR_RENDERER_ALLOW_SOFTWARE=1`. Treat a failure as missing GPU/driver/device support, not as permission to silently relabel software rendering as GPU. For a deterministic software fallback, use: ```text WLR_RENDERER=pixman ``` The fallback is useful for capture correctness tests but is not GPU evidence. A minimal Sway configuration can define the output and publish the generated session variables: ```text output HEADLESS-1 mode 1280x720 output * bg #1f2430 solid_color exec sh -lc 'systemctl --user import-environment WAYLAND_DISPLAY SWAYSOCK XDG_CURRENT_DESKTOP XDG_SESSION_TYPE && systemctl --user restart xdg-desktop-portal-wlr.service xdg-desktop-portal.service' exec foot --title AUV-Wayland-Validation ``` Confirm the real output name with Sway IPC before putting it in portal configuration. For unattended wlroots capture, use an xdpw configuration such as: ```ini [screencast] output_name=HEADLESS-1 max_fps=30 chooser_type=none ``` `chooser_type=none` bypasses interactive consent for the selected output. Use it only in an isolated session whose owner requested unattended capture. ## GPU access Check all layers instead of stopping at PCI discovery: 1. The host driver binds the device and exposes `/dev/dri/renderD*`. 2. The session user can open the chosen render node. 3. A container, if used, receives the render node and matching user/group IDs. 4. EGL or Vulkan reports the intended device and driver. 5. The compositor log reports the hardware renderer rather than `pixman`, `llvmpipe`, or another software implementation. 6. Portal capture succeeds without an implicit software-only claim. For NVIDIA, AMD, Intel, virtual GPUs, and containers, follow the compositor and driver documentation for that exact stack. Do not encode vendor workarounds as universal defaults. ## Remote viewing Remote viewing is optional and separate from AUV capture. For wlroots, keep WayVNC on loopback: ```bash wayvnc 127.0.0.1 5900 ``` Forward it from the client: ```bash ssh -N -L 5900:127.0.0.1:5900 user@host ``` Then connect a VNC viewer to `127.0.0.1:5900`. If loopback plus SSH tunneling is unsuitable, configure WayVNC authentication and TLS before changing the listen address. ## Primary upstream references - [wlroots environment variables](https://gitlab.freedesktop.org/wlroots/wlroots/-/blob/master/docs/env_vars.md) - [xdg-desktop-portal-wlr configuration](https://github.com/emersion/xdg-desktop-portal-wlr/blob/master/xdg-desktop-portal-wlr.5.scd) - [xdg-desktop-portal-wlr portal selection](https://github.com/emersion/xdg-desktop-portal-wlr) - [WayVNC remote-access guidance](https://github.com/any1/wayvnc/blob/master/README.md) -
troubleshooting.md 5 KB
# Troubleshooting Diagnose one boundary at a time. Preserve the failing command, exit status, relevant environment, and service logs before changing configuration. ## Failure map | Symptom | Likely boundary | Check first | | --- | --- | --- | | `WAYLAND_DISPLAY` unset over SSH | Session environment | `systemctl --user show-environment` and the live socket | | Wayland socket exists but clients fail | User/runtime mismatch | socket owner, `XDG_RUNTIME_DIR`, client UID | | Portal name missing on D-Bus | Portal frontend | `xdg-desktop-portal` user service and session bus | | ScreenCast interface missing | Wrong portal backend selection | `*-portals.conf`, compositor name, xdpw service | | Portal can select an output but no frame arrives | screencopy/buffer negotiation | xdpw and compositor versions, DMA-BUF versus SHM logs | | PipeWire remote or node fails | PipeWire session | PipeWire/WirePlumber services and runtime socket | | Capture is black or stale | Renderer or screencopy path | compositor renderer logs and an independent `grim` capture | | Headless compositor starts only with `pixman` | GPU initialization | render-node access, EGL/Vulkan driver, compositor logs | | WayVNC reports no output | Wrong compositor environment | `WAYLAND_DISPLAY`, `WAYVNC_OUTPUT`, compositor IPC | | First capture fails but later captures work | Initial-frame protocol defect | reproduce several times and test a maintained xdpw release | ## Session environment Compare the compositor, portal backend, and AUV processes: ```bash tr '\0' '\n' </proc/COMPOSITOR_PID/environ | \ grep -E '^(XDG_RUNTIME_DIR|WAYLAND_DISPLAY|SWAYSOCK|DBUS_SESSION_BUS_ADDRESS|XDG_CURRENT_DESKTOP)=' ``` Repeat for the portal process. Do not copy environment values blindly: stale Wayland and Sway sockets can remain named after an earlier session. Verify that the current process can use them. ## Portal selection and introspection Check the public portal interface: ```bash busctl --user introspect \ org.freedesktop.portal.Desktop \ /org/freedesktop/portal/desktop \ org.freedesktop.portal.ScreenCast ``` For Sway, confirm that the preferred portal configuration selects `wlr` for ScreenCast. A generic portal frontend being active does not prove that the correct backend owns the implementation. Inspect logs together: ```bash journalctl --user \ -u xdg-desktop-portal.service \ -u xdg-desktop-portal-wlr.service \ -u pipewire.service \ -u wireplumber.service \ --since '10 minutes ago' ``` ## No valid screencopy format If xdpw selects the output but reports that it cannot receive a valid format from wlroots screencopy: 1. Capture the complete xdpw and compositor versions. 2. Check whether the compositor advertises DMA-BUF, SHM, or both. 3. Reproduce with the current maintained distribution package or upstream release. 4. Compare an independent `grim` capture. 5. Use a source patch only when an upstream issue or exact code inspection demonstrates the missing protocol path. Do not distribute a locally copied binary or undocumented patch. Record source URL, revision, checksum, build recipe, patch, and the failing/passing probes. ## GPU versus software rendering Use at least two compatible evidence points when possible: - compositor debug or journal renderer initialization; - `eglinfo -B` or `vulkaninfo --summary`; - render-node file descriptor or device identity; - vendor monitoring tools while a changing scene renders. The following are not sufficient by themselves: - `lspci` or a vendor utility listing the GPU; - `/dev/dri/renderD*` existing; - Sway running with `WLR_BACKENDS=headless`; - a successful PNG capture. If `pixman` was forced, report software rendering even when a GPU is present. ## AUV capture diagnosis Run the driver probe before the product command: ```bash cargo run -p auv-driver-linux --example validate -- permissions displays capture-screen ``` Then run: ```bash target/debug/auv invoke display.capture --json ``` Interpret the layers separately: - Build success proves compilation only. - `permissions` proves AUV can inspect the session and portal interfaces. - `displays` proves output discovery and geometry. - `capture-screen` exercises the Linux driver directly. - `display.capture` proves the product invoke path and durable artifact projection. - Opening the PNG proves that the expected visual content arrived. When fallback occurs, preserve AUV's `fallback_reason`. A successful fallback must not be reported as success for the primary backend. ## Containers Treat a container as another session boundary. Confirm: - the matching Wayland socket is mounted; - `XDG_RUNTIME_DIR` inside the container resolves that mount; - the session D-Bus and PipeWire sockets are reachable; - the render device is passed through with usable ownership; - host and container graphics libraries are compatible. Prefer a compositor and portal entirely inside the container or entirely on the host. Splitting ownership across both requires deliberate socket and D-Bus plumbing and should be documented as a distinct topology.
-
-
scripts
-
probe-wayland.sh 6.1 KB
#!/usr/bin/env bash set -uo pipefail require_gpu=false case "${1:-}" in "") ;; --require-gpu) require_gpu=true ;; -h|--help) printf 'usage: %s [--require-gpu]\n' "$0" exit 0 ;; *) printf 'unknown argument: %s\n' "$1" >&2 exit 2 ;; esac failures=0 pass() { printf '[ok] %s\n' "$1" } warn() { printf '[warn] %s\n' "$1" } fail() { printf '[fail] %s\n' "$1" failures=$((failures + 1)) } value() { local name=$1 local current=${!name-} if [[ -n "$current" ]]; then printf '[info] %s=%s\n' "$name" "$current" else printf '[info] %s is unset\n' "$name" fi } printf 'AUV Wayland environment probe\n' printf '[info] kernel=%s\n' "$(uname -srm 2>/dev/null || printf unknown)" if [[ $(uname -s 2>/dev/null) == Linux ]]; then pass 'Linux host detected' else fail 'this workflow requires Linux' fi for name in XDG_SESSION_TYPE XDG_CURRENT_DESKTOP XDG_RUNTIME_DIR WAYLAND_DISPLAY SWAYSOCK DBUS_SESSION_BUS_ADDRESS; do value "$name" done runtime_dir=${XDG_RUNTIME_DIR:-/run/user/$(id -u)} if [[ -d "$runtime_dir" ]]; then pass "runtime directory exists: $runtime_dir" else fail "runtime directory is missing: $runtime_dir" fi if [[ -n ${WAYLAND_DISPLAY:-} ]]; then if [[ ${WAYLAND_DISPLAY} = /* ]]; then wayland_socket=$WAYLAND_DISPLAY else wayland_socket=$runtime_dir/$WAYLAND_DISPLAY fi if [[ -S "$wayland_socket" ]]; then pass "Wayland socket is reachable: $wayland_socket" else fail "Wayland socket is missing: $wayland_socket" fi else fail 'WAYLAND_DISPLAY is unset' fi if [[ -S "$runtime_dir/bus" ]]; then pass "session D-Bus socket exists: $runtime_dir/bus" else fail "session D-Bus socket is missing: $runtime_dir/bus" fi if command -v busctl >/dev/null 2>&1; then if busctl --user --no-pager introspect \ org.freedesktop.portal.Desktop \ /org/freedesktop/portal/desktop \ org.freedesktop.portal.ScreenCast >/dev/null 2>&1; then pass 'ScreenCast portal interface is available' else fail 'ScreenCast portal interface is unavailable on the session bus' fi else warn 'busctl is unavailable; portal introspection was skipped' fi if command -v pw-cli >/dev/null 2>&1; then if pw-cli info 0 >/dev/null 2>&1; then pass 'PipeWire core is reachable' else fail 'pw-cli cannot reach the PipeWire core' fi else warn 'pw-cli is unavailable; PipeWire probing was skipped' fi render_nodes=() while IFS= read -r node; do render_nodes+=("$node") done < <(compgen -G '/dev/dri/renderD*' || true) if (( ${#render_nodes[@]} == 0 )); then if $require_gpu; then fail 'no DRM render node was found' else warn 'no DRM render node was found; only software rendering may be available' fi else for node in "${render_nodes[@]}"; do if [[ -r "$node" && -w "$node" ]]; then pass "DRM render node is accessible: $node" elif $require_gpu; then fail "DRM render node is not readable and writable: $node" else warn "DRM render node is not readable and writable: $node" fi done fi renderer_evidence=false renderer_summary= if command -v eglinfo >/dev/null 2>&1; then renderer_output=$(eglinfo -B 2>/dev/null || true) renderer_summary=$(printf '%s\n' "$renderer_output" | sed -n '/EGL vendor string/p;/OpenGL.*renderer:/p;/Device platform:/p;/Device:/p') if [[ -n "$renderer_summary" ]]; then printf '[info] eglinfo renderer summary:\n' printf '%s\n' "$renderer_summary" | sed 's/^/ /' renderer_evidence=true else warn 'eglinfo is installed but did not report a renderer' fi fi if ! $renderer_evidence && command -v vulkaninfo >/dev/null 2>&1; then renderer_output=$(vulkaninfo --summary 2>/dev/null || true) renderer_summary=$(printf '%s\n' "$renderer_output" | sed -n '/deviceName/p;/driverName/p;/driverInfo/p') if [[ -n "$renderer_summary" ]]; then printf '[info] vulkaninfo summary:\n' printf '%s\n' "$renderer_summary" | sed 's/^/ /' renderer_evidence=true else warn 'vulkaninfo is installed but did not report a renderer' fi elif ! command -v eglinfo >/dev/null 2>&1 && ! command -v vulkaninfo >/dev/null 2>&1; then warn 'neither eglinfo nor vulkaninfo is installed; inspect compositor logs for renderer evidence' fi if $require_gpu && ! $renderer_evidence; then fail 'GPU prerequisites were required but no renderer tool produced evidence' elif $require_gpu && ! printf '%s\n' "$renderer_summary" | grep -Ei 'renderer|deviceName' | grep -Eivq 'llvmpipe|softpipe|swrast|pixman'; then fail 'GPU prerequisites were required but renderer tools reported only software candidates' elif $renderer_evidence && printf '%s\n' "$renderer_summary" | grep -Eiq 'llvmpipe|softpipe|swrast|pixman'; then warn 'renderer output includes a software implementation; correlate the relevant platform with compositor logs' fi if command -v swaymsg >/dev/null 2>&1 && [[ -n ${SWAYSOCK:-} ]]; then if swaymsg -t get_outputs -r >/dev/null 2>&1; then pass 'Sway IPC reports at least an output response' else fail 'Sway IPC is configured but get_outputs failed' fi elif command -v wayland-info >/dev/null 2>&1 && [[ -n ${WAYLAND_DISPLAY:-} ]]; then if wayland-info >/dev/null 2>&1; then pass 'wayland-info connected to the compositor' else fail 'wayland-info could not connect to the compositor' fi else warn 'no compositor connection probe was available' fi if command -v systemctl >/dev/null 2>&1; then for service_name in xdg-desktop-portal.service xdg-desktop-portal-wlr.service pipewire.service wireplumber.service; do service_state=$(systemctl --user is-active "$service_name" 2>/dev/null || true) printf '[info] %-35s %s\n' "$service_name" "${service_state:-unknown}" done fi for command_name in sway swaymsg wayland-info grim wayvnc auv; do if command -v "$command_name" >/dev/null 2>&1; then printf '[info] %-27s %s\n' "$command_name" "$(command -v "$command_name")" else printf '[info] %-27s not found\n' "$command_name" fi done if (( failures > 0 )); then printf '[fail] probe completed with %d required check(s) failing\n' "$failures" exit 1 fi pass 'probe completed without required-check failures' -
verify-auv-capture.sh 2.9 KB
#!/usr/bin/env bash set -euo pipefail auv_bin=auv repeat=3 store_root=${AUV_STORE_ROOT:-$PWD/.auv/wayland-validation} while (( $# > 0 )); do case "$1" in --auv) auv_bin=${2:?--auv requires a path} shift 2 ;; --repeat) repeat=${2:?--repeat requires a count} shift 2 ;; --store-root) store_root=${2:?--store-root requires a path} shift 2 ;; -h|--help) printf 'usage: %s [--auv PATH] [--repeat N] [--store-root PATH]\n' "$0" exit 0 ;; *) printf 'unknown argument: %s\n' "$1" >&2 exit 2 ;; esac done if [[ ! "$repeat" =~ ^[1-9][0-9]*$ ]]; then printf -- '--repeat must be a positive integer\n' >&2 exit 2 fi if [[ "$auv_bin" == */* ]]; then [[ -x "$auv_bin" ]] || { printf 'AUV executable is not executable: %s\n' "$auv_bin" >&2 exit 1 } elif ! command -v "$auv_bin" >/dev/null 2>&1; then printf 'AUV executable was not found: %s\n' "$auv_bin" >&2 exit 1 fi command -v python3 >/dev/null 2>&1 || { printf 'python3 is required to validate AUV JSON output\n' >&2 exit 1 } mkdir -p "$store_root" work_dir=$(mktemp -d "${TMPDIR:-/tmp}/auv-wayland-capture.XXXXXX") trap 'find "$work_dir" -type f -delete 2>/dev/null || true; rmdir "$work_dir" 2>/dev/null || true' EXIT for ((attempt = 1; attempt <= repeat; attempt++)); do result_file=$work_dir/result-$attempt.json "$auv_bin" invoke display.capture --store-root "$store_root" --json >"$result_file" python3 - "$result_file" "$attempt" <<'PY' import json import pathlib import sys result_path = pathlib.Path(sys.argv[1]) attempt = sys.argv[2] result = json.loads(result_path.read_text()) if result.get("status") != "completed": raise SystemExit(f"capture {attempt} did not complete: {result}") if result.get("command_id") != "display.capture": raise SystemExit(f"capture {attempt} returned unexpected command_id: {result.get('command_id')}") artifacts = [ artifact for artifact in result.get("artifacts", []) if artifact.get("purpose") == "auv.driver.display_capture" ] if len(artifacts) != 1: raise SystemExit(f"capture {attempt} returned {len(artifacts)} display artifacts") artifact = artifacts[0] if artifact.get("content_type") != "image/png": raise SystemExit(f"capture {attempt} returned unexpected content type: {artifact.get('content_type')}") file_path = artifact.get("file_path") if not file_path: raise SystemExit(f"capture {attempt} did not expose a file_path") png = pathlib.Path(file_path) if not png.is_file(): raise SystemExit(f"capture {attempt} artifact does not exist: {png}") with png.open("rb") as stream: signature = stream.read(8) if signature != b"\x89PNG\r\n\x1a\n": raise SystemExit(f"capture {attempt} artifact is not a PNG: {png}") print(f"capture {attempt}: run={result.get('run_id')} artifact={png}") PY done printf 'validated %d AUV display capture(s); store=%s\n' "$repeat" "$store_root" -
with-wayland-session.sh 1.1 KB
#!/usr/bin/env bash set -euo pipefail if (( $# == 0 )); then printf 'usage: %s <command> [args...]\n' "$0" >&2 exit 2 fi runtime_dir=${XDG_RUNTIME_DIR:-/run/user/$(id -u)} export XDG_RUNTIME_DIR=$runtime_dir wayland_socket_is_live() { local display=${WAYLAND_DISPLAY:-} [[ -n "$display" ]] || return 1 if [[ "$display" = /* ]]; then [[ -S "$display" ]] else [[ -S "$XDG_RUNTIME_DIR/$display" ]] fi } manager_value() { local key=$1 systemctl --user show-environment 2>/dev/null | sed -n "s/^${key}=//p" | tail -n 1 } if ! wayland_socket_is_live && command -v systemctl >/dev/null 2>&1; then for key in WAYLAND_DISPLAY SWAYSOCK XDG_CURRENT_DESKTOP XDG_SESSION_TYPE; do current=$(manager_value "$key") if [[ -n "$current" ]]; then printf -v "$key" '%s' "$current" export "$key" fi done fi if ! wayland_socket_is_live; then printf 'no live Wayland socket was found in the shell or systemd user environment\n' >&2 exit 1 fi if [[ -z ${DBUS_SESSION_BUS_ADDRESS:-} && -S "$XDG_RUNTIME_DIR/bus" ]]; then export DBUS_SESSION_BUS_ADDRESS="unix:path=$XDG_RUNTIME_DIR/bus" fi exec "$@"
-
-
SKILL.md 6.7 KB
--- name: auv-wayland-rendering description: Prepare, diagnose, and validate Linux GPU and Wayland environments for AUV rendering and capture through XDG Desktop Portal and PipeWire. Use when installing AUV desktop runtime dependencies, connecting from another machine over SSH, using an existing compositor or a headless wlroots/Sway session, checking hardware versus software rendering, running display.capture or Linux driver probes, exposing optional WayVNC safely, or troubleshooting blank frames and Wayland, portal, D-Bus, PipeWire, or session-environment failures. --- # AUV Wayland Rendering Build a reproducible Linux desktop session in which AUV can observe a Wayland display and persist capture artifacts. Treat environment validation as evidence, not as a change to AUV's public support claim. Keep ownership explicit: the compositor renders application clients; AUV requests frames through the portal and records them. Do not imply that AUV ships the compositor or a Linux overlay renderer. ## Read the relevant references - Read [setup.md](references/setup.md) before installing packages, creating a compositor session, or configuring remote viewing. - Read [troubleshooting.md](references/troubleshooting.md) when a probe or capture fails, the image is blank, or hardware rendering is uncertain. - Check AUV's current [support matrix](../../../docs/SUPPORT_MATRIX.md) before describing a result as supported. A successful live probe is `live-validated` evidence for the named environment only. ## Follow the workflow ### 1. Inspect before changing the host Run the read-only probe in the target shell: ```bash .agents/skills/auv-wayland-rendering/scripts/probe-wayland.sh ``` Add `--require-gpu` to make missing GPU prerequisites fatal when hardware rendering is required. The flag does not replace compositor-log evidence. Record: - distribution and package manager; - existing compositor and whether the session is local, nested, or headless; - `WAYLAND_DISPLAY`, `XDG_RUNTIME_DIR`, and the session D-Bus; - accessible `/dev/dri/renderD*` nodes and the renderer reported by compositor logs or `eglinfo`/`vulkaninfo`; - ScreenCast portal and PipeWire readiness. Do not infer GPU rendering from the presence of a GPU or render node. Require a renderer log or renderer-tool result. Label `pixman`, `llvmpipe`, and similar paths as software rendering. ### 2. Choose the session shape Prefer the existing logged-in Wayland compositor when one is available. It already owns the seat, GPU, D-Bus activation environment, and user consent UI. Use headless Sway when the host has no desktop session or the test must be isolated. Start with wlroots renderer auto-selection. Force `pixman` only as an explicit software fallback; doing so gives deterministic rendering but does not validate the GPU path. Use a nested compositor when isolation is needed inside an existing Wayland desktop and an extra window is acceptable. Do not point AUV at one compositor while its portal backend is attached to another. ### 3. Install the smallest capability set Install or verify: - a Wayland compositor such as Sway; - `xdg-desktop-portal` and the backend for that compositor; - PipeWire and WirePlumber; - `wayland-info` and `grim` for independent diagnostics; - WayVNC only when a human needs to view the wlroots session remotely. Request authorization before changing system packages, user services, group membership, login linger, or firewall state. Prefer distribution packages. Use a source build or patch only after reproducing a version-specific defect and recording the exact upstream revision and reason. ### 4. Keep one coherent user session Run the compositor, portal backend, PipeWire, and AUV as the same unprivileged user. They must agree on `XDG_RUNTIME_DIR`, `WAYLAND_DISPLAY`, and the session bus. For a compositor started by a user service, import its generated variables into the systemd user manager and retrieve them in SSH shells. Use the helper to run a command with either the current environment or the variables published by the user manager: ```bash .agents/skills/auv-wayland-rendering/scripts/with-wayland-session.sh \ auv invoke display.list --json ``` Do not run the compositor or AUV as root to work around device permissions. Fix seat, logind, container-device, or render-node access instead. ### 5. Validate from dependencies to AUV artifacts Validate in this order so each failure has one clear owner: 1. Confirm the Wayland socket and compositor output with `wayland-info` or the compositor IPC. 2. Confirm PipeWire and the `org.freedesktop.portal.ScreenCast` interface. 3. Run the AUV Linux driver probe: ```bash cargo run -p auv-driver-linux --example validate -- permissions displays ``` 4. Run repeated product-surface captures: ```bash .agents/skills/auv-wayland-rendering/scripts/verify-auv-capture.sh \ --auv target/debug/auv --repeat 3 ``` 5. Open at least one emitted PNG. Verify that it contains the expected client, has the expected dimensions, and is not a blank or stale frame. Repeated captures establish startup and first-frame reliability. To test freshness, visibly change a client between two capture passes and compare their artifacts; identical static frames do not prove that updates propagate. The verification script checks AUV's JSON result, artifact purpose, PNG signature, and file existence. It does not prove semantic correctness of the rendered application; visual inspection or an app-specific assertion remains separate. ### 6. Report the boundary precisely Report all of the following: - OS, compositor, portal backend, output name and dimensions; - renderer and whether it is hardware or software; - portal frame transport when known (`dma-buf`, shared memory, or fallback); - AUV revision and exact validation commands; - successful run IDs and artifact paths; - whether remote viewing was enabled and how it was secured; - known warnings, fallbacks, and missing capabilities. Do not turn compilation, a portal introspection result, or a single screenshot into a blanket Linux support claim. Keep GPU compositor rendering, GPU-buffer transport, and correct AUV artifact output as three separate claims. None implies the other two. ## Apply safety rules - Bind WayVNC to loopback and use an SSH tunnel unless authenticated transport was explicitly configured. - Do not expose an unauthenticated VNC port on `0.0.0.0`. - Do not overwrite an existing desktop's portal selection without checking its current backend and other consumers. - Do not persist services or enable login linger unless the user requested a durable session. - Keep capture and input evidence separate. A rendered frame does not prove that input was delivered or that an application completed an operation.
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.