---
title: "DroppyKitBuild, DroppyKit"
description: "Version constants of this DroppyKit build."
canonical: "https://getdroppy.app/docs/droppykit/api/droppy-kit-build"
last-updated: "2026-09-09"
---

# DroppyKitBuild

Version constants of this DroppyKit build.

`enum DroppyKitBuild`

## Type properties

### abi

`static let abi: Int`

The binary interface generation this DroppyKit was built as.

### apiVersion

`static let apiVersion: SemanticVersion`

The additive API version of this DroppyKit.

This is the version the repository is tagged at, and the two move together even when a release adds no API. A tag and a constant that disagree is the sort of thing nobody notices until they are debugging a handshake, at which point it is the first thing they distrust.

1.0.1 stated `@Sendable` on the main-actor closure parameters that were relying on it being inferred. A host compiled with approachable concurrency (SE-0434) already treats a global-actor-isolated function type as `@Sendable`, while this module's interface is emitted without that feature, so the two spellings of the same type disagreed across the module boundary and Droppy could not conform to its own services.

1.0.2 was documentation: the pages no longer described an install flow and an auto-update the host does not have.

1.1.0 adds the HUD's second shape. A droplet's HUD can now be a card as well as a strip, the shape Droppy's own low-battery and AirPods HUDs grow into, through a new [`DropletHUDRequest`](https://getdroppy.app/docs/droppykit/api/droplet-hudrequest) initializer. Additive: the original initializer keeps its symbol, so every droplet compiled against 1.0.x links unchanged.

1.1.2 fixes the harness's `--shots` mode, which resolved a relative directory against the bundled app's working directory and reported success after writing nothing. No API change.

1.2.0 is the coding-agent release: every scaffold carries the brief an agent reads and the MCP wiring for Claude Code, Codex and Cursor (`droppykit agent`), the SDK ships an MCP server (`droppykit mcp`), and the harness writes a JSON verdict (`--report`) beside the shots, which now render synchronously. No API change: a droplet that declares `minAPI` 1.1.0 still uses everything it did.

1.2.1 makes `droppykit build` work on the toolchain Xcode 26 ships: SwiftPM's native engine writes one object per source file and no `<Module>.o`, and 1.2.0 looked only for the latter. Adds `droppykit version` and `droppykit update`. No API change.

