| name | release-macos |
| description | Archive, notarize, and release a macOS app — creates GitHub release, uploads zip, updates Homebrew cask. |
| user-invocable | true |
| disable-model-invocation | true |
| argument-hint | <version> |
Run the full macOS app release pipeline for the current project. This skill handles archive, export, notarization, GitHub release, and Homebrew cask update.
Prerequisites
The project must have:
- An Xcode project (
.xcodeproj) with a scheme matching the app name
- A
config/exportOptions.plist for Developer ID signing
- A notarytool keychain profile named
notarytool (xcrun notarytool store-credentials)
gh CLI authenticated for GitHub releases
- A Homebrew tap repo at
../tap/Casks/<app-name>.rb (for cask update)
Steps
Given the version argument $VERSION:
-
Detect project settings — find the .xcodeproj, scheme name, and app name from the working directory. Look at the justfile, project.yml, or xcodeproj for these values.
-
Archive the app:
xcodebuild \
-project $PROJECT \
-scheme $SCHEME \
-configuration Release \
-archivePath build/archive/$APP_NAME-$VERSION.xcarchive \
archive 2>&1 | xcbeautify
- Export the signed .app from the archive:
xcodebuild -exportArchive \
-archivePath build/archive/$APP_NAME-$VERSION.xcarchive \
-exportPath build/export/$APP_NAME-$VERSION \
-exportOptionsPlist config/exportOptions.plist 2>&1 | xcbeautify
- Notarize the app:
temp_zip=$(mktemp -d)/$APP_NAME.zip
ditto -c -k --sequesterRsrc --keepParent "build/export/$APP_NAME-$VERSION/$APP_NAME.app" "$temp_zip"
xcrun notarytool submit "$temp_zip" --keychain-profile "notarytool" --wait
xcrun stapler staple "build/export/$APP_NAME-$VERSION/$APP_NAME.app"
rm -f "$temp_zip"
- Create dist zip (after stapling):
mkdir -p build/dist
ditto -c -k --sequesterRsrc --keepParent "build/export/$APP_NAME-$VERSION/$APP_NAME.app" "build/dist/$APP_NAME-$VERSION.zip"
- Create GitHub release (draft):
gh release create $VERSION --draft --title "$VERSION" --notes "Release $VERSION"
Skip if release already exists.
- Upload the zip to the release:
gh release upload $VERSION "build/dist/$APP_NAME-$VERSION.zip" --clobber
- Update Homebrew cask (if
../tap/Casks/ exists):
sha256=$(shasum -a 256 "build/dist/$APP_NAME-$VERSION.zip" | cut -d' ' -f1)
cask_file=$(find ../tap/Casks -name "*.rb" | head -1)
sed -i '' -e "s/version \"[^\"]*\"/version \"$VERSION\"/" -e "s/sha256 \"[^\"]*\"/sha256 \"$sha256\"/" "$cask_file"
Important
- Always confirm with the user before starting (this uploads to GitHub and modifies external repos)
- Run each step sequentially — each depends on the previous
- If notarization fails, do NOT proceed to zip/upload
- Show the user the SHA256 and draft release URL when done