Stability policy¶
Spectre is pre-1.0. This page documents what changes between releases, what doesn't, and how the project signals the difference at the source / compiler / binary level.
The companion document on the trust model lives at Security notes.
Versioning¶
Spectre follows Semantic Versioning:
- Major (
X.0.0) — breaking changes to the stable public API. - Minor (
0.X.0) — additive changes to the stable public API; experimental APIs may change. - Patch (
0.0.X) — bug fixes; experimental APIs may change.
Pre-1.0 caveats. The project has not yet shipped 1.0. Minor versions may introduce breaking changes to the stable public API until 1.0; that's the whole point of the pre-1.0 window. Each release notes call those out explicitly.
API tiers¶
Spectre distinguishes three tiers of public API. The distinction matters because experimental APIs are still visible: they appear in jar bytecode and in Kotlin Binary Compatibility Validator dumps. The tier controls what guarantees you get, not whether you can call the code.
Stable public API¶
Public declarations not annotated with @InternalSpectreApi or any experimental opt-in
annotation. Covered by binary-compatibility guarantees within a major version: a method
signature won't change, a class won't disappear, a property won't change type. Source-level
breaking changes (parameter renames with default values, etc.) are also treated as breaking
within a major version, even though BCV doesn't catch
every such case.
The committed api/<module>.api baselines in each library module enumerate the stable
public API for that module.
Experimental public API¶
Public declarations annotated with @ExperimentalSpectreHttpApi (or any future per-area
@ExperimentalSpectre*Api markers we add). These are visible to consumers and appear in
the API baselines, but they are explicitly not covered by compatibility guarantees and
may change or be removed in any release, including patch releases.
Three experimental markers exist today:
-
@ExperimentalSpectreApicovers selectedcoreAPIs that are useful now but still settling, such as the recomposition-monitor surface exposed throughComposeAutomator.monitorRecompositions(). -
@ExperimentalSpectreHttpApicovers the entireservermodule's public surface — the HTTP transport (installSpectreRoutes,HttpComposeAutomator, theComposeAutomator.http(...)factory, and the DTOs). Authentication, TLS, narrower per-window capture, and other major reshapes are tracked under #96 and will land under this marker. @ExperimentalSpectreAgentApicovers the entireagentmodule's attach-side public surface —AgentAttach,AttachedAutomator,AttachOptions,SpectreProcesses, and the wire DTOs. Tracked under #153; the marker stays in place while the attach UX, streaming wire ops (waitForVisualIdleetc.), and automated IntelliJ-hosted Compose attach tests settle. The transport itself runs on Linux, macOS, and Windows (nativeAF_UNIX). Nested inject-runtime packaging (attach when the target has no preinstalledspectre-core) is experimental inspect only for 1.0 — keep the marker; do not treat inject as a stable production attach mode.
Consumers opt in either at file level or call site:
@file:OptIn(ExperimentalSpectreHttpApi::class)
import dev.sebastiano.spectre.server.ExperimentalSpectreHttpApi
import dev.sebastiano.spectre.server.installSpectreRoutes
The annotation is WARNING-level, so callers that ignore the opt-in still compile — they just
see a compiler warning per call site. The instability guarantees are the same either way.
Internal escape hatch¶
Public declarations annotated with @InternalSpectreApi. Not part of the supported
surface; ERROR-level opt-in (the compiler refuses without an explicit @OptIn). May change
without notice and without a deprecation cycle.
This marker exists because some in-repo collaborators (the HTTP transport, the recording module's helpers, in-repo fixtures) legitimately need to reach into core's internals. End-user code should not need this annotation — if you find yourself opting in, please file an issue describing the use case so we can shape a stable API for it.
Binary compatibility validation¶
Spectre uses the Kotlin Gradle Plugin's built-in abiValidation extension to track public
ABI per module. Each library module commits a baseline at <module>/api/<module>.api —
a textual snapshot of the JVM-visible public surface: classes, functions, properties, and
fields a consumer can link against from the JVM.
The baseline is a conservative superset of the source-level public API. It also captures
JVM-visible compilation artifacts that aren't always intended as supported source API — most
notably synthetic constructors for classes that use the private-primary-constructor +
companion-factory pattern (the DefaultConstructorMarker form), Companion and enum-constant
static fields, and $serializer classes generated by kotlinx-serialization. A line in the
baseline is a tripwire that flags shape changes; it is not by itself a promise that every line
is a supported source-level entry point.
Workflow:
- On every PR —
./gradlew checkrunscheckKotlinAbiautomatically. A PR that changes the public surface without updating the committed baselines fails CI. - At release — the release workflow re-runs
checkKotlinAbibefore building artefacts, as defensive depth against tag-from-feature-branch shenanigans that would otherwise skip the PR-time check. - Regenerating the baselines — when a public API change is intentional, run
./gradlew updateKotlinAbilocally, review the diff, and commit the updatedapi/*.apifiles alongside the source change.
What's covered¶
- Public JVM ABI of
core,testing,server,recording— class shapes, method signatures, property types, field visibility, inheritance. - Both stable and experimental APIs appear in baselines. The annotation level controls the guarantee, not the visibility.
What's not covered¶
- Annotation usages on individual symbols. The baseline records the shape of declarations,
not the annotations attached to them. Silently removing
@ExperimentalSpectreHttpApifrom a marked declaration would not failcheckKotlinAbi, because removing an annotation doesn't change the JVM symbol shape. The opt-in / experimental-marker layer is enforced at compile time by the Kotlin compiler (via@RequiresOptIn), not by ABI validation. Source review remains the gate for the marker layer; ABI validation is the gate for the symbol layer. - Source-level breakages that don't change JVM ABI (renaming a parameter that has a default value, removing the default from a parameter, etc.).
- Runtime artefacts: the HTTP transport's wire format, recording video output, helper extracted-binary layout, semantics-tree refresh ordering, etc.
- Sample apps (
sample-desktop,sample-intellij-plugin) — not published, no baseline.
Platform support tiers¶
Spectre is JVM-first and targets desktop OSes.
| Platform | Tier | Notes |
|---|---|---|
| macOS | Primary | Full support. AWT Robot input, ScreenCaptureKit recording (with spectre-recording-macos helper), TCC permission diagnostics. |
| Windows | Full | AWT Robot input + Windows Graphics Capture region/window recording + agent attach over native AF_UNIX (Windows 10 1803 / Server 2019+). |
| Linux Xorg | Full | AWT Robot input + helper/GStreamer Xorg/Xvfb recording and screenshots. Validated against Xvfb in CI. |
| Linux Wayland | Best-effort | Portal-mediated capture via WaylandPortalRecorder, WaylandPortalWindowRecorder, and LinuxNativeScreenshotter. Validated on GNOME/Mutter only; KDE / sway / wlroots compositors may behave differently and are not exercised in CI. Real Robot input is unavailable on Wayland — use the synthetic adapter for tests. |
| BSD | Unsupported | Not built or tested. |
JVM runtime support tiers¶
Spectre is a JVM library and CLI. Supported JVM runtimes are the set we claim work for non-IDE modules; claims are fail-closed on executable evidence (same rule as the capability matrix).
| Runtime | Tier | Evidence / notes |
|---|---|---|
| JBR 21 (JetBrains Runtime, JBRSDK pin) | Primary (dev-loop default) | Local default; scheduled runtime matrix cell. Pins: .github/jbr-pins.env. |
| JBR 25 | Full | Runtime matrix cell; IntelliJ-hosted validation on platform 262 / IDEA 2026.2 (IDE-bundled JBR 25). |
| Temurin LTS (Eclipse Temurin at project toolchain major, currently 21) | Full | Per-PR CI (ci.yml / macos-check / windows) and runtime matrix vanilla cell. |
| Other vanilla LTS JDKs ≥ toolchain (e.g. other Temurin/Zulu majors ≥ 21) | Best-effort | Not every vendor/major is matrixed. Expect to work for non-IDE modules; regressions should be filed. |
| JVM < 21 | Unsupported | Toolchain and published bytecode target 21. |
What “supported” means operationally¶
- Exercised by the scheduled + release-gated runtime matrix
(
runtime-matrix.yml: contract corpus, agent attach where applicable, Linux recording smoke under xvfb) and/or by the IDE UI test path for JBR 25 in the IDE process. - Release-blocking: a red matrix blocks the tag-driven release pipeline
(
release.ymlcalls the matrix viaworkflow_callbefore helper builds / publish). - Not per-PR: everyday PRs stay on single-JDK Temurin 21 for speed. Compatibility signal is scheduled + release-gated, not every PR.
- Failures are triaged, not silent: scheduled cell failures open issues labelled
runtime-matrixrather than vanishing into Actions noise.
Adding or dropping a runtime¶
- Add: pin the runtime in
.github/jbr-pins.env(or Temurin major), extend the matrix include list, prove the cell green (or open a tracked triage issue), then document it here as Supported only when evidence exists. - Drop: remove matrix cells first (or mark them Unsupported with a linked issue), then update this table. Do not claim Supported without a green (or explicitly triaged) matrix path.
- Bump JBR pins: follow the bump procedure in
.github/jbr-pins.envand re-run the matrix viaworkflow_dispatch.
AndroidX-style stability expectations¶
Spectre adopts the cultural convention pioneered by AndroidX:
- Experimental APIs are explicit opt-in via a
@RequiresOptInannotation. The annotation carries the rationale ("not yet stable", "may change", etc.) and the opt-in is per file or per call site, not project-wide. - The compiler — not just docs — enforces the opt-in. Forgetting it is a warning (for
@ExperimentalSpectreHttpApi) or an error (for@InternalSpectreApi). - Stability promotions follow a deprecation cycle when feasible: when an experimental API graduates to stable, the marker is removed in the release that promotes it; when an experimental API is removed, it's done in a single release with the rationale documented.
Reporting incompatibilities¶
If a change in a Spectre release breaks your build or runtime in a way that wasn't called out
in the release notes, please open an issue at
https://github.com/rock3r/spectre/issues with the diff (a git log -p api/-style snippet
of the BCV baseline change is most useful) and what you observed.