Skip to main content

Versioning, stability and migration

How @spartaficial/spart-desk and @spartaficial/spart-desk-agent are versioned, which parts of the API are stable, experimental or internal, and how breaking changes are announced and migrated. Read it before you pin a version or build on an extension point.

Semantic versioning policy​

@spartaficial/spart-desk and @spartaficial/spart-desk-agent follow SemVer 2.0. Before 1.0:

  • 0.x minor versions (0.2, 0.3, …) may contain breaking changes to the public API; each is listed in this file with its justification and migration.
  • 0.x patch versions never break the public API.
  • From 1.0, breaking changes require a major version, and a deprecation is announced at least one minor version ahead (typed as @deprecated, logged once at run time where possible).

The two packages are versioned independently; the agent package declares the engine version range it needs (^<version>).

API surface tiers​

TierWhatGuarantee
StableDesktop, Application, DesktopLocator (all getBy*, read, locator, nth/first/last, actions, waitFor), ScreenLocator and LocatorBase, expectDesk (locator assertions, poll, toPass, value matchers, configure), DesktopOptions, spart-desk.config.ts (SpartDeskConfig, defineConfig, loadConfig), DesktopControl/ControlSnapshot/WindowInfo/ApplicationTarget, the error classes and their code/reason unions, ActionRecord/ActionLog, Trace/TraceEntry, FakeDriver/FakeRuntime/FakeOcrProvider/FakeGroundingProvider (/testing), the spart-desk CLI commands (including init) and the offline-bundle manifest schema 1.SemVer as above.
Experimentalruntime: "sandbox" (createSandboxRuntime, SandboxRuntimeOptions), grounding.provider (the GroundingProvider contract).May change in minor versions until their external prerequisites are validated (the sandbox runtime against a live Windows Sandbox; a grounding provider on real applications). Changes are documented here.
Extension pointsDesktopDriver, DesktopRuntime, OcrProvider, GroundingProvider, DesktopAction/InputAction.Most members of DesktopDriver and DesktopRuntime are required; an optional one has a fallback its documentation names (api.md). A new required member is a breaking change and comes in a minor version (a major one from 1.0), listed here. Adding an optional member to any of these interfaces, or a variant to DesktopAction/InputAction, is not breaking; implementers should default in exhaustive switches.
InternalThe Windows backend beyond WindowsDriver/WindowsDriverOptions/ExecutionTarget, the helper's own protocol, @internal-tagged members (stripped from the published types).No guarantee.

getByVision belongs to the stable locator API but does nothing without a grounding provider, which is experimental.

There is no runtime artifact to pin: the Windows backend is the helper executable (spart-desk-host.exe), built from the engine package's own sources and versioned with it. Its protocol version (spart-desk-host.exe version) changes only together with the engine code that speaks it, and a helper of another build is refused.

Release workflow​

Releases are built and signed in Spartaficial's release pipeline: the helper executables ship signed, and the packages are published from it. Versions and changelogs are managed with changesets, so every breaking change and its migration is recorded in each package's CHANGELOG.md; the table below covers the changes made before that.

Breaking changes so far​

0.1.0 → next release​

