diff --git a/ios-spm-app-packaging/SKILL.md b/ios-spm-app-packaging/SKILL.md
new file mode 100644
index 0000000..fc4b44d
--- /dev/null
+++ b/ios-spm-app-packaging/SKILL.md
@@ -0,0 +1,58 @@
+---
+name: ios-spm-app-packaging
+description: Scaffold, build, and package SwiftPM-based iOS apps using Tuist. Use when you need a from-scratch iOS app layout, SwiftPM dependencies, automated project generation, or signing/archiving/distribution steps outside manual Xcode project management.
+---
+
+# iOS SwiftPM App Packaging (Tuist)
+
+## Overview
+
+Bootstrap a SwiftPM-based iOS app using Tuist to generate the Xcode project. Build, archive, and distribute without manually managing xcodeproj files. Tuist uses Swift-based manifests for type-safe configuration with IDE autocomplete.
+
+## Two-Step Workflow
+
+1) Bootstrap the project folder
+ - Copy `assets/templates/bootstrap/` into a new repo.
+ - Rename `MyApp` in `Package.swift`, `Sources/MyApp/`, and `Project.swift`.
+ - Customize `APP_NAME`, `BUNDLE_ID`, and versions in `Project.swift`.
+
+2) Build, archive, and distribute
+ - Install Tuist: `brew install --cask tuist`.
+ - Generate project: `tuist generate`.
+ - Build: `tuist xcodebuild build -scheme MyApp -sdk iphonesimulator`.
+ - Archive: `Scripts/archive.sh`.
+ - Export IPA: `Scripts/export_ipa.sh`.
+ - Upload to TestFlight: `Scripts/upload_testflight.sh`.
+
+## Templates
+
+- `assets/templates/bootstrap/`: Minimal SwiftPM iOS app skeleton with CI configuration, Gemfile, and SwiftLint config.
+- `assets/templates/archive.sh`: Create a release archive (supports `SKIP_SIGNING=1`).
+- `assets/templates/export_ipa.sh`: Export IPA from archive for distribution.
+- `assets/templates/upload_testflight.sh`: Upload IPA to App Store Connect.
+- `assets/templates/release.sh`: Complete release workflow (version bump, build, GitHub release, TestFlight).
+- `assets/templates/ExportOptions.plist`: Export options for app-store or ad-hoc distribution.
+- `assets/templates/fastlane/`: Fastfile and Appfile for optional Fastlane automation.
+
+## Notes
+
+- Tuist regenerates the xcodeproj from `Project.swift`; never edit xcodeproj manually.
+- Add `*.xcodeproj` to `.gitignore` since it's generated.
+- Provisioning requires Apple Developer account and certificates configured in Keychain.
+- For CI without signing, use `SKIP_SIGNING=1 Scripts/archive.sh`.
+- Optional: Use `tuist cache warm` for faster builds via caching.
+
+## Signing
+
+Tuist defines build settings but doesn't manage certificates. Options:
+- **Manual**: Download certificates/profiles from Apple Developer portal.
+- **Automatic**: Let Xcode manage signing (local dev only).
+- **Fastlane match**: Automated certificate management via git repo (recommended for teams/CI).
+
+## Reference material
+
+- See `references/scaffold.md` for project setup details.
+- See `references/packaging.md` for build and archive configuration.
+- See `references/release.md` for TestFlight and App Store distribution.
+- See `references/fastlane.md` for optional Fastlane automation and `match` signing.
+- See `references/swiftlint.md` for code style enforcement and linting integration.
diff --git a/ios-spm-app-packaging/assets/templates/ExportOptions.plist b/ios-spm-app-packaging/assets/templates/ExportOptions.plist
new file mode 100644
index 0000000..5f077e5
--- /dev/null
+++ b/ios-spm-app-packaging/assets/templates/ExportOptions.plist
@@ -0,0 +1,10 @@
+
+
+
+
+ method
+ app-store-connect
+ destination
+ upload
+
+
diff --git a/ios-spm-app-packaging/assets/templates/archive.sh b/ios-spm-app-packaging/assets/templates/archive.sh
new file mode 100644
index 0000000..56370ae
--- /dev/null
+++ b/ios-spm-app-packaging/assets/templates/archive.sh
@@ -0,0 +1,43 @@
+#!/bin/bash
+set -euo pipefail
+
+# Archive iOS app for distribution
+# Usage: ./archive.sh
+#
+# Environment variables:
+# SKIP_SIGNING=1 - Use CI configuration (no code signing)
+# APP_NAME - App name (default: MyApp)
+# SCHEME - Xcode scheme (default: APP_NAME or APP_NAME-CI if SKIP_SIGNING)
+# CONFIGURATION - Build configuration (default: Release or CI if SKIP_SIGNING)
+# BUILD_DIR - Output directory (default: build)
+
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
+
+cd "$PROJECT_DIR"
+
+APP_NAME="${APP_NAME:-MyApp}"
+BUILD_DIR="${BUILD_DIR:-build}"
+
+# Use CI config/scheme when SKIP_SIGNING is set
+if [ "${SKIP_SIGNING:-0}" = "1" ]; then
+ CONFIGURATION="${CONFIGURATION:-CI}"
+ SCHEME="${SCHEME:-$APP_NAME-CI}"
+ echo "Running in CI mode (no code signing)..."
+else
+ CONFIGURATION="${CONFIGURATION:-Release}"
+ SCHEME="${SCHEME:-$APP_NAME}"
+fi
+
+echo "Regenerating Xcode project..."
+tuist generate
+
+echo "Archiving $APP_NAME (scheme: $SCHEME, config: $CONFIGURATION)..."
+tuist xcodebuild archive \
+ -scheme "$SCHEME" \
+ -sdk iphoneos \
+ -configuration "$CONFIGURATION" \
+ -archivePath "$BUILD_DIR/$APP_NAME.xcarchive" \
+ -allowProvisioningUpdates
+
+echo "Archive created: $BUILD_DIR/$APP_NAME.xcarchive"
diff --git a/ios-spm-app-packaging/assets/templates/bootstrap/.gitignore b/ios-spm-app-packaging/assets/templates/bootstrap/.gitignore
new file mode 100644
index 0000000..9247da3
--- /dev/null
+++ b/ios-spm-app-packaging/assets/templates/bootstrap/.gitignore
@@ -0,0 +1,25 @@
+# Xcode (generated by Tuist)
+*.xcodeproj
+*.xcworkspace
+xcuserdata/
+DerivedData/
+*.xcscmblueprint
+
+# Tuist
+.tuist-derived/
+Derived/
+
+# Build
+build/
+.build/
+
+# Swift Package Manager
+.swiftpm/
+Package.resolved
+
+# macOS
+.DS_Store
+
+# Archives
+*.xcarchive
+*.ipa
diff --git a/ios-spm-app-packaging/assets/templates/bootstrap/Package.swift b/ios-spm-app-packaging/assets/templates/bootstrap/Package.swift
new file mode 100644
index 0000000..7697d93
--- /dev/null
+++ b/ios-spm-app-packaging/assets/templates/bootstrap/Package.swift
@@ -0,0 +1,17 @@
+// swift-tools-version: 6.0
+import PackageDescription
+
+let package = Package(
+ name: "MyApp",
+ platforms: [.iOS(.v17)],
+ products: [
+ .library(name: "MyApp", targets: ["MyApp"])
+ ],
+ targets: [
+ .target(
+ name: "MyApp",
+ path: "Sources/MyApp",
+ resources: [.process("Resources")]
+ )
+ ]
+)
diff --git a/ios-spm-app-packaging/assets/templates/bootstrap/Project.swift b/ios-spm-app-packaging/assets/templates/bootstrap/Project.swift
new file mode 100644
index 0000000..b53c4a3
--- /dev/null
+++ b/ios-spm-app-packaging/assets/templates/bootstrap/Project.swift
@@ -0,0 +1,54 @@
+import ProjectDescription
+
+let project = Project(
+ name: "MyApp",
+ targets: [
+ .target(
+ name: "MyApp",
+ destinations: .iOS,
+ product: .app,
+ bundleId: "com.example.myapp",
+ deploymentTargets: .iOS("17.0"),
+ infoPlist: .extendingDefault(with: [
+ "UILaunchScreen": [:],
+ "UISupportedInterfaceOrientations": ["UIInterfaceOrientationPortrait"]
+ ]),
+ sources: ["Sources/MyApp/**"],
+ resources: ["Sources/MyApp/Resources/**"],
+ settings: .settings(
+ base: [
+ "MARKETING_VERSION": "1.0.0",
+ "CURRENT_PROJECT_VERSION": "1",
+ "SWIFT_VERSION": "6.0"
+ ],
+ configurations: [
+ .debug(name: "Debug", settings: [
+ "CODE_SIGN_IDENTITY": "Apple Development"
+ ]),
+ .release(name: "Release", settings: [
+ "CODE_SIGN_IDENTITY": "Apple Distribution"
+ ]),
+ .release(name: "CI", settings: [
+ "CODE_SIGNING_REQUIRED": "NO",
+ "CODE_SIGNING_ALLOWED": "NO",
+ "CODE_SIGN_IDENTITY": ""
+ ])
+ ]
+ )
+ )
+ ],
+ schemes: [
+ .scheme(
+ name: "MyApp",
+ buildAction: .buildAction(targets: ["MyApp"]),
+ runAction: .runAction(configuration: "Debug"),
+ archiveAction: .archiveAction(configuration: "Release")
+ ),
+ .scheme(
+ name: "MyApp-CI",
+ buildAction: .buildAction(targets: ["MyApp"]),
+ runAction: .runAction(configuration: "Debug"),
+ archiveAction: .archiveAction(configuration: "CI")
+ )
+ ]
+)
diff --git a/ios-spm-app-packaging/assets/templates/bootstrap/Sources/MyApp/MyApp.swift b/ios-spm-app-packaging/assets/templates/bootstrap/Sources/MyApp/MyApp.swift
new file mode 100644
index 0000000..fedfecf
--- /dev/null
+++ b/ios-spm-app-packaging/assets/templates/bootstrap/Sources/MyApp/MyApp.swift
@@ -0,0 +1,22 @@
+import SwiftUI
+
+@main
+struct MyApp: App {
+ var body: some Scene {
+ WindowGroup {
+ ContentView()
+ }
+ }
+}
+
+struct ContentView: View {
+ var body: some View {
+ VStack {
+ Image(systemName: "globe")
+ .imageScale(.large)
+ .foregroundStyle(.tint)
+ Text("Hello, world!")
+ }
+ .padding()
+ }
+}
diff --git a/ios-spm-app-packaging/assets/templates/bootstrap/Sources/MyApp/Resources/.keep b/ios-spm-app-packaging/assets/templates/bootstrap/Sources/MyApp/Resources/.keep
new file mode 100644
index 0000000..e69de29
diff --git a/ios-spm-app-packaging/assets/templates/export_ipa.sh b/ios-spm-app-packaging/assets/templates/export_ipa.sh
new file mode 100644
index 0000000..27c1531
--- /dev/null
+++ b/ios-spm-app-packaging/assets/templates/export_ipa.sh
@@ -0,0 +1,39 @@
+#!/bin/bash
+set -euo pipefail
+
+# Export IPA from archive
+# Usage: ./export_ipa.sh
+
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
+
+cd "$PROJECT_DIR"
+
+APP_NAME="${APP_NAME:-MyApp}"
+BUILD_DIR="${BUILD_DIR:-build}"
+EXPORT_OPTIONS="${EXPORT_OPTIONS:-ExportOptions.plist}"
+
+if [ ! -f "$EXPORT_OPTIONS" ]; then
+ echo "Creating default ExportOptions.plist for App Store..."
+ cat > "$EXPORT_OPTIONS" << 'EOF'
+
+
+
+
+ method
+ app-store-connect
+ destination
+ upload
+
+
+EOF
+fi
+
+echo "Exporting IPA..."
+xcodebuild -exportArchive \
+ -archivePath "$BUILD_DIR/$APP_NAME.xcarchive" \
+ -exportPath "$BUILD_DIR/export" \
+ -exportOptionsPlist "$EXPORT_OPTIONS" \
+ -allowProvisioningUpdates
+
+echo "IPA exported to: $BUILD_DIR/export/"
diff --git a/ios-spm-app-packaging/references/packaging.md b/ios-spm-app-packaging/references/packaging.md
new file mode 100644
index 0000000..fd441e5
--- /dev/null
+++ b/ios-spm-app-packaging/references/packaging.md
@@ -0,0 +1,110 @@
+# Packaging notes
+
+## Build commands
+
+Generate project with Tuist:
+```bash
+tuist generate
+```
+
+Build with tuist xcodebuild wrapper:
+```bash
+# Simulator build
+tuist xcodebuild build -scheme MyApp -sdk iphonesimulator -configuration Debug
+
+# Device build (requires signing)
+tuist xcodebuild build -scheme MyApp -sdk iphoneos -configuration Release
+```
+
+## Archive for distribution
+
+```bash
+tuist generate
+tuist xcodebuild archive \
+ -scheme MyApp \
+ -sdk iphoneos \
+ -configuration Release \
+ -archivePath build/MyApp.xcarchive
+```
+
+## Export IPA
+
+Create `ExportOptions.plist`:
+```xml
+
+
+
+
+ method
+ app-store-connect
+ destination
+ upload
+
+
+```
+
+Export:
+```bash
+xcodebuild -exportArchive \
+ -archivePath build/MyApp.xcarchive \
+ -exportPath build/export \
+ -exportOptionsPlist ExportOptions.plist
+```
+
+## Common environment variables
+
+- `APP_NAME`: App/target name.
+- `BUNDLE_ID`: Bundle identifier.
+- `TEAM_ID`: Apple Developer Team ID.
+- `SCHEME`: Xcode scheme name.
+- `CONFIGURATION`: `Debug`, `Release`, or `CI`.
+- `SKIP_SIGNING`: Set to `1` to use CI configuration (no code signing).
+
+## Signing modes
+
+| Method | Use Case |
+|--------|----------|
+| Automatic | Local dev with Xcode managing profiles |
+| Manual | CI with exported provisioning profiles |
+| Ad-hoc | Internal testing outside TestFlight |
+| App Store | TestFlight and App Store distribution |
+
+## CI / no-signing environments
+
+Archive commands fail without valid signing certificates. The project includes a `CI` configuration and `MyApp-CI` scheme for testing the archive pipeline without signing.
+
+**Why archive fails without certs:**
+- `xcodebuild archive` requires code signing even for test builds
+- CI environments often lack provisioning profiles
+
+**Use the CI configuration:**
+```bash
+# Archive without signing (uses CI config)
+SKIP_SIGNING=1 Scripts/archive.sh
+
+# Or manually:
+tuist xcodebuild archive \
+ -scheme MyApp-CI \
+ -sdk iphoneos \
+ -configuration CI \
+ -archivePath build/MyApp.xcarchive
+```
+
+**For real distribution** (requires Apple Developer account):
+```bash
+tuist generate
+tuist xcodebuild archive \
+ -scheme MyApp \
+ -sdk iphoneos \
+ -configuration Release \
+ -allowProvisioningUpdates
+```
+
+## Tuist caching (optional)
+
+Speed up builds by caching dependencies:
+```bash
+tuist cache warm
+tuist generate
+tuist xcodebuild build
+```
diff --git a/ios-spm-app-packaging/references/scaffold.md b/ios-spm-app-packaging/references/scaffold.md
new file mode 100644
index 0000000..b05bd47
--- /dev/null
+++ b/ios-spm-app-packaging/references/scaffold.md
@@ -0,0 +1,130 @@
+# Scaffold a SwiftPM iOS app (Tuist)
+
+## Steps
+
+1) Create a repo and initialize SwiftPM:
+```
+mkdir MyApp
+cd MyApp
+swift package init --type library
+```
+
+2) Create `Project.swift` for Tuist (see template below).
+
+3) Create the app entry point under `Sources/MyApp/`.
+ - Use SwiftUI with `@main` App struct.
+
+4) Add resources directory:
+```
+mkdir -p Sources/MyApp/Resources
+```
+
+5) Install Tuist and generate project:
+```
+brew install --cask tuist
+tuist generate
+open MyApp.xcodeproj
+```
+
+6) Add generated files to `.gitignore`:
+```
+echo "*.xcodeproj" >> .gitignore
+echo ".tuist-derived/" >> .gitignore
+```
+
+## Minimal Package.swift
+
+```swift
+// swift-tools-version: 6.0
+import PackageDescription
+
+let package = Package(
+ name: "MyApp",
+ platforms: [.iOS(.v17)],
+ products: [
+ .library(name: "MyApp", targets: ["MyApp"])
+ ],
+ targets: [
+ .target(
+ name: "MyApp",
+ path: "Sources/MyApp",
+ resources: [.process("Resources")]
+ )
+ ]
+)
+```
+
+## Minimal Project.swift (Tuist)
+
+```swift
+import ProjectDescription
+
+let project = Project(
+ name: "MyApp",
+ targets: [
+ .target(
+ name: "MyApp",
+ destinations: .iOS,
+ product: .app,
+ bundleId: "com.example.myapp",
+ deploymentTargets: .iOS("17.0"),
+ infoPlist: .extendingDefault(with: [
+ "UILaunchScreen": [:]
+ ]),
+ sources: ["Sources/MyApp/**"],
+ resources: ["Sources/MyApp/Resources/**"],
+ settings: .settings(base: [
+ "MARKETING_VERSION": "1.0.0",
+ "CURRENT_PROJECT_VERSION": "1",
+ "SWIFT_VERSION": "6.0"
+ ])
+ )
+ ]
+)
+```
+
+## Minimal SwiftUI entry point
+
+```swift
+import SwiftUI
+
+@main
+struct MyApp: App {
+ var body: some Scene {
+ WindowGroup {
+ ContentView()
+ }
+ }
+}
+
+struct ContentView: View {
+ var body: some View {
+ Text("Hello")
+ }
+}
+```
+
+## Adding SPM dependencies
+
+In `Project.swift`, add packages and dependencies:
+
+```swift
+let project = Project(
+ name: "MyApp",
+ packages: [
+ .remote(url: "https://github.com/Alamofire/Alamofire", requirement: .upToNextMajor(from: "5.0.0"))
+ ],
+ targets: [
+ .target(
+ name: "MyApp",
+ destinations: .iOS,
+ product: .app,
+ bundleId: "com.example.myapp",
+ sources: ["Sources/MyApp/**"],
+ dependencies: [
+ .package(product: "Alamofire")
+ ]
+ )
+ ]
+)
+```