Release Screendrop
This skill releases new versions of Screendrop using a custom Go CLI
(cmd/screendrop-release). The CLI can run fully automated and
non-interactively, so a release can be triggered directly from a chat session
(the agent can run it end to end).
There are two modes:
- Full auto (
-build) - archive, export (Developer ID), notarize, staple,
package, sign, and publish. Nothing in Xcode's GUI is required.
- Package-only (no
-build) - assumes the user already exported a
notarized ~/Downloads/Screendrop.app from Xcode, then packages & publishes.
Prefer full auto unless the user says they've already exported the app.
Prerequisites
Always required:
- Tools installed:
create-dmg (brew), gh (GitHub CLI, authenticated), git, plutil.
- The Sparkle
sign_update binary in DerivedData (created when the project is
built/archived - the -build flow produces it automatically).
For full auto (-build) additionally:
xcodebuild, xcrun, ditto (all part of Xcode / command line tools).
- A notarytool keychain profile named
screendrop-notary (already set up
on this machine via an App Store Connect API key). It was created once with:xcrun notarytool store-credentials "screendrop-notary" \
--key /path/to/AuthKey_XXXXXXXXXX.p8 --key-id XXXXXXXXXX --issuer <issuer-uuid>
If notarization fails with a credentials error, this profile is missing or
wrong - ask the user to re-run store-credentials.
The Release CLI
Source: /Users/fayazahmed/Developer/fayazara/mac/Screendrop/cmd/screendrop-release/
Flags
-build - run the archive → export → notarize → staple phase first.
-set-version <x.y.z> - set MARKETING_VERSION before archiving (and commit it). Used with -build.
-set-build <n> - set CURRENT_PROJECT_VERSION before archiving (and commit it). Used with -build.
-scheme <name> - Xcode scheme to archive (default Screendrop).
-notes "<text>" - release notes, one bullet per line (markdown - prefixes are stripped). Skips the interactive prompt.
-notes-file <path> - read release notes from a file instead.
-notary-profile <name> - notarytool keychain profile (default screendrop-notary).
-yes / -y - assume "yes" for all confirmation prompts (non-interactive).
Triggering a full release from here (recommended)
- Decide the version and build number. The build number
(
CURRENT_PROJECT_VERSION) must increase every release or Sparkle won't
offer the update. Check the current values:grep -E "MARKETING_VERSION|CURRENT_PROJECT_VERSION" \
Screendrop.xcodeproj/project.pbxproj | sort -u
Pick the next MARKETING_VERSION (use real dotted semver like 0.20.2, never
regress - e.g. don't go 0.19 → 0.2) and CURRENT_PROJECT_VERSION = current + 1.
- Make sure code changes are committed and pushed to
main first, so the
release tag points at the released source. (The CLI commits the version bump
and pushes the appcast, but it does not push your other unrelated commits.)
- Run it (this is non-interactive and safe to run from a tool call):
cd /Users/fayazahmed/Developer/fayazara/mac/Screendrop && \
go run ./cmd/screendrop-release -build -yes \
-set-version <x.y.z> -set-build <n> \
-notes "First note
Second note"
Notarization blocks for a few minutes - this is expected, not a hang. Use a
generous tool timeout (~7 min).
Package-only (app already exported by the user)
cd /Users/fayazahmed/Developer/fayazara/mac/Screendrop && \
go run ./cmd/screendrop-release -yes -notes "Your notes here"
What it does (in order)
With -build:
- Set version/build (if
-set-version/-set-build given) - edits pbxproj and commits.
- Archive -
xcodebuild archive (scheme Screendrop, Release, generic/platform=macOS).
- Export -
xcodebuild -exportArchive with a generated Developer ID ExportOptions.plist.
- Notarize - zips the app and runs
xcrun notarytool submit --wait, verifying status: Accepted.
- Staple -
xcrun stapler staple, then places the app at ~/Downloads/Screendrop.app.
Then always:
6. Preflight checks + validate the app's version/build and Sparkle keys.
7. Collect release notes (from -notes/-notes-file, else stdin).
8. Create DMG with create-dmg → ~/Downloads/Screendrop.dmg.
9. Sign DMG with Sparkle sign_update (EdDSA).
10. Push commits - push any local commits (e.g. the version bump) to main.
11. GitHub release - gh release create vX.Y.Z with the DMG attached.
12. Update + push appcast.xml - prepend the new <item> (de-duping any entry for the same build), commit & push to main.
13. Homebrew cask - regenerate and push the cask to fayazara/homebrew-tap (non-fatal).
Ordering & robustness: the release is created before the appcast is
pushed, so a published appcast never points at a missing release. Network
operations (gh, git push) are retried with backoff. Re-running a release is
safe: an existing GitHub release gets the DMG re-uploaded (--clobber) and the
appcast entry for that build is replaced rather than duplicated. The -build
phase also auto-points DEVELOPER_DIR at Xcode, so it works even when the
active developer dir is the Command Line Tools.
Environment / constants
- Repo auto-detected at
~/Developer/fayazara/mac/Screendrop (override with SCREENDROP_REPO).
- GitHub repo:
fayazara/screendrop · branch: main · team: TB2S44TFQS · bundle: com.fayazahmed.Screendrop.
- DMG volume:
Screendrop · minimum macOS: 26.4.
Sparkle Configuration
- SUFeedURL:
https://raw.githubusercontent.com/fayazara/screendrop/main/appcast.xml
- SUPublicEDKey:
MA/6n0fqT0T2updDlkXr8BjhJKoHWik9uf6Lh5pUG7U=
- UpdaterManager.swift: Singleton, starts at launch (Release builds only), menu bar + Settings UI integration.
After releasing
Verify the release succeeded:
gh release view v<x.y.z> --repo fayazara/screendrop --json tagName,assets -q '{tag: .tagName, assets: [.assets[].name]}'
The CLI pushes the appcast commit itself, so run git pull --ff-only origin main
afterward to sync your local main.
Troubleshooting
- Partial failure / network error mid-release - just re-run the exact same command. The pipeline is idempotent: an existing GitHub release gets the DMG re-uploaded, and the appcast entry for that build is replaced (not duplicated). Network calls already retry with backoff.
- notarytool credentials error - the
screendrop-notary keychain profile is missing/invalid; have the user re-run store-credentials.
- Notarization "Invalid" - inspect with
xcrun notarytool log <submission-id> --keychain-profile screendrop-notary (usually a signing/entitlements issue).
xcodebuild archive fails - the CLI prints the last ~40 lines and auto-sets DEVELOPER_DIR to Xcode; if it still fails, common causes are signing or a Dev-scheme/LSUIElement mismatch. Confirm scheme is Screendrop (not Screendrop Dev).
- Screendrop.app not found (package-only mode) - the user must export from Xcode first, or use
-build.
- sign_update not found - build/archive the project once so DerivedData has the Sparkle artifacts.
- gh auth - run
gh auth login.
- Build already in appcast - re-running is safe (the entry is replaced), but a new release still needs a higher build number; bump
-set-build.
- Version regression - never set
MARKETING_VERSION lower (Sparkle compares by build number, but the display string should still read forward, e.g. 0.20.1, not 0.2).
1---2name: release-screendrop3description: Release the Screendrop macOS app to GitHub using the screendrop-release CLI tool. Use this skill whenever the user wants to publish a new version, create a release, ship an update, cut a build, push a release to GitHub, or update the appcast. Also use when they mention archiving, notarization, DMG creation, Sparkle signing, bumping the version/build, or anything related to building and distributing a new Screendrop version.4---56# Release Screendrop78This skill releases new versions of Screendrop using a custom Go CLI9(`cmd/screendrop-release`). The CLI can run **fully automated and10non-interactively**, so a release can be triggered directly from a chat session11(the agent can run it end to end).1213There are two modes:1415- **Full auto (`-build`)** - archive, export (Developer ID), notarize, staple,16 package, sign, and publish. Nothing in Xcode's GUI is required.17- **Package-only** (no `-build`) - assumes the user already exported a18 notarized `~/Downloads/Screendrop.app` from Xcode, then packages & publishes.1920Prefer **full auto** unless the user says they've already exported the app.2122## Prerequisites2324Always required:25261. Tools installed: `create-dmg` (brew), `gh` (GitHub CLI, authenticated), `git`, `plutil`.272. The Sparkle `sign_update` binary in DerivedData (created when the project is28 built/archived - the `-build` flow produces it automatically).2930For **full auto (`-build`)** additionally:31323. `xcodebuild`, `xcrun`, `ditto` (all part of Xcode / command line tools).334. A **notarytool keychain profile** named `screendrop-notary` (already set up34 on this machine via an App Store Connect API key). It was created once with:35 ```bash36 xcrun notarytool store-credentials "screendrop-notary" \37 --key /path/to/AuthKey_XXXXXXXXXX.p8 --key-id XXXXXXXXXX --issuer <issuer-uuid>38 ```39 If notarization fails with a credentials error, this profile is missing or40 wrong - ask the user to re-run `store-credentials`.4142## The Release CLI4344Source: `/Users/fayazahmed/Developer/fayazara/mac/Screendrop/cmd/screendrop-release/`4546### Flags4748- `-build` - run the archive → export → notarize → staple phase first.49- `-set-version <x.y.z>` - set `MARKETING_VERSION` before archiving (and commit it). Used with `-build`.50- `-set-build <n>` - set `CURRENT_PROJECT_VERSION` before archiving (and commit it). Used with `-build`.51- `-scheme <name>` - Xcode scheme to archive (default `Screendrop`).52- `-notes "<text>"` - release notes, one bullet per line (markdown `- ` prefixes are stripped). Skips the interactive prompt.53- `-notes-file <path>` - read release notes from a file instead.54- `-notary-profile <name>` - notarytool keychain profile (default `screendrop-notary`).55- `-yes` / `-y` - assume "yes" for all confirmation prompts (non-interactive).5657### Triggering a full release from here (recommended)58591. **Decide the version and build number.** The build number60 (`CURRENT_PROJECT_VERSION`) **must increase** every release or Sparkle won't61 offer the update. Check the current values:62 ```bash63 grep -E "MARKETING_VERSION|CURRENT_PROJECT_VERSION" \64 Screendrop.xcodeproj/project.pbxproj | sort -u65 ```66 Pick the next `MARKETING_VERSION` (use real dotted semver like `0.20.2`, never67 regress - e.g. don't go `0.19` → `0.2`) and `CURRENT_PROJECT_VERSION` = current + 1.682. **Make sure code changes are committed and pushed** to `main` first, so the69 release tag points at the released source. (The CLI commits the version bump70 and pushes the appcast, but it does not push your other unrelated commits.)713. **Run it** (this is non-interactive and safe to run from a tool call):72 ```bash73 cd /Users/fayazahmed/Developer/fayazara/mac/Screendrop && \74 go run ./cmd/screendrop-release -build -yes \75 -set-version <x.y.z> -set-build <n> \76 -notes "First note77 Second note"78 ```79 Notarization blocks for a few minutes - this is expected, not a hang. Use a80 generous tool timeout (~7 min).8182### Package-only (app already exported by the user)8384```bash85cd /Users/fayazahmed/Developer/fayazara/mac/Screendrop && \86go run ./cmd/screendrop-release -yes -notes "Your notes here"87```8889### What it does (in order)9091With `-build`:921. **Set version/build** (if `-set-version`/`-set-build` given) - edits pbxproj and commits.932. **Archive** - `xcodebuild archive` (scheme `Screendrop`, Release, `generic/platform=macOS`).943. **Export** - `xcodebuild -exportArchive` with a generated Developer ID `ExportOptions.plist`.954. **Notarize** - zips the app and runs `xcrun notarytool submit --wait`, verifying `status: Accepted`.965. **Staple** - `xcrun stapler staple`, then places the app at `~/Downloads/Screendrop.app`.9798Then always:996. **Preflight checks** + **validate** the app's version/build and Sparkle keys.1007. **Collect release notes** (from `-notes`/`-notes-file`, else stdin).1018. **Create DMG** with `create-dmg` → `~/Downloads/Screendrop.dmg`.1029. **Sign DMG** with Sparkle `sign_update` (EdDSA).10310. **Push commits** - push any local commits (e.g. the version bump) to `main`.10411. **GitHub release** - `gh release create vX.Y.Z` with the DMG attached.10512. **Update + push appcast.xml** - prepend the new `<item>` (de-duping any entry for the same build), commit & push to `main`.10613. **Homebrew cask** - regenerate and push the cask to `fayazara/homebrew-tap` (non-fatal).107108**Ordering & robustness:** the release is created **before** the appcast is109pushed, so a published appcast never points at a missing release. Network110operations (`gh`, `git push`) are retried with backoff. Re-running a release is111safe: an existing GitHub release gets the DMG re-uploaded (`--clobber`) and the112appcast entry for that build is replaced rather than duplicated. The `-build`113phase also auto-points `DEVELOPER_DIR` at Xcode, so it works even when the114active developer dir is the Command Line Tools.115116### Environment / constants117118- Repo auto-detected at `~/Developer/fayazara/mac/Screendrop` (override with `SCREENDROP_REPO`).119- GitHub repo: `fayazara/screendrop` · branch: `main` · team: `TB2S44TFQS` · bundle: `com.fayazahmed.Screendrop`.120- DMG volume: `Screendrop` · minimum macOS: `26.4`.121122## Sparkle Configuration123124- **SUFeedURL**: `https://raw.githubusercontent.com/fayazara/screendrop/main/appcast.xml`125- **SUPublicEDKey**: `MA/6n0fqT0T2updDlkXr8BjhJKoHWik9uf6Lh5pUG7U=`126- **UpdaterManager.swift**: Singleton, starts at launch (Release builds only), menu bar + Settings UI integration.127128## After releasing129130Verify the release succeeded:131```bash132gh release view v<x.y.z> --repo fayazara/screendrop --json tagName,assets -q '{tag: .tagName, assets: [.assets[].name]}'133```134The CLI pushes the appcast commit itself, so run `git pull --ff-only origin main`135afterward to sync your local `main`.136137## Troubleshooting138139- **Partial failure / network error mid-release** - just re-run the exact same command. The pipeline is idempotent: an existing GitHub release gets the DMG re-uploaded, and the appcast entry for that build is replaced (not duplicated). Network calls already retry with backoff.140- **notarytool credentials error** - the `screendrop-notary` keychain profile is missing/invalid; have the user re-run `store-credentials`.141- **Notarization "Invalid"** - inspect with `xcrun notarytool log <submission-id> --keychain-profile screendrop-notary` (usually a signing/entitlements issue).142- **`xcodebuild archive` fails** - the CLI prints the last ~40 lines and auto-sets `DEVELOPER_DIR` to Xcode; if it still fails, common causes are signing or a Dev-scheme/`LSUIElement` mismatch. Confirm scheme is `Screendrop` (not `Screendrop Dev`).143- **Screendrop.app not found** (package-only mode) - the user must export from Xcode first, or use `-build`.144- **sign_update not found** - build/archive the project once so DerivedData has the Sparkle artifacts.145- **gh auth** - run `gh auth login`.146- **Build already in appcast** - re-running is safe (the entry is replaced), but a *new* release still needs a higher build number; bump `-set-build`.147- **Version regression** - never set `MARKETING_VERSION` lower (Sparkle compares by build number, but the display string should still read forward, e.g. `0.20.1`, not `0.2`).