MCPInstall

cocoapods-to-spm

Migrates an existing Capacitor iOS app from CocoaPods to Swift Package Manager (SPM) before CocoaPods Trunk goes read-only (expected December 2, 2026). Use when the app still has ios/App/Podfile, Pods/, Podfile.lock or App.xcworkspace and the user wants CapApp-SPM, runs or recovers from npx cap spm-migration-assistant, needs debug.xcconfig / CAPACITORDEBUG wired up, sees "Some installed Capacitor plugins are not compatible with SPM" or " does not have a Package.swift", or plans the Capacitor 9 upgrade where SPM is the default. Do not use for adding SPM support inside a plugin repository (use capacitor-plugin-spm-support), the UIScene lifecycle migration (use capacitor-uiscene-migration), full version upgrades (use capacitor-app-upgrades), or generic iOS build debugging (use debugging-capacitor).

Installs
797
Last 24h
—
Trending rank
—
Security
Not audited

Install

Works with every agent the skills CLI supports.

npx skills add https://github.com/cap-go/capgo-skills --skill cocoapods-to-spm
  1. 01

    Install

    Run the command in your project. The CLI asks which agents to install for.

  2. 02

    Describe the task

    Ask your agent for something this skill covers. It loads cocoapods-to-spm automatically when relevant.

  3. 03

    Review the result

    The agent follows the SKILL.md steps, scripts and references bundled with the skill.

SKILL.md

The instructions your agent reads when the skill is triggered.

CocoaPods to Swift Package Manager Migration

Move a Capacitor iOS app from CocoaPods to SPM without losing native project customizations.

When to Use

TRIGGER when:

  • ios/App/Podfile, Pods/, Podfile.lock, or App.xcworkspace exists and the user wants SPM.
  • User asks about npx cap spm-migration-assistant, CapApp-SPM, debug.xcconfig, or --packagemanager SPM.
  • User worries about CocoaPods Trunk becoming read-only (expected December 2, 2026), or about pods that can no longer be published/updated.
  • npx cap sync warns Some installed Capacitor plugins are not compatible with SPM or <plugin id> does not have a Package.swift.
  • Upgrading to Capacitor 9 and wanting to drop CocoaPods at the same time.

Do not use:

  • Adding Package.swift / CAPBridgedPlugin to a plugin you maintain -> capacitor-plugin-spm-support.
  • SceneDelegate / UIScene adoption (Capacitor 8.5+, required by Xcode 27) -> capacitor-uiscene-migration.
  • The Capacitor major upgrade itself -> capacitor-app-upgrades, capacitor-app-upgrade-v8-to-v9.
  • Build or runtime failures unrelated to dependency management -> debugging-capacitor.

Why Now

  • CocoaPods Trunk is expected to become read-only on December 2, 2026. Existing pods keep resolving, but no new pod versions get published, so plugin fixes will increasingly ship SPM-only.
  • Capacitor 8+ scaffolds new iOS projects with SPM by default. Upgrading Capacitor does not convert an existing CocoaPods app.
  • Capacitor 9 (currently next / alpha) only adds the Cordova product / CapacitorCordova pod when a Cordova plugin is installed. Native code that imports Cordova without a Cordova plugin breaks in either setup.

