You can build your own tools for Droppy. A timezone clock, a small status display or a focused workflow can live on its shelf and notch, written in SwiftUI against the public DroppyKit SDK. The useful starting point is one small thing you want within reach while you work.
Version note, September 19, 2026: this guide follows DroppyKit 1.8.1. Its current scaffold declares a Droppy 15.3.0 minimum, which is newer than the public 15.2.2 beta and September 12 nightly. That requirement is enforced. Start with the harness; use a Playground or Droppy build that meets your droplet's declared minimum before installing it. The host support guide describes the 15.3 surface target, not a promise that every older download supports it.
Scripts folder on your PATH, run droppykit new to scaffold, droppykit run to see your views in the harness, and droppykit build to get a .droplet bundle in .build/. Droppy loads that bundle into its own process, so a droplet is not sandboxed code: it runs in-process, on the main actor, with Droppy's permissions. You need macOS 14 or later, Swift 6.2 with Xcode 26, and Droppy 15.3.0 or later.
What a droplet can put on screen
A droplet draws through surfaces that ship inside Droppy: a shelf widget on the expanded shelf, a live activity in the compact row beside the notch, a mini HUD for a short confirmation, and, beyond those, a lock screen row, a menu bar extra, a shelf takeover and a settings pane in Droppy's own Settings window. Not every surface is in every release. The SDK's Host support page names a Droppy version and what it mounts, and in 15.3 all of these are mounted. A surface Droppy cannot mount refuses and says so rather than appearing to succeed.
Setting up the toolchain
droppykit is not in the package your droplet depends on, because SwiftPM checks the SDK out for the compiler, not for you. It lives in the SDK repository's Scripts folder: clone that repository once and add the folder to your PATH with an export line in your shell profile.
From a directory where you keep projects, the public DroppyKit repository gives you this starting sequence. The new droplet is a separate folder beside the SDK checkout.
git clone https://gitlab.com/droppyformac1/droppykit.git
export PATH="$PWD/droppykit/Scripts:$PATH"
droppykit new worldclock --name "World Clock"
cd worldclock
droppykit run
Scaffolding with droppykit new
droppykit new worldclock --name "World Clock" writes a package that builds, a droplet that runs, a manifest that validates, a starter Icon Composer document and a placeholder avatar, so droppykit validate passes before any of it has been replaced. The Swift type name comes from the id: world-clock becomes WorldClock. It also writes AGENTS.md, CLAUDE.md and the MCP wiring for Claude Code, Codex and Cursor, because most droplets are written with an agent at the keyboard.
Droplet ids have rules, because an id becomes a directory name, a preferences namespace and part of a path: 3 to 40 characters of lowercase letters, digits and hyphens, starting with a letter and ending with a letter or digit. Dots are forbidden, since preferences are namespaced to droplet.<your-id>.<key>, so a dot would let one droplet's keys overlap another's namespace.
The entry point, and why the bundle is a library
Every droplet has two types. The principal is what Droppy's loader instantiates through the bundle's NSPrincipalClass: it is @objc and does nothing but make the droplet, because it runs before the host is ready. The droplet lives for the session, conforms to Droplet, and holds the host.
activate(host:) is called once, after Droppy's managers are up, and runs under a watchdog: keep it fast and store the host, because there is no global accessor. Throwing marks the droplet failed for the session. deactivate() is called on disable or removal, and everything started in activation has to stop there, because Swift cannot unload code and a timer left running keeps running until Droppy relaunches. prepareForRemoval() returns true by default and can veto a removal that would lose work in flight.
The product is a dynamic library on purpose. Droppy already carries DroppyKit as a resilient framework, and your bundle must link that framework in the form the host expects. A bare swift build is not the supported packaging path: linking a second SDK copy or using non-resilient imports can cause type-identity or missing-symbol failures. Use droppykit build, which applies the library-evolution and linkage settings, then droppykit validate before sharing the bundle.
The manifest is what everything else reads
droplet.json tells the build script, the validator, the Store and getdroppy.app what this droplet is: its id, name and version, the kit block with its ABI and minimum SDK API, minAppVersion, the declared capabilities and surfaces, its icon, creator and source repository. Two fields matter most. surfaces and your Swift conformances must agree in both directions, and the harness reports the difference, because a manifest and code that disagree is the most common reason a droplet validates locally and does nothing once installed. And capabilities are shown to the user before they install, so ask for what you use and nothing more: a long list is the most common reason a submission is sent back.
| Where you work | Command | What you get |
|---|---|---|
| First package | droppykit new | Package, manifest, icon document, harness target |
| Edit and run loop | droppykit run | Every surface, in Droppy's Settings panel chrome |
| Pictures for review | droppykit run -- --shots ./shots | One PNG per harness page, no window |
| Machine-readable verdict | droppykit run -- --report ./report.json | Surfaces, problems, activity and log as JSON |
| Shipping bundle | droppykit build | <Product>.droplet in .build/ |
| Submission checks | droppykit validate | The same checks a submission runs |
Iterating in the harness
droppykit run opens your droplet in the harness, which uses Droppy's Settings panel source in a larger window so a solo and a paired widget fit side by side. Its host services simulate interactions: preferences live in memory and workspace.open records a URL instead of opening it. This makes the editing loop convenient, but it is not a sandbox around arbitrary code your droplet runs directly.
Two of its pages catch more than the rest. Overview compares conformances against the manifest and names a surface you declared but did not implement, or implemented without declaring, and its Hardware notch switch re-renders everything as a floating island, where content that assumed wings either side of a cut-out falls over. --shots renders each page to a PNG without a window, and --report writes the verdicts as JSON, where problems lists everything the pages would flag. A droplet is not finished while problems has anything in it.
The same droplet on the real surfaces
Droppy Playground is a free, separate app drawing the notch, shelf, island and HUDs with Droppy's code. It includes the media player and omits the full app's file shelf, clipboard and Cloud features. Drop a built bundle or the package onto its Store page; a package is searched for a built bundle under .build/. It runs the same admission checks apart from Droppy's approval policy, and checks compatibility against the Droppy host version it was built from.
Release Droppy loads a local .droplet too, from the Local droplets section of its Store page. A droplet runs with Droppy's permissions, so before running a build it did not sign, Droppy asks, and the answer lasts until Droppy quits: nothing is recorded on disk, so nothing another app writes can approve a build for you. A bundle changed after approval is refused until you approve it again, so keep anything your droplet writes out of its own bundle. Rebuilding a droplet that has run installs the new bundle, but the earlier build keeps running until you restart Droppy.
The SDK ships the guides this workflow comes from: Create your first droplet, Droplet setup, Harness, Playground and Submitting. The companion guide to surface design takes the other half of the job.
Sources and version scope
Scripts folder, with the requirements in Add SPM. Harness pages, --shots and --report are in Harness, and the Playground's install path, with release Droppy's per-launch approval for a local build, in Playground and Host support.