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
Bootstrap the project folder
- Copy
assets/templates/bootstrap/ into a new repo.
- Rename
MyApp in Package.swift, Sources/MyApp/, and version.env.
- Customize
APP_NAME, BUNDLE_ID, and versions.
Build, package, and run the bootstrapped app
- Copy scripts from
assets/templates/ into your repo (for example, Scripts/).
- Build/tests:
swift build and swift test.
- Package:
Scripts/package_app.sh.
- Run:
Scripts/compile_and_run.sh (preferred) or Scripts/launch.sh.
- Release (optional):
Scripts/sign-and-notarize.sh and Scripts/make_appcast.sh.
- Tag + GitHub release (optional): create a git tag, upload the zip/appcast to the GitHub release, and publish.
Minimum End-to-End Example
Shortest path from bootstrap to a running app:
# 1. Copy and rename the skeleton
cp -R assets/templates/bootstrap/ ~/Projects/MyApp
cd ~/Projects/MyApp
sed -i '' 's/MyApp/HelloApp/g' Package.swift version.env
# 2. Copy scripts
cp assets/templates/package_app.sh Scripts/
cp assets/templates/compile_and_run.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 build/HelloApp.app/Contents
# Check that the binary is present and executable
file build/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 build/HelloApp.app
# Verify the bundle passes Gatekeeper checks locally
spctl --assess --type execute --verbose build/HelloApp.app
After notarization and stapling:
# Confirm the staple ticket is attached
stapler validate build/HelloApp.app
# Re-run Gatekeeper to confirm notarization is recognised
spctl --assess --type execute --verbose build/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), so BUILD_NUMBER in version.env must increase for each update.
- For menu bar apps, set
MENU_BAR_APP=1 when packaging to emit LSUIElement in 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.
1---2name: macos-spm-app-packaging3description: Scaffold, build, sign, and package SwiftPM macOS apps without Xcode projects.4---5
6# macOS SwiftPM App Packaging (No Xcode)
7
8## Overview
9Bootstrap 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.
10
11## When to Use
12- When the user needs a SwiftPM-based macOS app without relying on an Xcode project.
13- When you need packaging, signing, notarization, or appcast guidance for a SwiftPM app.
14
15## Two-Step Workflow
161) Bootstrap the project folder
17 - Copy `assets/templates/bootstrap/` into a new repo.
18 - Rename `MyApp` in `Package.swift`, `Sources/MyApp/`, and `version.env`.
19 - Customize `APP_NAME`, `BUNDLE_ID`, and versions.
20
212) Build, package, and run the bootstrapped app
22 - Copy scripts from `assets/templates/` into your repo (for example, `Scripts/`).
23 - Build/tests: `swift build` and `swift test`.
24 - Package: `Scripts/package_app.sh`.
25 - Run: `Scripts/compile_and_run.sh` (preferred) or `Scripts/launch.sh`.
26 - Release (optional): `Scripts/sign-and-notarize.sh` and `Scripts/make_appcast.sh`.
27 - Tag + GitHub release (optional): create a git tag, upload the zip/appcast to the GitHub release, and publish.
28
29## Minimum End-to-End Example
30Shortest path from bootstrap to a running app:
31```bash
32# 1. Copy and rename the skeleton
33cp -R assets/templates/bootstrap/ ~/Projects/MyApp
34cd ~/Projects/MyApp
35sed -i '' 's/MyApp/HelloApp/g' Package.swift version.env
36
37# 2. Copy scripts
38cp assets/templates/package_app.sh Scripts/
39cp assets/templates/compile_and_run.sh Scripts/
40chmod +x Scripts/*.sh
41
42# 3. Build and launch
43swift build
44Scripts/compile_and_run.sh
45```
46
47## Validation Checkpoints
48Run these after key steps to catch failures early before proceeding to the next stage.
49
50**After packaging (`Scripts/package_app.sh`):**
51```bash
52# Confirm .app bundle structure is intact
53ls -R build/HelloApp.app/Contents
54
55# Check that the binary is present and executable
56file build/HelloApp.app/Contents/MacOS/HelloApp
57```
58
59**After signing (`Scripts/sign-and-notarize.sh` or ad-hoc dev signing):**
60```bash
61# Inspect signature and entitlements
62codesign -dv --verbose=4 build/HelloApp.app
63
64# Verify the bundle passes Gatekeeper checks locally
65spctl --assess --type execute --verbose build/HelloApp.app
66```
67
68**After notarization and stapling:**
69```bash
70# Confirm the staple ticket is attached
71stapler validate build/HelloApp.app
72
73# Re-run Gatekeeper to confirm notarization is recognised
74spctl --assess --type execute --verbose build/HelloApp.app
75```
76
77## Common Notarization Failures
78| Symptom | Likely Cause | Recovery |
79|---|---|---|
80| `The software asset has already been uploaded` | Duplicate submission for same version | Bump `BUILD_NUMBER` in `version.env` and repackage. |
81| `Package Invalid: Invalid Code Signing Entitlements` | Entitlements in `.entitlements` file don't match provisioning | Audit entitlements against Apple's allowed set; remove unsupported keys. |
82| `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. |
83| 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. |
84| `stapler validate` fails after successful notarization | Ticket not yet propagated | Wait ~60 s, then re-run `xcrun stapler staple`. |
85
86## Templates
87- `assets/templates/package_app.sh`: Build binaries, create the .app bundle, copy resources, sign.
88- `assets/templates/compile_and_run.sh`: Dev loop to kill running app, package, launch.
89- `assets/templates/build_icon.sh`: Generate .icns from an Icon Composer file (requires Xcode install).
90- `assets/templates/sign-and-notarize.sh`: Notarize, staple, and zip a release build.
91- `assets/templates/make_appcast.sh`: Generate Sparkle appcast entries for updates.
92- `assets/templates/setup_dev_signing.sh`: Create a stable dev code-signing identity.
93- `assets/templates/launch.sh`: Simple launcher for a packaged .app.
94- `assets/templates/version.env`: Example version file consumed by packaging scripts.
95- `assets/templates/bootstrap/`: Minimal SwiftPM macOS app skeleton (Package.swift, Sources/, version.env).
96
97## Notes
98- Keep entitlements and signing configuration explicit; edit the template scripts instead of reimplementing.
99- Remove Sparkle steps if you do not use Sparkle for updates.
100- Sparkle relies on the bundle build number (`CFBundleVersion`), so `BUILD_NUMBER` in `version.env` must increase for each update.
101- For menu bar apps, set `MENU_BAR_APP=1` when packaging to emit `LSUIElement` in Info.plist.
102
103## Limitations
104- Use this skill only when the task clearly matches the scope described above.
105- Do not treat the output as a substitute for environment-specific validation, testing, or expert review.
106- Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.