1.5.0 is for widgets the user watches rather than touches. A droplet can hold the expanded shelf open while its widget is on it ([`setHoldsOpen(_:)`](https://getdroppy.app/docs/droppykit/api/droplet-shelf-service#set-holds-open)), open its own Settings page from a widget button ([`openSettings()`](https://getdroppy.app/docs/droppykit/api/droplet-workspace-service#open-settings)), and ask the host for speech recognition through the new `speech-recognition` capability. Additive: every new requirement has a default, so a host or harness built against 1.4 still conforms.

1.6.0 gives a widget the host's own inset for its slot ([`contentInsets`](https://getdroppy.app/docs/droppykit/api/shelf-widget-context#content-insets)), which is zero under a notch. Every guide until now told a droplet to pad `DroppySpacing.mdl` on all four edges, and Droppy's own widgets pad nothing there, so a droplet sat 14pt lower and narrower than the built-in beside it. Additive: one computed property on a struct droplets only read.

1.6.1 gives [`DropletSliderRow`](https://getdroppy.app/docs/droppykit/api/droplet-slider-row) Droppy's own slider: the hosted `NSSlider` with no tick marks, a value pill you can click and type into, and arrow keys on the row. It used to build SwiftUI's `Slider`, which draws a tick per step and re-renders on every scroll frame. No API change.

1.6.2 ships the COMPILED icon in the bundle. `droppykit build` runs the same `actool` Xcode runs on an app's icon, so a droplet carries the real macOS icon — squircle, material, specular edge, shadow — and Droppy draws that instead of the flat preview this SDK renders from the document. No API change; rebuild a droplet to get it.

1.6.3 stops requiring `source.commit`. A manifest cannot name the commit that contains it, so the field accepted any string, was never consumed, and could not be accurate by definition. The submission carries the commit. [`commit`](https://getdroppy.app/docs/droppykit/api/droplet-source#commit) stays as a property and is empty when the manifest omits it, with a new initializer that leaves it out; an old manifest still decodes. 1.7.0 closes the category. [`DropletCategory`](https://getdroppy.app/docs/droppykit/api/droplet-category) names the three Store sections a droplet can appear under, and `validate(submission:)` refuses anything else instead of letting the host file it under Productivity with no error on any surface. `minAppVersion` is checked numeric-dotted for the same reason `version` already was: every comparison in the system reads components as integers, so a tagged value claims a release it is not. Additive in symbols; the two checks are a validation tightening, and a manifest that named a section the Store does not have was already being filed somewhere else.

1.7.1 tells the truth about live activities and draws the compiled icon flush. The guides now say the expanded surface is a hover card (not a shelf open), droplets hold compact or none (never the companion pill), and interactive state stays stable with `nil` only at the true end; `validate-droplet.sh` warns on a glass control in the live row and on a card sized off the host metrics. `DropletIconRenderer` trims the transparent border `actool` bakes around the squircle, so an external droplet fills the widget frame like a built-in. No API change; rebuild a droplet to get the icon.

1.8.0 says how content appears. A host on 1.8.0 animates a live activity's accessories, its hover card and a HUD's strip and card onto the notch and off it exactly as Droppy's own: the card grows out of the notch with the shell and folds back into it, and the compact content unfolds again with a blur once the card has gone. Before, a droplet's two layouts traded places in one frame. Adds [`DroppyTransition`](https://getdroppy.app/docs/droppykit/api/droppy-transition) (`compactContent`, `compactLeading`, `compactTrailing`, `element`, `expandedContent`), the host's own transitions for content a droplet swaps while a surface is up, and [`notchOpen`](https://getdroppy.app/docs/droppykit/api/droppy-animation#notch-open) and [`notchClose`](https://getdroppy.app/docs/droppykit/api/droppy-animation#notch-close). Additive; the host motion needs no rebuild, the new API needs `minAPI` 1.8.0.

1.8.1 makes droplet surfaces behave exactly like Droppy's own. A live activity is compact only and mounted like Droppy's own chips: hovering or clicking it opens the shelf, and `makeExpanded` is not mounted (the requirement stays for ABI). A HUD is mounted exactly like Droppy's battery HUD. The motion 1.8.0 described for a hover card no longer exists; the guides, the agent brief and the validator say so. No API change.

1.9.0 makes a droplet's settings pane native. Droppy's Settings pages are the grouped `Form` System Settings is built from, and a pane rooted in the new [`DropletSettingsPane`](https://getdroppy.app/docs/droppykit/api/droplet-settings-pane) joins it: every kit row renders as the Form's own row, with no card, divider or row metric drawn by hand. Adds [`DropletSettingsPane`](https://getdroppy.app/docs/droppykit/api/droplet-settings-pane), [`DropletSettingsSection`](https://getdroppy.app/docs/droppykit/api/droplet-settings-section) and `ContainerValues.dropletSettingsPaneIsNative` (macOS 15+). A pane rooted in a `VStack` of cards is pixel-unchanged. Additive; the new root needs `minAPI` 1.9.0.

1.10.0 makes shelf keyboard focus real for external widgets. A `keyboardFocusable` widget is promoted when it opens alone, and [`requestKeyboardFocus()`](https://getdroppy.app/docs/droppykit/api/droplet-shelf-service#request-keyboard-focus) asks for the same promotion when its field appears later; a granted request keeps the panel eligible for the keyboard while the widget is on the shelf, Settings window or not. A droplet calling the method needs `minAPI` 1.10.0.

1.11.0 is the Droplet Store repository release. Droplets are published from gitlab.com/droppyformac1/droplets, one folder each, and `droppykit submit` opens the merge request that puts one there. Two additions in the SDK itself: [`DropletURLHandling`](https://getdroppy.app/docs/droppykit/api/droplet-urlhandling), through which a droplet receives `droppy://droplet/<id>/…` URLs (the reply channel a droplet that drives another app needs), and [`gitlab`](https://getdroppy.app/docs/droppykit/api/droplet-creator#gitlab), the maker's GitLab username the repository's `CODEOWNERS` is generated from. Additive: a droplet adopting either declares `minAPI` 1.11.0, every other droplet links unchanged.

1.12.0 is the launcher release. [`DropletLauncherService`](https://getdroppy.app/docs/droppykit/api/droplet-launcher-service), on [`launcher`](https://getdroppy.app/docs/droppykit/api/droplet-host#launcher) behind the `launcher` capability, offers a droplet that draws a launcher Droppy's commands, droplets, settings and content (clipboard history, notes, OCR, recordings, tasks, the shelf, web answers), to list with its own search and run through the host. [`minMacOS`](https://getdroppy.app/docs/droppykit/api/droplet-manifest#min-mac-os) names the oldest macOS a droplet runs on, which the bundle carries as `LSMinimumSystemVersion`: the Store leaves it off an older Mac's shelf and the loader refuses it there. [`DroppyPanelSurface`](https://getdroppy.app/docs/droppykit/api/droppy-panel-surface) is Droppy's launcher surface, Dynamic Glass included, for a droplet's own floating panel. Additive: a droplet reading `host.launcher` or drawing the surface declares `minAPI` 1.12.0.

1.13.0 gives a droplet's Settings page pages of its own. [`SettingsPagesProviding`](https://getdroppy.app/docs/droppykit/api/settings-pages-providing) builds them, [`DropletSettingsPageLink`](https://getdroppy.app/docs/droppykit/api/droplet-settings-page-link) is the row that opens one inside Droppy's Settings window (Droppy's toolbar, history and sidebar beside it), [`DropletSettingsPage`](https://getdroppy.app/docs/droppykit/api/droplet-settings-page) is a page's grouped-Form root, and [`openSettingsPage(_:title:)`](https://getdroppy.app/docs/droppykit/api/droplet-workspace-service#open-settings-page-title) opens one directly. Additive: a droplet adopting them declares `minAPI` 1.13.0.

1.14.0 lends a droplet Droppy's own shortcut recorder: [`DroppyShortcutRecorder`](https://getdroppy.app/docs/droppykit/api/droppy-shortcut-recorder) is the native button and recording bubble every shortcut in Droppy's Settings records through, drawn by the host, for a shortcut the droplet keeps itself. Additive: a droplet drawing it declares `minAPI` 1.14.0.

1.15.0 makes Droppy the active app while a droplet's floating panel is up: [`DroppyPanelActivation`](https://getdroppy.app/docs/droppykit/api/droppy-panel-activation), begun after the panel is ordered front and finished before it is ordered out, so the panel gets every mouse move (hover) and the foreground goes back to the app it was summoned over. Additive: a droplet using it declares `minAPI` 1.15.0.

1.16.0 puts a droplet's own shortcuts on Droppy's Shortcuts page, the one place every shortcut in Droppy is set: [`ShortcutsProviding`](https://getdroppy.app/docs/droppykit/api/shortcuts-providing) lists them as [`DropletShortcutEntry`](https://getdroppy.app/docs/droppykit/api/droplet-shortcut-entry) rows that Droppy records with its own recorder, and [`openShortcuts()`](https://getdroppy.app/docs/droppykit/api/droplet-workspace-service#open-shortcuts) opens the page on the droplet's section. Shortcuts registered through [`DropletShortcutsService`](https://getdroppy.app/docs/droppykit/api/droplet-shortcuts-service) are listed there too, as that service has always promised. Additive: a droplet adopting them declares `minAPI` 1.16.0.

1.16.1 adds no API. `droppykit build` reads which DroppyKit API a built droplet calls and refuses a `kit.minAPI` older than the newest of it, which passed the handshake on an older host and died at dyld.

1.17.0 lets a droplet's own Settings page finish by itself: [`goBackInSettings()`](https://getdroppy.app/docs/droppykit/api/droplet-workspace-service#go-back-in-settings) steps Droppy's Settings back the way the toolbar's Back does, for an editor's Save or a picker's pick. And `droppykit build` links every target of the droplet's own package that its product depends on, not only the product's own, so a droplet can carry a vendored library as a target of its own (DropClip keeps OpenSelection and its core that way). Every `String` DroppyKit draws (row titles, info tips, options, page links) is looked up in Droppy's own string catalog first, so a droplet's page reads in Droppy's language where Droppy has its words; that is the host's DroppyKit, so it reaches droplets built against any earlier version too. Additive: a droplet going back declares `minAPI` 1.17.0.

1.17.1 adds no API. Every pop-up in a settings row sits on the trailing edge, sized to its content, the way System Settings draws one: the kit's own picker rows are the Form's pop-up row, and a droplet's own `Picker` in `DropletControlRow` or `DropletGroupedPickerRow` hugs its content instead of filling a column with its title and chevrons centred. That is the host's DroppyKit, so droplets built against earlier versions get it too.

1.18.0 puts a droplet page's own controls in Droppy's Settings toolbar: [`makeSettingsPageToolbar(id:context:)`](https://getdroppy.app/docs/droppykit/api/settings-pages-providing#make-settings-page-toolbar-id-context) (a new requirement with a default of none) returns them for the page on screen, and the host draws them at the right of the toolbar, where Droppy's own pages keep theirs, instead of a bar the page scrolls under. [`DropletSettingsToolbarButton`](https://getdroppy.app/docs/droppykit/api/droplet-settings-toolbar-button), [`DropletSettingsToolbarMenu`](https://getdroppy.app/docs/droppykit/api/droplet-settings-toolbar-menu), [`DropletSettingsToolbarSwitch`](https://getdroppy.app/docs/droppykit/api/droplet-settings-toolbar-switch) and [`DropletSettingsToolbarSearchField`](https://getdroppy.app/docs/droppykit/api/droplet-settings-toolbar-search-field) are Droppy's Liquid Glass pills ([`DropletSettingsToolbarPill`](https://getdroppy.app/docs/droppykit/api/droplet-settings-toolbar-pill), drawn by the host through `DroppyKitSurfaceBridge`), laid out on [`DropletSettingsToolbarMetrics`](https://getdroppy.app/docs/droppykit/api/droplet-settings-toolbar-metrics). DropClip's pages use it. Additive; a droplet adopting it declares `minAPI` 1.18.0.

1.19.0 adds [`DropletConfirmationDialog`](https://getdroppy.app/docs/droppykit/api/droplet-confirmation-dialog). Droplets ask a question through the host's own glass popup and act only on explicit confirmation.

1.20.0 adds host-specific droplet callback URLs, including Playground. Dynamic widget traits and invalidations are consumed by both hosts and the harness. Failed activation is cleaned up before reporting refusal.

1.20.1 adds no API and changes [`contentInsets`](https://getdroppy.app/docs/droppykit/api/shelf-widget-context#content-insets) in two places. The Dynamic Island keeps one even gap: a solo widget there is no longer clipped at its card, the island shell is the clip, so the inset is zero for it (it was 12) and a droplet sits flush to its rectangle beside Droppy's own widgets; [`shelfFullBleedCornerRadius`](https://getdroppy.app/docs/droppykit/api/droppy-shell-metrics#shelf-full-bleed-corner-radius) is concentric with the island at the card's distance (26.5, was 34), and the harness draws a solo island card unclipped. Everywhere the host still clips the card at its continuous 18pt corner (every card under a notch, every grouped row on either shape), the inset is 8 ([`sm`](https://getdroppy.app/docs/droppykit/api/droppy-spacing#sm)) on every edge, where it was zero and a header's symbol lost its corner to the clip; the corner needs 5.25, so 8 leaves 2.75 of margin. The numbers come from the running Droppy, so every droplet that pads with it gets both on Droppy 16.0.1 without a rebuild, and keeps zero and 12 on 16.0.0 and earlier. Under the 18pt corner it gives up parity with Droppy's own widgets, which draw flush and clear the corner element by element: a droplet's content sits 8pt in from the edge there. A `.fixed` or dynamic height loses 16pt to it under the 18pt corner and none alone on the island, and a context built with the 1.0 initializer (which never sets `usesIslandCurvature`) reads 8. The harness hands each stage the flags the host gives it, where it used to take them from the Mac it ran on.

1.21.0 adds the notch wrap: [`ShelfWidgetNotchWrapTraits`](https://getdroppy.app/docs/droppykit/api/shelf-widget-notch-wrap-traits), declared in [`notchWrap`](https://getdroppy.app/docs/droppykit/api/shelf-widget-layout-traits#notch-wrap) through a new initializer, and [`ShelfWidgetNotchWrap`](https://getdroppy.app/docs/droppykit/api/shelf-widget-notch-wrap) in [`notchWrap`](https://getdroppy.app/docs/droppykit/api/shelf-widget-context#notch-wrap). A solo widget under a notch that opts in gets its header row split across the bands beside the camera, like Droppy's own Notes and Pomodoro. Additive: a widget that does not opt in, and every context built with the older initializers, reads `nil` and keeps the classic layout. It also adds the timer wash, [`DroppyWashCircleButtonStyle`](https://getdroppy.app/docs/droppykit/api/droppy-wash-circle-button-style) and [`DroppyWashPillButtonStyle`](https://getdroppy.app/docs/droppykit/api/droppy-wash-pill-button-style) with [`DroppyWashTone`](https://getdroppy.app/docs/droppykit/api/droppy-wash-tone): the flat-wash controls of Droppy's own Pomodoro and Stay Awake. A droplet adopting either declares `minAPI` 1.21.0. With them the design rule changes: every control a widget draws on the shelf is the wash (34pt alone, 28pt paired or in the row wrapped beside the camera, 24pt in a list row), and the Liquid Glass styles stay for the droplets that use them and for controls floating over content outside a widget.

1.21.0 lines a grouped row up: [`contentInsets`](https://getdroppy.app/docs/droppykit/api/shelf-widget-context#content-insets) is zero on every edge in a row of two to four widgets and the host clips the card square and hands it the declared height less those 16pt, so a droplet's first row starts on the row's top line and its last ends on the bottom line, where Droppy's own widgets' do. It was 8, which put a droplet's header 8pt under the built-in beside it. The number comes from the running Droppy, so every droplet gets it without a rebuild.

1.21.0 draws icons in the user's icon style. macOS 26 lets a user draw every app icon Default, Clear or Tinted, light or dark, in a tint of their choosing, and the Dock follows it live. [`DroppyIconStyle`](https://getdroppy.app/docs/droppykit/api/droppy-icon-style) is that choice, [`DroppyIconStyleObserver`](https://getdroppy.app/docs/droppykit/api/droppy-icon-style-observer) keeps it current (a SwiftUI body that reads `style` redraws when it changes), `EnvironmentValues.droppyIconStyle` pins one for previews, [`DroppySystemIconRenderer`](https://getdroppy.app/docs/droppykit/api/droppy-system-icon-renderer) draws a bundle's icon in any style through the system's own renderer, with the compiled icon's real Liquid Glass, and [`icon(inBundleAt:style:pixelSize:)`](https://getdroppy.app/docs/droppykit/api/droplet-icon-renderer#icon-in-bundle-at-style-pixel-size) does it for an installed droplet. A droplet's own icon needs no change: the host on 1.21.0 draws it in the user's style from the `Assets.car` `droppykit build` has written since 1.6.2. Additive; a droplet reading the style declares `minAPI` 1.21.0.

1.21.0 also lets a droplet offer typed actions to AI apps through Droppy's MCP server: [`MCPToolProviding`](https://getdroppy.app/docs/droppykit/api/mcptool-providing) lists [`DropletMCPTool`](https://getdroppy.app/docs/droppykit/api/droplet-mcptool) values and runs one call with its arguments as JSON text. Droppy lists them once the user switches on its MCP droplet and allows droplets on that page, and asks before every call to a destructive one. Additive; a droplet adopting it declares `minAPI` 1.21.0.

1.21.0 also hands droplets Droppy's own floating player: [`DroppyNowPlayingPlayer`](https://getdroppy.app/docs/droppykit/api/droppy-now-playing-player) is the real player, showing what is playing, laid out at the size and corner radius of the droplet's own cards when it asks (`init(size:cornerRadius:)`), with [`size`](https://getdroppy.app/docs/droppykit/api/droppy-now-playing-player#size) `nil` where the host draws none. Additive; a droplet using it declares `minAPI` 1.21.0, or weak-links it and checks for it first.

### supportedABIRange

`static let supportedABIRange: ClosedRange<Int>`

The ABI generations a host built against this DroppyKit should advertise: this generation plus the one before it, once one exists.

The handshake has always taken a range so a host can hold the previous generation through a transition, and the shipping host has always advertised `abi...abi`, which is one generation. That mismatch is invisible while ABI is 1 and becomes load-bearing on the day ABI becomes 2, which is the day it is too late to notice. Hosts advertise this constant instead of building their own range, so the policy arrives with the bump rather than after it.

At ABI 1 this is `1...1`, because there is no earlier generation to hold. At ABI 2 it becomes `1...2` with no host change.
