Imported from sickn33/agentic-awesome-skills (
skills/macos-spm-app-packaging/SKILL.md). Install upstream withnpx skills add sickn33/agentic-awesome-skills --skill macos-spm-app-packaging. Copyright stays with the author.
macOS SwiftPM App Packaging (No Xcode)
Overview
Bootstrap a complete SwiftPM macOS app folder, then build, package, and run it without Xcode. Use assets/templates/bootstrap/ for the starter layout and references/packaging.md + references/release.md for packaging and release details.
When to Use
- When the user needs a SwiftPM-based macOS app without relying on an Xcode project.
- When you need packaging, signing, notarization, or appcast guidance for a SwiftPM app.
Two-Step Workflow
The templates mutate build folders, launch/terminate apps, access the keychain and may upload signed archives to Apple; release/tag publication is separate authorization. Scripts are tracked as regular non-executable templates: inspect/copy only to an approved new project and set executable bits there. Pin the required Swift/Xcode tools; “without Xcode projects” does not mean every optional tool works without Xcode. Universal main binaries do not prove embedded frameworks contain both architectures; verify all code/resources and entitlements. A process being alive is not a functional app test. Never use broad process-name matching against unrelated applications.
AAS review 2026-10-23: script and example corrections are local adaptations; original source attribution is retained.
-
Bootstrap the project folder
- Copy
assets/templates/bootstrap/into a new repo. - Rename
MyAppinPackage.swift,Sources/MyApp/, andversion.env. - Customize
APP_NAME,BUNDLE_ID, and versions.
- Copy
-
Build, package, and run the bootstrapped app
- Copy scripts from
assets/templates/into your repo (for example,Scripts/). - Build/tests:
swift buildandswift test. - Package:
Scripts/package_app.sh. - Run:
Scripts/compile_and_run.sh(preferred) orScripts/launch.sh. - Release (optional):
Scripts/sign-and-notarize.shandScripts/make_appcast.sh. - Tag + GitHub release (optional): create a git tag, upload the zip/appcast to the GitHub release, and publish.
- Copy scripts from
Minimum End-to-End Example
Shortest path from bootstrap to a running app:
# 1. Copy and rename the skeleton
SKILL_ROOT=/absolute/path/to/this/skill
cp -R "$SKILL_ROOT/assets/templates/bootstrap/" ~/Projects/MyApp
cd ~/Projects/MyApp
sed -i '' 's/MyApp/HelloApp/g' Package.swift
mv Sources/MyApp Sources/HelloApp
export APP_NAME=HelloApp BUNDLE_ID=com.example.helloapp
# 2. Copy scripts
mkdir -p Scripts
cp "$SKILL_ROOT/assets/templates/"*.sh Scripts/
chmod +x Scripts/*.sh
# 3. Build and launch
swift build
Scripts/compile_and_run.sh
Validation Checkpoints
Run these after key steps to catch failures early before proceeding to the next stage.
After packaging (Scripts/package_app.sh):
# Confirm .app bundle structure is intact
ls -R HelloApp.app/Contents
# Check that the binary is present and executable
file HelloApp.app/Contents/MacOS/HelloApp
After signing (Scripts/sign-and-notarize.sh or ad-hoc dev signing):
# Inspect signature and entitlements
codesign -dv --verbose=4 HelloApp.app
# Verify the bundle passes Gatekeeper checks locally
spctl --assess --type execute --verbose HelloApp.app
After notarization and stapling:
# Confirm the staple ticket is attached
stapler validate HelloApp.app
# Re-run Gatekeeper to confirm notarization is recognised
spctl --assess --type execute --verbose HelloApp.app
Common Notarization Failures
| Symptom | Likely Cause | Recovery |
|---|---|---|
The software asset has already been uploaded |
Duplicate submission for same version | Bump BUILD_NUMBER in version.env and repackage. |
Package Invalid: Invalid Code Signing Entitlements |
Entitlements in .entitlements file don't match provisioning |
Audit entitlements against Apple's allowed set; remove unsupported keys. |
The executable does not have the hardened runtime enabled |
Missing --options runtime flag in codesign invocation |
Edit sign-and-notarize.sh to add --options runtime to all codesign calls. |
| Notarization hangs / no status email | xcrun notarytool network or credential issue |
Run xcrun notarytool history to check status; re-export App Store Connect API key if expired. |
stapler validate fails after successful notarization |
Ticket not yet propagated | Wait ~60 s, then re-run xcrun stapler staple. |
Templates
assets/templates/package_app.sh: Build binaries, create the .app bundle, copy resources, sign.assets/templates/compile_and_run.sh: Dev loop to kill running app, package, launch.assets/templates/build_icon.sh: Generate .icns from an Icon Composer file (requires Xcode install).assets/templates/sign-and-notarize.sh: Notarize, staple, and zip a release build.assets/templates/make_appcast.sh: Generate Sparkle appcast entries for updates.assets/templates/setup_dev_signing.sh: Create a stable dev code-signing identity.assets/templates/launch.sh: Simple launcher for a packaged .app.assets/templates/version.env: Example version file consumed by packaging scripts.assets/templates/bootstrap/: Minimal SwiftPM macOS app skeleton (Package.swift, Sources/, version.env).
Notes
- Keep entitlements and signing configuration explicit; edit the template scripts instead of reimplementing.
- Remove Sparkle steps if you do not use Sparkle for updates.
- Sparkle relies on the bundle build number (
CFBundleVersion), soBUILD_NUMBERinversion.envmust increase for each update. - For menu bar apps, set
MENU_BAR_APP=1when packaging to emitLSUIElementin Info.plist.
Limitations
- Use this skill only when the task clearly matches the scope described above.
- Do not treat the output as a substitute for environment-specific validation, testing, or expert review.
- Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.
