| name | dev-test-linux |
| description | This skill should be used when the user asks to "test Linux desktop apps", "automate GTK/Qt applications", "test with ydotool", "test with xdotool", "verify Linux UI interactions", "capture screenshots on Linux", "control D-Bus services", "test Wayland applications", "test X11 applications", or needs Linux desktop E2E testing. Provides comprehensive guidance for Linux automation with ydotool (Wayland), xdotool (X11), grim, and D-Bus. |
| user-invocable | false |
| disable-model-invocation | true |
## Gate Reminder
Before taking screenshots or running E2E tests, you MUST complete all 6 gates from dev-tdd:
GATE 1: BUILD
GATE 2: LAUNCH (with file-based logging)
GATE 3: WAIT
GATE 4: CHECK PROCESS
GATE 5: READ LOGS ← MANDATORY, CANNOT SKIP
GATE 6: VERIFY LOGS
THEN: E2E tests/screenshots
You loaded dev-tdd earlier. Follow the gates now.
Contents
Linux Desktop Automation
## Tool Availability Gate
Verify automation tools are installed before proceeding.
echo $XDG_SESSION_TYPE
which ydotool || echo "MISSING: ydotool"
which wtype || echo "MISSING: wtype"
which grim || echo "MISSING: grim"
which slurp || echo "MISSING: slurp"
which xdotool || echo "MISSING: xdotool"
which xclip || echo "MISSING: xclip"
which scrot || echo "MISSING: scrot"
which dbus-send || echo "MISSING: dbus-send"
If missing (Wayland):
STOP: Cannot proceed with Wayland automation.
Missing tools for Wayland E2E testing.
Install with:
# Arch
sudo pacman -S ydotool wtype grim slurp
# Debian/Ubuntu
sudo apt install ydotool wtype grim slurp
# Nix
nix-env -iA nixpkgs.ydotool nixpkgs.wtype nixpkgs.grim nixpkgs.slurp
Start ydotool daemon:
sudo systemctl enable --now ydotool
# Or for user service:
systemctl --user enable --now ydotool
Reply when installed and I'll continue testing.
This gate is non-negotiable. Missing tools = full stop.
## When to Use Linux Automation
Use Linux automation (ydotool/xdotool) for:
- Linux native application automation
- GTK/Qt application testing
- System-wide keyboard/mouse control
- Window management testing
- D-Bus service interaction
- Accessibility testing (AT-SPI)
Do NOT use Linux automation for:
- Testing web applications (use Chrome MCP or Playwright)
- macOS desktop automation (use dev-test-hammerspoon)
- Cross-platform testing
Related skills:
- Read
${CLAUDE_SKILL_DIR}/../../skills/dev-test-chrome/SKILL.md and follow its instructions.
- Read
${CLAUDE_SKILL_DIR}/../../skills/dev-test-playwright/SKILL.md and follow its instructions.
- Chrome MCP skill - for debugging
- Playwright skill - for CI/CD
Linux Automation Facts
- Many systems still run X11 despite Wayland's rise — support both xdotool (X11) and ydotool (Wayland), and always detect the display server first (snippet below). Assuming Wayland-only drops working setups.
- The ydotool daemon is a one-time setup; web-testing tools cannot drive native Linux desktop apps, and manual testing in their place produces no automated evidence — "it worked" becomes an unverified claim.
- D-Bus gives precise control over desktop state that raw input simulation cannot; skipping it as "too complex" trades precision for flakiness.
Display Server Detection
if [ "$XDG_SESSION_TYPE" = "wayland" ]; then
else
fi
Always detect display server before choosing tools.
Detect Display Server
if [ "$XDG_SESSION_TYPE" = "wayland" ]; then
echo "Using Wayland tools (ydotool, wtype, grim)"
else
echo "Using X11 tools (xdotool, xclip, scrot)"
fi
Wayland: ydotool
Requires ydotoold daemon running.
Keyboard Input
ydotool type "hello world"
ydotool type --delay 50 "slow typing"
ydotool key 28:1 28:0
ydotool key 1:1 1:0
ydotool key 29:1 46:1 46:0 29:0
ydotool key 29:1 47:1 47:0 29:0
ydotool key 56:1 15:1 15:0 56:0
Alternative: wtype (Wayland-native)
wtype "hello world"
wtype -M ctrl -k c
wtype -M ctrl -M shift -k s
wtype -k Return
wtype -k Escape
Available modifiers: shift, ctrl, alt, logo (super)
Mouse Input
ydotool mousemove --absolute 100 200
ydotool mousemove 50 -30
ydotool click 1
ydotool click 3
ydotool click 1 1
ydotool mousemove --absolute 500 300 && ydotool click 1
ydotool mousemove --absolute 100 100
ydotool mousedown 1
ydotool mousemove --absolute 200 200
ydotool mouseup 1
X11: xdotool
Keyboard Input
xdotool type "hello world"
xdotool key Return
xdotool key Escape
xdotool key ctrl+c
xdotool key ctrl+shift+s
xdotool key alt+Tab
xdotool key super+d
xdotool type --delay 50 "slow typing"
xdotool keydown ctrl
xdotool key c
xdotool keyup ctrl
Mouse Input
xdotool mousemove 100 200
xdotool mousemove --relative 50 30
xdotool click 1
xdotool click 2
xdotool click 3
xdotool click --repeat 2 1
xdotool mousemove 500 300 click 1
xdotool mousemove 100 100 mousedown 1 mousemove 200 200 mouseup 1
Window Control (X11)
xdotool getactivewindow
xdotool search --name "Firefox" windowactivate
xdotool search --class "firefox" windowactivate
xdotool getactivewindow getwindowname
xdotool getactivewindow windowmove 100 100
xdotool getactivewindow windowsize 800 600
xdotool getactivewindow windowminimize
xdotool search --name "Firefox" windowactivate --sync
Screenshots
### The Iron Law of Visual Verification
Every E2E test MUST include screenshot evidence.
Capture a screenshot after completing a workflow to prove success.
Wayland: grim + slurp
grim /tmp/screenshot.png
grim -o DP-1 /tmp/screen.png
grim -g "$(slurp)" /tmp/region.png
grim -g "100,200 800x600" /tmp/region.png
hyprctl clients -j | jq '.[] | select(.class=="firefox")'
grim -g "X,Y WxH" /tmp/window.png
grim -g "$(swaymsg -t get_tree | jq -r '.. | select(.focused?) | .rect | "\(.x),\(.y) \(.width)x\(.height)"')" /tmp/window.png
X11: scrot / import
scrot /tmp/screenshot.png
scrot -u /tmp/window.png
scrot -s /tmp/selection.png
scrot -d 3 /tmp/delayed.png
import -window root /tmp/screenshot.png
import -window "$(xdotool getactivewindow)" /tmp/window.png
Image Comparison
compare -metric AE baseline.png current.png diff.png
compare -metric AE -fuzz 5% baseline.png current.png diff.png
D-Bus Control
Preferred for apps that expose D-Bus interfaces.
dbus-send --session --print-reply --dest=org.freedesktop.DBus \
/org/freedesktop/DBus org.freedesktop.DBus.ListNames
dbus-send --print-reply --dest=org.pwmt.zathura.PID-12345 \
/org/pwmt/zathura org.pwmt.zathura.OpenDocument string:"/path/to/file.pdf"
dbus-send --print-reply --dest=org.pwmt.zathura.PID-12345 \
/org/pwmt/zathura org.pwmt.zathura.GotoPage uint32:5
dbus-send --session --dest=org.gnome.Nautilus \
/org/gnome/Nautilus org.freedesktop.Application.Open \
array:string:"file:///home/user" dict:string:string:""
dbus-send --session --print-reply --dest=org.example.App \
/org/example/App org.freedesktop.DBus.Introspectable.Introspect
Accessibility (AT-SPI)
Use AT-SPI for UI element discovery and verification.
import pyatspi
desktop = pyatspi.Registry.getDesktop(0)
for app in desktop:
if "firefox" in app.name.lower():
print(f"Found: {app.name}")
def dump_tree(node, indent=0):
print(" " * indent + f"{node.getRole()}: {node.name}")
for child in node:
dump_tree(child, indent + 1)
dump_tree(app)
def find_button(app, name):
for child in app:
if child.getRole() == pyatspi.ROLE_PUSH_BUTTON:
if name.lower() in child.name.lower():
return child
found = find_button(child, name)
if found:
return found
return None
button = find_button(app, "Submit")
if button:
button.queryAction().doAction(0)
Complete E2E Examples
### E2E Test Structure
Every Linux E2E test MUST:
- Detect - Check display server (Wayland vs X11)
- Launch - Start the application
- Wait - Allow app to fully initialize
- Interact - Perform user actions
- Verify - Check expected state
- Screenshot - Capture visual evidence
- Cleanup - Close app, restore state
Wayland E2E Test
#!/bin/bash
set -e
echo "Starting E2E test..."
firefox &
sleep 3
wtype -M ctrl -k l
sleep 0.2
wtype "https://example.com"
wtype -k Return
sleep 2
grim /tmp/test_before.png
ydotool mousemove --absolute 500 400
ydotool click 1
sleep 0.5
grim /tmp/test_after.png
SIZE_BEFORE=$(stat -c%s /tmp/test_before.png)
SIZE_AFTER=$(stat -c%s /tmp/test_after.png)
if [ "$SIZE_BEFORE" -ne "$SIZE_AFTER" ]; then
echo "PASS: Screenshots differ (interaction worked)"
else
echo "WARN: Screenshots identical"
fi
echo "Test complete"
X11 E2E Test
#!/bin/bash
set -e
echo "Starting X11 E2E test..."
gedit &
sleep 2
xdotool search --name "gedit" windowactivate --sync
xdotool type "Hello, this is an automated test!"
sleep 0.5
xdotool key ctrl+a
xdotool key ctrl+c
CLIPBOARD=$(xclip -selection clipboard -o)
if [[ "$CLIPBOARD" == *"automated test"* ]]; then
echo "PASS: Clipboard contains expected text"
else
echo "FAIL: Clipboard mismatch"
exit 1
fi
scrot -u /tmp/test_result.png
echo "Screenshot saved"
xdotool key ctrl+w
sleep 0.5
xdotool key Tab key Return
echo "Test complete"
Output Requirements
Document every test run in LEARNINGS.md using this template:
## Linux E2E Test: [Description]
**Display Server:** Wayland / X11
**Tool:** ydotool / xdotool
**Script:**
```bash
./test_workflow.sh
Output:
Starting E2E test...
PASS: Screenshots differ (interaction worked)
Test complete
Result: PASS
Screenshot: /tmp/test_result.png
## Integration
This skill integrates with `dev-test` for Linux desktop automation.
Read `${CLAUDE_SKILL_DIR}/../../skills/dev-tdd/SKILL.md` and follow its instructions.