Skip to content

Installation

Spectre publishes these library modules to Maven Central:

Module Maven coordinate
core dev.sebastiano.spectre:spectre-core:<version>
testing dev.sebastiano.spectre:spectre-testing:<version>
recording dev.sebastiano.spectre:spectre-recording:<version>
recording-macos dev.sebastiano.spectre:spectre-recording-macos:<version>
recording-linux dev.sebastiano.spectre:spectre-recording-linux:<version>
recording-windows dev.sebastiano.spectre:spectre-recording-windows:<version>
server dev.sebastiano.spectre:spectre-server:<version>
agent dev.sebastiano.spectre:spectre-agent:<version>
agent-runtime dev.sebastiano.spectre:spectre-agent-runtime:<version>

Before a release tag is published

The main branch declares 0.1.0-SNAPSHOT. Until a tagged release has been published to Maven Central, consume the checkout as a Gradle composite build (includeBuild) or publish locally with ./gradlew publishToMavenLocal.

Requirements

  • JDK 21 or newer. JBR 21 is the project's dev-loop default; JBR 25 is exercised via the IDE-hosted UI test. Any JDK 21+ works for the non-IDE modules.
  • Windows 10 version 1903 or newer, .NET 8 Desktop Runtime, and Windows App Runtime 1.8 for native window/region recording and still-window screenshots through Windows Graphics Capture. Contributors and CI that build the helper from source need the .NET 8 SDK.
  • A Compose Desktop or Compose Multiplatform (desktop target) application. Spectre reads Compose's semantics tree, so the UI under test must be a real Compose surface.
  • Platform-specific recording dependencies if you plan to use the recording module — see Recording for the per-OS prerequisites.

Consume from Maven Central

Add the modules you need to the consuming project's build.gradle.kts:

dependencies {
    testImplementation("dev.sebastiano.spectre:spectre-core:<version>")
    testImplementation("dev.sebastiano.spectre:spectre-testing:<version>")

    // Optional, depending on what you need:
    testImplementation("dev.sebastiano.spectre:spectre-recording:<version>")
    testRuntimeOnly("dev.sebastiano.spectre:spectre-recording-macos:<version>") // macOS SCK helper
    testRuntimeOnly("dev.sebastiano.spectre:spectre-recording-linux:<version>") // Linux capture helper
    testRuntimeOnly("dev.sebastiano.spectre:spectre-recording-windows:<version>") // Windows WGC helper
    testImplementation("dev.sebastiano.spectre:spectre-server:<version>")
    testImplementation("dev.sebastiano.spectre:spectre-agent:<version>")
    testRuntimeOnly("dev.sebastiano.spectre:spectre-agent-runtime:<version>") // Java-agent runtime
}

spectre-recording contains the public recording API and common JVM implementation. The macOS, Linux, and Windows helper artifacts are runtime-only resources: add the one(s) your tests can run on with testRuntimeOnly(...), or with runtimeOnly(...) for production application code.

If you depend on server, you also need to add a Ktor server engine yourself — Spectre intentionally doesn't bundle one. See Cross-JVM access for the choice.

If you depend on agent, keep the artifact roles separate:

  • Add spectre-agent to the attacher's compile/test classpath. This is the API containing AgentAttach, AttachedAutomator, and AttachOptions.
  • Add spectre-agent-runtime to the attacher's runtime/test-runtime classpath. AgentAttach locates that physical jar and passes it to VirtualMachine.loadAgent(...).
  • Add spectre-core to the target app. The target does not need spectre-agent or spectre-agent-runtime declared as dependencies.

Custom launchers that do not expose the runtime jar on java.class.path can pass an explicit AttachOptions.agentJarPath or set -Ddev.sebastiano.spectre.agent.runtimeJar=<path>. See Agent attach for the full attach flow and custom path examples.

You also need the JUnit version that matches the wrapper you'll use:

dependencies {
    testImplementation("org.junit.jupiter:junit-jupiter:5.10.0")
}
dependencies {
    testImplementation("junit:junit:4.13.2")
}

The testing module declares both JUnit dependencies as compileOnly, so consumers pick whichever they're already using.

Consume the current checkout

Clone Spectre next to the project that wants to use it:

git clone https://github.com/rock3r/spectre.git

In the consuming project's settings.gradle.kts, include Spectre's checkout as a composite build and map the published module coordinates to the included projects:

includeBuild("../spectre") {
    dependencySubstitution {
        substitute(module("dev.sebastiano.spectre:spectre-core"))
            .using(project(":core"))
        substitute(module("dev.sebastiano.spectre:spectre-testing"))
            .using(project(":testing"))
        substitute(module("dev.sebastiano.spectre:spectre-recording"))
            .using(project(":recording"))
        substitute(module("dev.sebastiano.spectre:spectre-recording-macos"))
            .using(project(":recording-macos"))
        substitute(module("dev.sebastiano.spectre:spectre-recording-linux"))
            .using(project(":recording-linux"))
        substitute(module("dev.sebastiano.spectre:spectre-recording-windows"))
            .using(project(":recording-windows"))
        substitute(module("dev.sebastiano.spectre:spectre-server"))
            .using(project(":server"))
        substitute(module("dev.sebastiano.spectre:spectre-agent"))
            .using(project(":agent"))
        substitute(module("dev.sebastiano.spectre:spectre-agent-runtime"))
            .using(project(":agent-runtime"))
    }
}

In the consuming project's build.gradle.kts, use the same coordinates as the Maven Central path — Gradle resolves them against the included build:

dependencies {
    testImplementation("dev.sebastiano.spectre:spectre-core")
    testImplementation("dev.sebastiano.spectre:spectre-testing")

    // Optional, depending on what you need:
    testImplementation("dev.sebastiano.spectre:spectre-recording")
    testRuntimeOnly("dev.sebastiano.spectre:spectre-recording-macos")
    testRuntimeOnly("dev.sebastiano.spectre:spectre-recording-linux")
    testRuntimeOnly("dev.sebastiano.spectre:spectre-recording-windows")
    testImplementation("dev.sebastiano.spectre:spectre-server")
    testImplementation("dev.sebastiano.spectre:spectre-agent")
    testRuntimeOnly("dev.sebastiano.spectre:spectre-agent-runtime")
}

Versions are intentionally omitted: includeBuild substitutes the project dependency into the consumer's classpath using whatever version the included build declares, so the 0.1.0-SNAPSHOT declared by Spectre's root Gradle build is implicit.

For local Maven-style testing without a composite build, publish the current checkout to Maven Local:

./gradlew publishToMavenLocal

Modules at a glance

Module What it gives you
core ComposeAutomator, semantics tree reader, selectors, RobotDriver for input.
testing ComposeAutomatorExtension (JUnit 5), ComposeAutomatorRule (JUnit 4).
recording Region and window-targeted screen capture API (AutoRecorder, native helpers, deprecated ffmpeg escape hatches, …).
recording-macos Runtime-only macOS ScreenCaptureKit helper resources for recording.
recording-linux Runtime-only Linux capture helper resources for recording.
recording-windows Runtime-only Windows Graphics Capture helper resources for recording.
server Embedded HTTP transport (Ktor) and HttpComposeAutomator for cross-JVM access. Experimental; see Security notes.
agent Local attach transport API. Experimental; see Agent attach.
agent-runtime Loadable Java-agent runtime for agent; add as runtime-only beside the API jar.

Most projects only need core + testing. Add recording if you want video output for test runs, add the platform helper artifact(s) for the OSes you run recording tests on, and add server or agent if your test process needs to reach a UI in a different JVM.

Next

Continue to Getting started for a worked example.