A Kotlin library for driving Compose Desktop UIs from automated tests. Reads the semantics
tree, drives mouse and keyboard input — either real OS-level events via java.awt.Robot or
synthetic AWT events dispatched straight into the window hierarchy (RobotDriver.synthetic(...),
useful when tests run in parallel and can't fight over OS focus) — and records the screen,
against IDE-hosted Compose surfaces (IntelliJ, Jewel) and standalone desktop apps alike.
Important
Heads up: this repo is currently a lot of vibe slop. Large parts were written with heavy AI pair-programming and haven't yet had a proper human review pass end-to-end. I'll be going through it manually to read, audit, and tighten things up. Until then, treat design and implementation choices as "looks plausible, not yet hand-audited" and expect follow-up commits to rework bits once I've actually read them.
macOS, Windows, Linux Xorg, and Linux Wayland. The Wayland path goes through a small
out-of-process Rust helper (recording/native/linux/) that owns the xdg-desktop-portal
handshake, the PipeWire FD lifetime, and the gst-launch-1.0 subprocess; the JVM-side
recorder talks to it over stdin/stdout via a tiny JSON protocol. Same out-of-process
architecture as the macOS Swift helper.
Note
Linux support is best-effort. Routine validation runs on one machine: Ubuntu 22.04,
exercising the Xorg session (input + popup + HiDPI + x11grab) and the GNOME / mutter
Wayland session (the portal-based recording path). Other distros, compositors (KDE /
Plasma, sway, wlroots), window managers, and Ubuntu versions aren't covered. Reports
and PRs widening the coverage are very welcome — open an issue with your distro /
compositor / session combo and we'll work through it.
User guide and API documentation: https://spectre.sebastiano.dev.
Start at Getting started for the shape of a Spectre test, or The automator for the mental model.
core— semantics tree, selectors, coordinate mapping, Robot-backed input.server— embedded HTTP transport (Ktor) for cross-JVM access.recording— region capture viaffmpeg, plus window-targeted capture (ScreenCaptureKit on macOS,gdigrabon Windows).AutoRecorderpicks per call. Seedocs/RECORDING-LIMITATIONS.md.testing— JUnit 5 extension and JUnit 4 rule.sample-desktop— Compose Desktop app for manual smokes.sample-intellij-plugin— in-tree IntelliJ plugin hosting a Jewel tool window. Unpublished; serves as the IDE-hosted test bed.
Standalone Compose Desktop app:
./gradlew :sample-desktop:runIntelliJ plugin — then Tools → Run Spectre Against the Sample Tool Window, or pass
-PspectreAutorun=true to fire the action on project open:
./gradlew :sample-intellij-plugin:runIde./gradlew check # tests + Detekt + Compose Rules + ktfmt
./gradlew ktfmtFormat # rewrite Kotlin / .gradle.kts in placeTwo heavier checks live outside :check:
:sample-intellij-plugin:uiTest— boots IntelliJ viaintellij-ide-starter, installs the plugin, firesRunSpectreAction, and asserts every tagged Compose node shows up inidea.log.:recording:checkon macOS — covers the Swift ScreenCaptureKit helper.
JBR 21 is the dev-loop default. JBR 25 also gets exercised via the IDE-hosted test (bundled with IntelliJ 2026.1). Any JDK 21+ works for the non-IDE modules. CI runs on Temurin 21.
ci.yml—:checkon Linux, every PR.macos-check.yml—:checkon macOS, broad path filter.windows.yml—:checkon Windows, broad path filter.macos.yml— Swift helper build +:recording:check, gated onrecording/**.ide-uitest.yml— IDE-hosted UI test on macOS + Windows, gated on plugin / core / recording changes.out/ide-tests/{installers,cache}is cached between runs.validation-windows.yml—:sample-desktop:validationTest*on Windows, gated onsample-desktop/**. JUnit-XML-driven verifier so a Gradle/Compose protocol flake on shutdown can't hide a real failure.validation-linux.yml— same validation matrix on Linux underxvfb-run(real Xorg, no compositor in the loop), gated on the samesample-desktop/**filter shape.
The user guide and these reference pages are also published as a single browseable site at https://spectre.sebastiano.dev.
- Architecture
- Testing
- Conventions
- Static analysis
- Recording limitations
- Spike gist — original design notes.
