A CLI tool for AI agents to control and test Qt6 GUI applications on Linux.
Two components work together:
libqt-auto-test.so— shared library injected into the target Qt6 process viaLD_PRELOADor ptrace. Runs a Unix-socket agent inside the process.qt-auto-test— CLI client that connects to the agent socket and issues commands, printing JSON to stdout.
| Dependency | Version | Purpose |
|---|---|---|
| Qt6 (Core, Gui, Widgets, Test) | ≥ 6.0 | Agent library |
| CMake | ≥ 3.16 | Build system |
| GCC or Clang | C++17 | Compiler |
| libX11 | any | Window-title lookup in CLI |
| nlohmann/json | ≥ 3.11 | JSON (fetched automatically if absent) |
Install on Debian/Ubuntu:
sudo apt install qt6-base-dev qt6-base-dev-tools cmake build-essential libx11-dev
# optional — avoids downloading nlohmann/json at configure time:
sudo apt install nlohmann-json3-devcmake -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo
cmake --build build --parallel $(nproc)Build outputs:
| Path | Description |
|---|---|
build/cli/qt-auto-test |
CLI binary |
build/lib/libqt-auto-test.so |
LD_PRELOAD agent library |
build/tests/test_app/test_app |
Minimal Qt6 app for testing |
cmake --install build --prefix /usr/localInstalls to $prefix/bin/qt-auto-test, $prefix/lib/libqt-auto-test.so, and $prefix/share/man/man1/qt-auto-test.1.
qt-auto-test launch -- /path/to/myapp --any-app-flagsSets LD_PRELOAD and execs the app. The -- separator is required.
qt-auto-test inject --pid 4321
# or by process name:
qt-auto-test inject --name myappUses ptrace to call dlopen inside the target. Requires either CAP_SYS_PTRACE or ptrace_scope ≤ 1. x86-64 only.
# All widgets with screen positions (stable IDs for the session)
qt-auto-test widgets --name myapp
# Text content — same IDs as above, joinable on "id"
qt-auto-test text --name myapp# Full primary screen
qt-auto-test screenshot --name myapp --output /tmp/screen.png
# Single widget
qt-auto-test screenshot --name myapp --widget w0004 --output /tmp/btn.png
# Pixel region (screen coordinates)
qt-auto-test screenshot --name myapp --region 100,200,400,300 --output /tmp/crop.pngFull-screen capture may fail on Wayland without a screen-sharing portal. Widget-level capture (--widget) works on both X11 and Wayland.
qt-auto-test send-keys --name myapp --widget w0007 --keys '<Ctrl+A>new text<Return>'Key specs: <Return>, <Tab>, <Escape>, <Backspace>, <Delete>, <Up>, <Down>, <Left>, <Right>, <Home>, <End>, <PageUp>, <PageDown>, <F1>–<F12>, <Ctrl+X>, <Shift+X>, <Alt+X>, <Meta+X> and combinations like <Ctrl+Shift+Z>. Text outside angle brackets is typed literally.
# Click a widget
qt-auto-test click --name myapp --widget w0004
# Click at screen coordinates
qt-auto-test click --name myapp --x 350 --y 210
# Double-click, right-click
qt-auto-test click --name myapp --widget w0004 --double
qt-auto-test click --name myapp --widget w0004 --button right
# Drag (screen coordinates)
qt-auto-test drag --name myapp --from-x 150 --from-y 310 --to-x 400 --to-y 310
# Scroll (positive = up, negative = down)
qt-auto-test scroll --name myapp --widget w0006 --delta -3# Right-click a widget to open its context menu
qt-auto-test click --name myapp --widget w0012 --button right
# Find the QMenu that appeared
qt-auto-test widgets --name myapp | jq '.widgets[] | select(.class=="QMenu")'
# List its items (text, enabled, shortcut, separator, has_submenu)
qt-auto-test actions --name myapp --widget w0045
# Trigger an item by name ("Copy" matches "&Copy" automatically)
qt-auto-test trigger-action --name myapp --widget w0045 --action-text Copy
# Or by zero-based index
qt-auto-test trigger-action --name myapp --widget w0045 --action-index 0trigger-action calls QAction::trigger() directly — no synthetic mouse event, so the menu does not need to stay focused. Works with both QMenu::exec() (modal) and QMenu::popup() (non-modal) menus.
qt-auto-test detach --name myappStops the agent and removes the socket. The target process continues running.
Every subcommand except launch accepts one of:
| Flag | Resolved by |
|---|---|
--pid <n> |
Direct process ID |
--name <n> |
/proc/*/comm scan |
--window <title> |
X11 _NET_WM_NAME + _NET_WM_PID (requires EWMH-compliant WM) |
All commands that contact the agent print a JSON response. status is "ok" or "error". Exit code is 0 on success, 1 on error.
{ "status": "error", "error": "widget not found: w9999" }man -l docs/qt-auto-test.1 # from the source tree
man qt-auto-test # after install- Qt6 only. The agent library is compiled against Qt6; injecting into a Qt5 process fails at load time.
- x86-64 only for
inject. All other subcommands are architecture-independent. - One client at a time. The agent processes connections sequentially.
- Widget IDs are session-scoped. IDs reset after
detach/ re-inject.