How the CLI Decides

  • The CLI treats the project as SPM if and only if ios/App/CapApp-SPM/ exists. Deleting or renaming it silently flips npx cap sync back to CocoaPods behavior.
  • ios/App/CapApp-SPM/Package.swift is regenerated on every npx cap sync ios (// DO NOT MODIFY THIS FILE - managed by Capacitor CLI commands). Put customizations in capacitor.config.*, never in that file.
  • A plugin is included only if its npm package root has a Package.swift. Others are skipped with a warning; their native code is silently missing at runtime ("X" plugin is not implemented on ios).
  • During sync, if a plugin's Package.swift pins capacitor-swift-pm to a different major, the CLI rewrites that file inside node_modules and warns <id> is built for Capacitor <N>, it might cause issues. Treat this as "upgrade the plugin", not as success.
  • Cordova plugins get a generated package under ios/capacitor-cordova-ios-plugins/sources/<Name>. Plain .framework files are not supported as SPM binary targets (warning: custom .framework files are not supported as binaryTarget in SPM); they need an .xcframework.

Command Policy

  • Use the repo's package manager for installs and scripts; keep Capacitor CLI calls as npx cap ... so the project-local CLI runs.
  • Run commands from the directory containing capacitor.config.*.

Live Project Snapshot

Detected Capacitor, iOS, Cordova, and plugin dependencies: !node -e "const fs=require('fs');if(!fs.existsSync('package.json'))process.exit(0);const pkg=JSON.parse(fs.readFileSync('package.json','utf8'));const out=[];for(const section of ['dependencies','devDependencies']){for(const [name,version] of Object.entries(pkg[section]||{})){if(name.startsWith('@capacitor/')||name.startsWith('@capgo/')||name.startsWith('@capacitor-community/')||name.startsWith('@awesome-cordova-plugins/')||name.startsWith('cordova-')||name.includes('capacitor'))out.push(section+'.'+name+'='+version)}}console.log(out.sort().join('\n'))"

Relevant iOS dependency files: !find ios -maxdepth 5 \( -name 'Podfile' -o -name 'Podfile.lock' -o -name 'Pods' -o -name 'App.xcworkspace' -o -name 'Package.swift' -o -name 'Package.resolved' -o -name 'CapApp-SPM' -o -name 'debug.xcconfig' -o -name 'project.pbxproj' -o -name 'Info.plist' -o -name '*.entitlements' -o -name 'GoogleService-Info.plist' \) 2>/dev/null

Procedure

1. Inspect (read-only)

  1. Capacitor version in package.json (@capacitor/ios). 8.x and 9.x are supported; on 6.x/7.x, prefer upgrading first.
  2. ios/App/Podfile and Podfile.lock: list every pod, and which ones are not Capacitor plugins (Firebase, analytics SDKs, custom pods added by hand).
  3. For each Capacitor/Cordova plugin: does node_modules/<pkg>/Package.swift exist? Cordova plugins get a generated package, so only NO entries block:
    node -e "const fs=require('fs');const p=require('./package.json');for(const n of Object.keys({...p.dependencies,...p.devDependencies})){const d='node_modules/'+n;if(!fs.existsSync(d+'/ios')&&!fs.existsSync(d+'/plugin.xml'))continue;console.log((fs.existsSync(d+'/Package.swift')?'SPM     ':fs.existsSync(d+'/plugin.xml')?'CORDOVA ':'NO      ')+n)}"
    
  4. ios/App/App.xcodeproj/project.pbxproj: signing, custom build settings, extra targets (widgets, notification service extensions), build phases, schemes.
  5. ios/App/App/: AppDelegate.swift, SceneDelegate.swift, Info.plist, entitlements, GoogleService-Info.plist, custom Swift/ObjC files.

Report findings before editing: plugins without SPM, non-plugin pods that need an SPM replacement, and native customizations at risk.

2. Resolve blockers

For every NO plugin or non-plugin pod:

  • Upgrade the plugin (most maintained plugins, including @capacitor/* and @capgo/*, ship Package.swift).
  • Replace it with a maintained SPM-capable alternative.
  • If the project owns the plugin, convert it with capacitor-plugin-spm-support.
  • For third-party SDK pods added directly in the Podfile, add the vendor's SPM package to the App target in Xcode after migration.

Ask the user before proceeding if a critical plugin has no SPM path. Do not keep a hybrid Podfile + CapApp-SPM setup.

3. Choose a path

PathUse when
npx cap spm-migration-assistantMost apps; keeps the existing Xcode project and its customizations.
Fresh scaffoldios/ is close to the template (no extensions, few native edits).
Manual repairThe assistant ran partially or the project is heavily customized.

4a. Run the migration assistant

Commit first. Requires CocoaPods (or Bundler) still installed because it runs pod deintegrate.

npx cap spm-migration-assistant

It runs pod deintegrate, deletes Podfile, Podfile.lock, and App.xcworkspace, extracts ios/App/CapApp-SPM/, writes ios/debug.xcconfig (CAPACITOR_DEBUG = true), adds CAPACITOR_DEBUG = $(CAPACITOR_DEBUG) to Info.plist if missing, then runs an iOS update that generates Package.swift. It ends with To complete migration follow the manual steps at https://capacitorjs.com/docs/ios/spm#using-our-migration-tool.

Two manual Xcode steps remain (npx cap open ios, which now opens App.xcodeproj):

  1. Project App -> Package Dependencies -> + -> Add Local... -> select ios/App/CapApp-SPM -> Add Package, and link the CapApp-SPM library to the App target.
  2. Project App -> Info -> Configurations -> Debug -> set the configuration file to debug.xcconfig.

Then npx cap sync ios.

4b. Fresh scaffold

Back up everything listed in step 1.5 first.

rm -rf ios
npx cap add ios --packagemanager SPM
npx cap sync ios

On Capacitor 8.5+ the new template already includes SceneDelegate.swift and UIApplicationSceneManifest. Restore icons, Info.plist keys, entitlements, signing, Firebase plist, custom sources, and extension targets by merging, not overwriting template files.

5. Optional SPM config in capacitor.config.*

Only when needed (all under experimental.ios.spm, verify the installed CLI version supports them):

  • swiftToolsVersion (8.3+, default '5.9'): header of the generated Package.swift.
  • packageTraits (8.3+): { "<plugin id>": ["TraitName", ".defaults"] }; requires swiftToolsVersion >= '6.1'.
  • packageOptions (8.4+): { "<plugin id>": { symlink: true, moduleAliases: { "Target": "Alias" } } } for package name or module collisions.

6. UIScene check

The assistant changes dependency management only. If Info.plist lacks UIApplicationSceneManifest, the app is not on the scene lifecycle that Capacitor 8.5+ and Xcode 27 expect; run npx cap migrate or follow capacitor-uiscene-migration.

Verification

# No CocoaPods leftovers
ls ios/App | grep -E 'Podfile|Pods|xcworkspace' && echo "LEFTOVERS" || echo "clean"
# CLI sees SPM and every plugin is included
npx cap sync ios 2>&1 | grep -Ei 'Package.swift|not compatible|built for Capacitor'
grep -c '.package(name:' ios/App/CapApp-SPM/Package.swift
# Plugin classes registered for runtime
node -e "console.log(require('./ios/App/App/capacitor.config.json').packageClassList)"
# Build without Xcode UI (project, not workspace)
xcodebuild -project ios/App/App.xcodeproj -scheme App -destination 'generic/platform=iOS Simulator' build

Also confirm in Xcode: CapApp-SPM linked to the App target, Debug uses debug.xcconfig, signing/bundle id/capabilities unchanged. On device, exercise each native plugin once (camera, push, purchases, etc.).

Commit ios/App/CapApp-SPM/ and ios/debug.xcconfig. Follow CapApp-SPM/.gitignore for Package.resolved (newer templates ignore it).

Error Handling

Load references/troubleshooting.md for the full table. Most common:

Message / symptomFix
Capacitor project is already using SPM, exiting.CapApp-SPM/ already exists. Do manual repair, not the assistant.
CocoaPods is not installed. (assistant)Install CocoaPods temporarily or use the fresh scaffold path.
<id> does not have a Package.swift / Some installed Capacitor plugins are not compatible with SPMUpgrade, replace, or convert that plugin (step 2).
"X" plugin is not implemented on ios at runtimePlugin skipped from Package.swift, or packageClassList missing it. Fix the plugin, re-sync, clean build.
No such module 'Capacitor' / Missing package product 'CapApp-SPM'Local package not added/linked; redo manual step 1, then File -> Packages -> Reset Package Caches.
Debug-only features off (no WebView inspection, no debug logs)debug.xcconfig not set on Debug configuration.

Output Format

For planning, return: current state (Capacitor version, pods, plugins without SPM, customizations at risk), chosen path and why, ordered steps, remaining Xcode/device-only checks.

FAQ

What does the cocoapods-to-spm skill do?

Migrates an existing Capacitor iOS app from CocoaPods to Swift Package Manager (SPM) before CocoaPods Trunk goes read-only (expected December 2, 2026). Use when the app still has ios/App/Podfile, Pods/, Podfile.lock or App.xcworkspace and the user wants CapApp-SPM, runs or recovers from npx cap spm-migration-assistant, needs debug.xcconfig / CAPACITORDEBUG wired up, sees "Some installed Capacitor plugins are not compatible with SPM" or " does not have a Package.swift", or plans the Capacitor 9 upgrade where SPM is the default. Do not use for adding SPM support inside a plugin repository (use capacitor-plugin-spm-support), the UIScene lifecycle migration (use capacitor-uiscene-migration), full version upgrades (use capacitor-app-upgrades), or generic iOS build debugging (use debugging-capacitor).

How do I install cocoapods-to-spm?

Run npx skills add https://github.com/cap-go/capgo-skills --skill cocoapods-to-spm in your project. The skills CLI detects the agents you use and copies the skill into the right folder. For Claude Code you can also place the skill folder at ~/.claude/skills/cocoapods-to-spm/ (personal) or .claude/skills/cocoapods-to-spm/ (project).

Which AI agents can use cocoapods-to-spm?

Any agent that supports the open Agent Skills format (a folder with a SKILL.md file), including Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, Windsurf, Cline, OpenCode and more.

Is cocoapods-to-spm safe to install?

No partner security audit is available yet. Skills can run commands and scripts, so read the SKILL.md and any bundled files before installing.

Who maintains cocoapods-to-spm?

It is published by cap-go in cap-go/capgo-skills. It has 797 recorded installs.

More from cap-go/capgo-skills

View all →

capacitor-best-practices

cap-go/capgo-skills

Review and set up Capacitor apps against current best practices (Capacitor 8.5 stable, 9 alpha via @next). Use for a Capacitor codebase review, capacitor.config.ts audit, new project setup, aligning @capacitor/core/cli/ios/android and plugin majors, plugin patterns (availability checks, checkPermissions/requestPermissions, error code handling, web fallbacks), or release prep; or on " " plugin is not implemented on ios, Could not find the web assets directory, platform has not been added yet, a dev server.url shipped to production, lost edits in android/app/src/main/assets/public, SPM vs CocoaPods, or AppDelegate/UIScene drift. Do not use for security audits (capacitor-security), performance (capacitor-performance), tests (capacitor-testing), crashes (debugging-capacitor), major upgrades (capacitor-app-upgrades), SPM migration (cocoapods-to-spm), UIScene adoption (capacitor-uiscene-migration), or live updates (capgo-live-updates).

ionic-design

cap-go/capgo-skills

Builds and reviews Ionic Framework UI in Capacitor apps (Ionic 9 current, Ionic 8 still common) - page structure (ion-header/ion-content/ion-footer), lists, modern form syntax (label/labelPlacement on ion-input/ion-select), sheet modals, tabs + ion-router-outlet, CSS variable theming, dark palettes (palettes/dark.system.css, .ion-palette-dark), iOS vs MD mode, and Ionic 8 - 9 breaking changes (React Router 6, Vue Router 5, Angular 18-22 zoneless, removed ion-picker-legacy, boolean autocorrect, npx @ionic/migrate). Use when writing Ionic components, theming an Ionic app, fixing platform-mode styling, or upgrading @ionic/react, @ionic/vue, @ionic/angular. Do not use for Konsta UI (konsta-ui), Tailwind setup (tailwind-capacitor), raw safe-area CSS (safe-area-handling), keyboard resize (capacitor-keyboard), or Ionic Appflow/Enterprise migrations (ionic-appflow-migration, ionic-enterprise-sdk-migration).

Frontend & Design1.6K installs

capacitor-plugins

cap-go/capgo-skills

Pick, install, and wire up Capacitor plugins for native features (camera, filesystem, geolocation, biometrics, in-app purchases, social login, SQLite, calendar, contacts, health, BLE, NFC, etc.). Covers official @capacitor/ packages (Capacitor 8.5 stable, 9 alpha on next) plus the 145-package @capgo/ index, native permission keys (Info.plist, AndroidManifest, variables.gradle minSdk), npx cap sync / cap ls verification, and errors like '"Camera" plugin is not implemented on ios', 'unable to find plugin', UNIMPLEMENTED, and OS-PLUG- codes. Use for "which plugin should I use for X", adding a plugin, or a plugin call failing after install. Do not use for push setup (capacitor-push-notifications), splash assets (capacitor-splash-screen), keyboard layout (capacitor-keyboard), deep links (capacitor-deep-linking), OTA updates (capgo-live-updates), upgrading plugin source code (capacitor-plugin-upgrades), or adding SPM to a plugin (capacitor-plugin-spm-support).

Frontend & Design1.6K installs

debugging-capacitor

cap-go/capgo-skills

Diagnoses and fixes runtime bugs in Capacitor iOS/Android apps - white/blank screen on launch, startup crashes, "X" plugin is not implemented on ios/android, net::ERRCLEARTEXTNOTPERMITTED, App Transport Security blocks, CORS on capacitor://localhost, permission denials, live reload not connecting, and Capacitor 8.5+ UIScene regressions (appUrlOpen, universal links, pause/resume silent because AppDelegate callbacks stopped). Covers Safari Web Inspector, chrome://inspect, Xcode/LLDB, Android Studio, npx cap run --url (Capacitor 9) vs -l --host (8), xcrun simctl openurlprivacypush, xcrun devicectl device process launchopenURL, xctrace. Do not use for only reading device logs (ios-android-logs), the UIScene migration itself (capacitor-uiscene-migration), deep-link setup (capacitor-deep-linking), speed (capacitor-performance), crash SDKs (capacitor-native-observability), tests (capacitor-testing), or upgrades/build errors (capacitor-app-upgrades, cocoapods-to-spm).

capacitor-testing

cap-go/capgo-skills

Testing guide for Capacitor apps and plugins. Covers web-layer unit and component tests with Vitest and mocked Capacitor plugins (vi.mock('@capacitor/core'), registerPlugin), Playwright for the web build, Appium E2E with NATIVEAPP / WEBVIEW context switching, native plugin unit tests with Swift Testing vs XCTest (what can migrate, CAPPluginCall patterns, xcodebuild test on a simulator) and Android JUnit, plus an agent-driven verification loop on simulators and devices (build, install, launch, screenshot, UI hierarchy, tap, logs) with xcrun simctl, xcrun devicectl, adb, Xcode MCP device tools, and live reload via npx cap run --url (Capacitor 9) or -l --host --port (Capacitor 8). Use when adding tests, mocking plugins, "does it work on device", verifying a UI change on a simulator, migrating XCTest to Swift Testing, or setting up test CI. Do not use for crash log capture (ios-android-logs), WebView debugging sessions (debugging-capacitor), or build pipelines (capacitor

Testing & QA1.3K installs

safe-area-handling

cap-go/capgo-skills

Fixes notch, Dynamic Island, home indicator, display cutout, and system bar overlap in Capacitor apps. Covers viewport-fit=cover + env(safe-area-inset-), the Capacitor 8 SystemBars core plugin (insetsHandling, injected --safe-area-inset- CSS variables for Android WebView < 140, removal of android.adjustMarginsForEdgeToEdge), Android 15/16 enforced edge-to-edge (overlaysWebView and backgroundColor of @capacitor/status-bar no longer work at targetSdk 36), iOS contentInset, and insets that change at runtime on rotation, iPad/foldable resizable windows. Use when headers sit under the status bar, tab bars hide behind the gesture bar, env() returns 0 on Android, or layout broke after upgrading to Capacitor 8 / targetSdk 35+. Do not use for keyboard overlap (capacitor-keyboard), Ionic/Konsta component theming (ionic-design, konsta-ui), Tailwind utility setup (tailwind-capacitor), or iOS multi-window/resizability adoption (capacitor-ios-resizability).

Mobile1.3K installs

Popular code quality & workflow skills

View category →

grill-me

mattpocock/skills

A relentless interview to sharpen a plan or design.

Scan a codebase for deepening opportunities, present them as a visual HTML report, then grill through whichever one you pick.

handoff

mattpocock/skills

Compact the current conversation into a handoff document for another agent to pick up.

domain-modeling

mattpocock/skills

Build and sharpen a project's domain model. Use when discussing codebase terminology, writing or editing a GLOSSARY.md, or recording or editing an ADR.

codebase-design

mattpocock/skills

Shared vocabulary for designing deep modules. Use when the user wants to design or improve a module's interface, find deepening opportunities, decide where a seam goes, make code more testable or AI-navigable, or when another skill needs the deep-module vocabulary.

diagnosing-bugs

mattpocock/skills

Diagnosis loop for hard bugs and performance regressions. Use when the user says "diagnose"/"debug this", or reports something broken/throwing/failing/slow.