# Release Macos Spm Packaging

> Scaffold, build, and package SwiftPM-based macOS apps without Xcode project. Use when you need a from-scratch macOS app layout, SwiftPM targets/resources, custom .app bundle assembly, or signing/notarization steps outside Xcode.

- **Type:** Skill
- **Install:** `agentstack add skill-patrickserrano-lacquer-release-macos-spm-packaging`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [patrickserrano](https://agentstack.voostack.com/s/patrickserrano)
- **Installs:** 0
- **Category:** [Agent Skills](https://agentstack.voostack.com/c/agent-skills)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [patrickserrano](https://github.com/patrickserrano)
- **Source:** https://github.com/patrickserrano/lacquer/tree/main/profiles/ios/skills/release-macos-spm-packaging
- **Website:** https://patrickserrano.github.io/lacquer/

## Install

```sh
agentstack add skill-patrickserrano-lacquer-release-macos-spm-packaging
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# macOS SwiftPM App Packaging

## Overview

Bootstrap a complete SwiftPM macOS app, then build, package, and run it without Xcode. This skill covers the full workflow from project scaffolding to release distribution.

## Project Scaffolding

### Basic Structure

```
MyApp/
├── Package.swift
├── Sources/
│   └── MyApp/
│       ├── MyApp.swift          # @main App entry
│       └── ContentView.swift
├── Resources/
│   ├── Assets.xcassets/
│   └── Info.plist
├── Scripts/
│   ├── package_app.sh
│   ├── compile_and_run.sh
│   └── sign-and-notarize.sh
└── version.env
```

### Package.swift

```swift
// swift-tools-version: 5.9
import PackageDescription

let package = Package(
    name: "MyApp",
    platforms: [.macOS(.v14)],
    products: [
        .executable(name: "MyApp", targets: ["MyApp"])
    ],
    targets: [
        .executableTarget(
            name: "MyApp",
            resources: [
                .process("Resources")
            ]
        )
    ]
)
```

### version.env

```bash
APP_NAME="MyApp"
BUNDLE_ID="com.example.myapp"
VERSION="1.0.0"
BUILD_NUMBER="1"
MIN_MACOS="14.0"
# Set to 1 for menu bar apps
MENU_BAR_APP=0
```

## Build and Run

### Build with SwiftPM

```bash
# Debug build
swift build

# Release build
swift build -c release

# Run tests
swift test
```

### Package as .app Bundle

Create `Scripts/package_app.sh`:

```bash
#!/bin/bash
set -e

source version.env

BUILD_DIR=".build/release"
APP_BUNDLE="$BUILD_DIR/$APP_NAME.app"
CONTENTS="$APP_BUNDLE/Contents"
MACOS="$CONTENTS/MacOS"
RESOURCES="$CONTENTS/Resources"

# Build release
swift build -c release

# Create bundle structure
rm -rf "$APP_BUNDLE"
mkdir -p "$MACOS" "$RESOURCES"

# Copy binary
cp "$BUILD_DIR/$APP_NAME" "$MACOS/"

# Copy resources
cp -r Resources/* "$RESOURCES/" 2>/dev/null || true

# Generate Info.plist
cat > "$CONTENTS/Info.plist" 

    CFBundleExecutable
    $APP_NAME
    CFBundleIdentifier
    $BUNDLE_ID
    CFBundleName
    $APP_NAME
    CFBundleVersion
    $BUILD_NUMBER
    CFBundleShortVersionString
    $VERSION
    LSMinimumSystemVersion
    $MIN_MACOS
    CFBundlePackageType
    APPL
$([ "$MENU_BAR_APP" = "1" ] && echo "    LSUIElement
    ")

EOF

echo "Created $APP_BUNDLE"
```

### Development Run Script

Create `Scripts/compile_and_run.sh`:

```bash
#!/bin/bash
set -e

source version.env

# Kill existing instance
pkill -x "$APP_NAME" 2>/dev/null || true

# Package
./Scripts/package_app.sh

# Launch
open ".build/release/$APP_NAME.app"
```

## Code Signing

### Development Signing

```bash
# Sign for local development
codesign --force --sign - ".build/release/MyApp.app"

# Or with a specific identity
codesign --force --sign "Developer ID Application: Your Name" ".build/release/MyApp.app"
```

### Create Stable Dev Identity

```bash
# Generate self-signed certificate for consistent dev signing
security create-keychain -p "" dev-signing.keychain
security default-keychain -s dev-signing.keychain
# Follow prompts in Keychain Access to create certificate
```

## Notarization and Release

**One-time setup.** Notarization needs the full Xcode.app, not the lightweight
Command Line Tools package — CLT omits `notarytool`/`stapler`. Store credentials
once so scripts never carry a plaintext password:

```bash
xcrun notarytool store-credentials "AC_PASSWORD" \
    --apple-id "your@email.com" \
    --team-id "TEAM_ID"
# Prompts interactively for an app-specific password (appleid.apple.com,
# Sign-In and Security -> App-Specific Passwords). Stored in the login
# keychain under the given profile name; `--keychain-profile "AC_PASSWORD"`
# below reads it back. Regenerate if the Apple ID password ever changes --
# app-specific passwords go stale silently, with no warning at submit time.
```

Create `Scripts/sign-and-notarize.sh`:

```bash
#!/bin/bash
set -e

source version.env

APP_PATH=".build/release/$APP_NAME.app"
ZIP_PATH=".build/release/$APP_NAME-$VERSION.zip"

# Sign with Developer ID
codesign --force --options runtime --sign "Developer ID Application: Your Name" "$APP_PATH"

# Create zip for notarization
ditto -c -k --keepParent "$APP_PATH" "$ZIP_PATH"

# Submit for notarization (--keychain-profile reads the credentials stored
# above by `store-credentials` -- notarytool does not take a literal
# --password value or the altool-style "@keychain:" reference syntax)
xcrun notarytool submit "$ZIP_PATH" \
    --keychain-profile "AC_PASSWORD" \
    --wait

# Staple the ticket
xcrun stapler staple "$APP_PATH"

# Re-zip with stapled ticket
rm "$ZIP_PATH"
ditto -c -k --keepParent "$APP_PATH" "$ZIP_PATH"

echo "Release ready: $ZIP_PATH"
```

### Verify the release

Run all three before shipping — each catches a different failure mode (wrong
signing identity, Gatekeeper rejection, missing/unstapled ticket):

```bash
codesign -dv --verbose=4 "$APP_PATH"      # confirms who signed it and with what identity
spctl -a -vvv -t exec "$APP_PATH"         # confirms Gatekeeper will actually accept it
xcrun stapler validate "$APP_PATH"        # confirms the notarization ticket is attached
```

## Sparkle Updates (Optional)

### Generate Appcast Entry

```bash
#!/bin/bash
source version.env

ZIP_PATH=".build/release/$APP_NAME-$VERSION.zip"
SIZE=$(stat -f%z "$ZIP_PATH")
SIGNATURE=$(./bin/sign_update "$ZIP_PATH")
DATE=$(date -R)

cat 
    Version $VERSION
    $DATE
    $BUILD_NUMBER
    $VERSION
    

EOF
```

## GitHub Release

```bash
# Create tag
git tag -a "v$VERSION" -m "Release $VERSION"
git push origin "v$VERSION"

# Create GitHub release
gh release create "v$VERSION" \
    ".build/release/$APP_NAME-$VERSION.zip" \
    --title "v$VERSION" \
    --notes "Release notes here"
```

## Checklist

### Scaffolding
- [ ] Package.swift with correct targets and resources
- [ ] version.env with app metadata
- [ ] Info.plist template or generation script
- [ ] Basic app entry point (@main App)

### Build
- [ ] `swift build` succeeds
- [ ] `swift test` passes
- [ ] Resources copied correctly

### Packaging
- [ ] .app bundle structure correct
- [ ] Info.plist generated with correct values
- [ ] App launches from Finder

### Release
- [ ] Code signed with Developer ID
- [ ] Notarized and stapled
- [ ] Verified with `codesign -dv`, `spctl -a -vvv -t exec`, and `stapler validate`
- [ ] Zip created for distribution
- [ ] (Optional) Sparkle appcast updated

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [patrickserrano](https://github.com/patrickserrano)
- **Source:** [patrickserrano/lacquer](https://github.com/patrickserrano/lacquer)
- **License:** MIT
- **Homepage:** https://patrickserrano.github.io/lacquer/

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** yes
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-patrickserrano-lacquer-release-macos-spm-packaging
- Seller: https://agentstack.voostack.com/s/patrickserrano
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