ChangeWhyMigration
ControlSource is "uia" | "vision" (was … | "fake"); FakeDriver reports "uia". Since widened to "uia" | "java" | "ocr" | "image" | "grounding" | "region", one value per way a control is found.A test double leaked into the public model; narrowing later would be a bigger break.Replace source === "fake" checks with "uia". Only tests are affected.
ActionStrategy no longer includes `fake.${string}`.Same reason.None expected in consumer code.
MCP desktop_snapshot returns compact text by default, fenced as untrusted content; format: "json" restores the object form (now with depth, total, truncated, omitted). desktop_get_text (since replaced by desktop_inspect) and desktop_list_applications are fenced too.Token economy and prompt-injection mitigation.Agents parsing JSON pass format: "json" and strip the fence markers.
MCP desktop_snapshot is capped at 200 controls (deepest dropped first).Bounded tool output.Scope with root/maxDepth or raise maxControls.
expectDesktop is renamed expectDesk.Shorter, and the API now covers more than locators (poll, toPass, value matchers): one short name for all of it.Replace the import and the calls; locator assertions behave as before.
assertionTimeout (DesktopOptions, DesktopConfig) is replaced by expect: { timeout }; DesktopConfig.expect also carries toPass: { timeout, intervals }.The name every expect default shares in spart-desk.config.ts; one place for all of them.Desktop.create({ assertionTimeout: n }) → Desktop.create({ expect: { timeout: n } }); desktop.config.assertionTimeout → desktop.config.expect.timeout.
pollingInterval (DesktopOptions, DesktopConfig, the config file) is replaced by intervals: readonly number[] (default [100, 250, 500, 1000], last entry repeats); every auto-waiting method accepts a per-call intervals.A backoff schedule for every wait, and one setting for actions, assertions, poll and toPass.pollingInterval: n → intervals: [n]; desktop.config.pollingInterval → desktop.config.intervals.
DesktopDriver: the members a driver used to leave out are required (a question it cannot answer returns undefined, an action it cannot take throws not_supported); capabilities is a DriverCapabilities (nativeInput, screenshot, capture, java) the engine reads instead of looking for methods.The engine checked for a method, then the backend refused anyway: two ways of saying "cannot", and decorators that copied methods only so that their absence stayed visible.Implement the members a driver lacked and declare capabilities. A FakeDriver subclass that writes screenshots passes { capabilities: { screenshot: { available: true } } }.
DesktopRuntime: prepare is required, launch returns a LaunchResult with attachedToExisting: boolean, terminate(target, { since, force? }) takes its options always. SandboxRuntimeOptions.connect/guestRoot are removed.Nothing had to normalise a bare target or a missing since; options that did nothing are gone.Return { target, attachedToExisting: false }; pass { since: Date.now() } to a direct terminate.
desktop.close(), mouse.dblclick(), app.controls() and the type ResolverName are removed.One way to do each thing.desktop.dispose(); mouse.click(point, { clickCount: 2 }); (await app.snapshot()).controls; ControlSource.
rightOf/leftOf/above/below take only the anchor; getByVision no longer offers fuzzy, dblclick no longer offers mouse; isVisible/count/all/allTextContents take SignalOptions. InputOptions is renamed SignalOptions.Options a method ignored were accepted without effect.Drop the ignored options.
OcrSettings → OcrOptions, GroundingThresholds → GroundingOptions, ImageSettings/ImageConfig → ImagesOptions/ImagesConfig, ExpectSettings/ToPassSettings → ExpectDefaults/ToPassDefaults; ExpectConfigureOptions and PollOptions → ExpectOptions, ToPassOptions → AssertionOptions.One type per setting, named after it.Rename the imports.
The main entry no longer exports the engine's internals (the resolution planner, the capability probe, screen and image plumbing, snapshot building, diagnostics helpers, suggestLocator(s), withTranscript, StdioHost, …); WindowKeyboard, WindowMouse, RowQuery, ColumnCondition, ItemQuery are types only; LocatorAssertions/TableAssertions/ListAssertions give way to the *Matchers types.A smaller surface to learn and to keep stable.candidatesFor/recommendLocators for suggestions; transcript: { onTraffic } for transcripts; matchTemplate, decodePng, toGray stay.
OCR readers are named as ocr.provider names them: "windows" (was "windows-ocr") and "paddle" (was "paddle-ocr"), in desktop.textName, records and errors.One name per reader.Compare against the new names.
Agent: desktop_click_at → desktop_mouse (MOUSE_TOOL, spart-desk-cli mouse, --allow-mouse, allowMouse, sensitive action mouse, violation mouse-disabled); AgentSession methods take one request object; mouseAt/clickAt → mouse; restrictedKeys adds to the defaults; AgentError.code is typed.Names that say what the tool does; one calling convention; a policy cannot drop a default restriction by accident.See the agent's changesets for each rename.

Additions in the same release (non-breaking): DesktopLocator.nth/first/last, nth= in the string grammar, CapabilityUnavailableError, InstallError (since removed with the installer), the /install entry point, the spart-desk CLI, MCP desktop_attach (opt-in), snapshot root/maxDepth/maxControls, complete tool annotations; expectDesk's .not, custom messages, configure, poll and toPass (both resolving with their value), value matchers, AssertionError.customMessage and its non-locator subjects (poll(), callback, value; timeout is 0 for one-shot assertions); the project configuration (spart-desk.config.ts, defineConfig, loadConfig, findConfigFile, ConfigError, Desktop.create({ configFile })) and spart-desk init.

Deprecation policy​

Deprecated members are marked @deprecated with the replacement, kept for at least one minor version after 1.0, and listed here with the version that removes them.