Build Test CodeQL Latest Release

Modernize Apple dependencies safely.

PkgLift analyzes native Xcode projects, builds a dependency migration plan, and safely moves the supported subset of CocoaPods dependencies to Swift Package Manager.

No blind conversions. No guesswork.

Analyze → Plan → Migrate → Verify

Project website · Installation · Quick Start · Compatibility · Safety Philosophy · Pilot Evidence · Diagnostics · Support · Report a Migration · Propose a Registry Mapping

PkgLift v0.4.0 analyzing, planning, and dry-running the repo-owned mixed-language fixture

Condensed from PkgLift v0.4.0 output against the repository-owned mixed-language fixture. This demo stops at dry run; the separate end-to-end workflow is the apply-and-build proof. See the full pilot boundary.

If PkgLift helps with a migration, star the repository or share a redacted migration report. Both make the next unsupported project shape easier to prioritize.

What PkgLift Does

PkgLift automates the evidence-backed parts of moving a native iOS or macOS Xcode project from CocoaPods to Swift Package Manager (SwiftPM), while preserving uncertain dependencies under CocoaPods for human review.

pkglift analyze
pkglift plan
pkglift migrate                         # dry run; no project mutation
pkglift migrate --apply                 # reviewed AUTO entries only
pkglift verify --build --scheme MyApp

A Reviewed Migration, Not a Conversion Guess

A project might begin with direct CocoaPods declarations such as:

target 'MyApp' do
  pod 'Alamofire', '5.9.1'
  pod 'InternalAnalytics'
end

PkgLift can produce a plan where the exact, version-supported Alamofire mapping is executable while the unknown internal dependency is preserved:

Alamofire 5.9.1      AUTO     exact verified mapping
InternalAnalytics   UNKNOWN  no registry evidence

After review, only the AUTO entry may be added as a Swift package. The unknown pod and the remaining CocoaPods integration stay in place. PkgLift does not invent a package URL, product name, target, or compatible version.

Why PkgLift Exists

CocoaPods has announced a plan for trunk to stop accepting new Podspecs on December 2, 2026. The plan explicitly keeps existing trunk and CDN builds available, and does not mean CocoaPods itself or private spec repositories stop working. PkgLift provides a reviewable path for native Xcode projects that want to move supported dependencies to SwiftPM without pretending every pod or project shape can be converted automatically.

What Is New in v0.4.0

  • Analysis dependencies and migration-plan entries can carry additive typed sourceProvenance evidence for a bounded literal external Git declaration.
  • Supported HTTPS, SSH, and SCP-style repository identities are canonicalized deterministically without guessing transport equivalence.
  • Podfile declarations are reconciled with CocoaPods EXTERNAL SOURCES and CHECKOUT OPTIONS evidence without executing Ruby or contacting the repository.
  • Credentials, URL user information, queries, and fragments are removed at the parser trust boundary and raw source URLs are not retained in standard or portable JSON.
  • Saved and current external provenance is compared during migration preflight; missing, changed, conflicting, credential-bearing, or lossy evidence refuses mutation.
  • XcodeBenchmark and Hammerspoon provide independent pinned, read-only real-project evidence for deliberate external Git refusal paths.
  • External sources remain analysis-only: every result is REVIEW, BLOCKED, or UNKNOWN, never AUTO.

See the v0.4.0 release notes, changelog, JSON contract, migration-safety guide, and real-project pilot documentation for the complete evidence and refusal boundaries.

Safety Philosophy

PkgLift operates on a strict safety model. Every dependency is classified before migration:

Classification Meaning Executed automatically
AUTO Exact pod or subspec mapping, supported locked version, verified package product, exact destination target, and complete supported consumer-language evidence Yes, after plan review and --apply
REVIEW A plausible migration exists, but human judgment or unsupported project context is involved No
BLOCKED A known incompatibility or unsafe project construct prevents automatic migration No
UNKNOWN PkgLift lacks exact registry evidence No

REVIEW, BLOCKED, and UNKNOWN are not failed conversions. They are safe outcomes that prevent PkgLift from changing a project without sufficient evidence.

We never guess. We never blindly edit project files without a reviewed plan.

Compatibility

PkgLift targets partial CocoaPods-to-SwiftPM migration in native Xcode projects. A language or ecosystem listed as detected is not necessarily eligible for automatic migration.

Project or integration Current behavior
Swift-only target AUTO-eligible when the complete target profile and exact registry mapping both support Swift
Objective-C-only target AUTO-eligible only when the exact mapping explicitly supports Objective-C
Mixed Swift/Objective-C target AUTO-eligible only when the same mapping explicitly supports both languages
Objective-C++, C, or C++ target Detected from PBX metadata; currently REVIEW unless a mapping explicitly supports every detected language
Carthage Root metadata and confirmed Xcode integration are detected; Carthage dependencies are not parsed, migrated, or modified, and confirmed presence prevents AUTO
React Native use_react_native! is detected as an unsupported project integration and prevents AUTO
Flutter flutter_install_all_ios_pods is detected as an unsupported project integration and prevents AUTO
Capacitor capacitor_pods is detected as an unsupported project integration and prevents AUTO
Kotlin Multiplatform (KMP) No heuristic detection is claimed; local pods and dynamic generation remain non-automatic under existing safety rules
External Git pod PkgLift v0.4.0 can analyze bounded literal repository/ref provenance, but the dependency remains REVIEW, BLOCKED, or UNKNOWN and is never migrated automatically
Local :path pod Detected as an external source; typed local provenance and automatic migration are not implemented

Host support remains macOS 14 or later on Apple Silicon (arm64). Distribution is through a Developer ID-signed and Apple-notarized binary, Homebrew, or a source build. See Limitations for the intentionally conservative boundaries.

Installation

PkgLift v0.4.0 is distributed as a Developer ID-signed and Apple-notarized Apple Silicon binary for macOS 14 or later.

Install with Homebrew:

brew install Alexsvensson99/tap/pkglift

Release archives are also available from GitHub Releases. Maintainer signing, notarization, and release instructions are documented in Distribution.

Verify and extract a downloaded archive before installing it:

shasum -a 256 -c pkglift-macos-arm64.tar.gz.sha256
tar -xzf pkglift-macos-arm64.tar.gz
sudo mkdir -p /usr/local/libexec/pkglift /usr/local/bin
sudo cp pkglift /usr/local/libexec/pkglift/
sudo cp -R PkgLift_PkgLiftRegistry.bundle /usr/local/libexec/pkglift/
sudo ln -sf /usr/local/libexec/pkglift/pkglift /usr/local/bin/pkglift

From a source checkout:

swift build -c release
sudo mkdir -p /usr/local/libexec/pkglift /usr/local/bin
sudo cp .build/release/pkglift /usr/local/libexec/pkglift/
sudo cp -R .build/release/PkgLift_PkgLiftRegistry.bundle /usr/local/libexec/pkglift/
sudo ln -sf /usr/local/libexec/pkglift/pkglift /usr/local/bin/pkglift

Quick Start

  1. Navigate to the repository root containing the Podfile; Xcode projects and workspaces may be nested beneath it.
  2. Run pkglift analyze to see what PkgLift can classify.
  3. Run pkglift plan to generate .pkglift/plan.json.
  4. Review every entry in the plan.
  5. Run pkglift migrate for a validated dry run.
  6. Keep the generated .pkglift/plan.json from appearing as an untracked change. For a one-off test, add only that file to the repository-local Git exclude; for a shared policy, add it to .gitignore and commit the policy change. See Testing PkgLift on a Real Project for the safe commands and review flow.
  7. Confirm that git status --short is empty, then run pkglift migrate --apply.
  8. Run pod install so CocoaPods updates the dependencies that remain.
  9. Run pkglift verify; add --build --scheme <scheme> for a full build.

PkgLift deliberately refuses --apply when Git reports a dirty worktree. Do not bypass that safeguard to work around the generated plan file.

PkgLift discovers projects and workspaces recursively while excluding generated dependency and build trees. If a workspace references multiple projects, select both the workspace and project explicitly:

pkglift analyze --path . \
  --workspace Workspaces/Products.xcworkspace \
  --project Projects/App.xcodeproj

Selection paths are standardized and resolved through symlinks beneath --path. Workspace references that escape that root or use unsupported location schemes are refused rather than guessed.

For a reproducible full build, pass the same explicit settings used by the project or CI:

pkglift verify \
  --path . \
  --workspace MyApp.xcworkspace \
  --project MyApp.xcodeproj \
  --build \
  --scheme MyApp \
  --configuration Debug \
  --destination 'generic/platform=iOS Simulator' \
  --derived-data-path .pkglift/DerivedData

Commands

  • analyze: Scans the project and dependencies.
  • plan: Generates a migration plan.
  • migrate: Validates the saved plan and previews it; --apply performs only typed AUTO actions.
  • verify: Verifies the project after migration and can optionally resolve packages and run a build.
  • diagnostics: Writes a local, privacy-preserving JSON report without uploading it.
  • registry validate: Validates local and bundled registry mappings.
  • version: Prints the current version.

analyze and plan accept --portable-json as an alternative to --json. Portable output removes local paths and URL credentials and adds portableOutput.version = 1, but still contains dependency and target names. External Git literals are already canonicalized and stripped of credentials, queries, and fragments before either standard or portable JSON is constructed. plan --portable-json prints the portable representation while keeping the standard executable plan in .pkglift/plan.json.

analyze also accepts a CI policy without changing its normal behavior:

pkglift analyze --json --fail-on unresolved > pkglift-analysis.json

PkgLift writes the complete result before exiting with status 1. Only direct dependencies affect the policy: blocked matches BLOCKED; unresolved matches BLOCKED or UNKNOWN; and non-auto matches every direct dependency that is not AUTO. Analysis never creates or changes a migration plan.

Share a Real-World Result

Testing on varied public and private project layouts helps PkgLift improve without weakening its safety model.

Generate a minimized report when it helps reproduce the result:

pkglift diagnostics \
  --path . \
  --output pkglift-diagnostics.json

Review the JSON before sharing it. The report contains counts, flags, tool versions, Git state, and typed failure stages; it excludes source code, complete Podfiles, dependency and target names, repository URLs, changed filenames, arbitrary error messages, and absolute user paths. See Privacy-Preserving Diagnostics.

Registry

The PkgLift Registry is an open-source database mapping exact CocoaPods identifiers to verified SwiftPM repositories and products. It handles module naming, version requirements, and compatibility evidence.

See Registry and Contributing Registry Mappings to learn how mappings are verified.

Configuration

Customize PkgLift using a .pkglift.yml file in the project root:

schemaVersion: 1
migration:
  allow:
    - Alamofire
  deny:
    - SomeInternalPod

An invalid configuration is an error; PkgLift does not silently ignore it.

Limitations

PkgLift v0.4.0 retains these safety boundaries:

  • Only CocoaPods-to-SwiftPM migration is supported.
  • Migration is partial: non-automatic pods and their CocoaPods integration are preserved.
  • A stable major.minor.patch lockfile version at or above the exact mapping's verified SwiftPM minimum, exactly one matching Xcode target, a complete non-empty target language profile, and mapping support for every detected language are required for AUTO.
  • Dynamic Ruby, install hooks, script_phase, use_frameworks!, inherit! :search_paths, abstract_target, external pod sources, and ambiguous target mappings are non-automatic. PkgLift analyzes only bounded literal :git provenance; every external dependency still resolves to REVIEW, BLOCKED, or UNKNOWN, never AUTO.
  • Local :path provenance, repository network resolution, Podspec generation, and automatic external-source migration are not implemented.
  • Confirmed Carthage integration and React Native, Flutter, or Capacitor Podfile markers prevent AUTO; PkgLift does not migrate or remove those integrations.
  • KMP is not detected through speculative file or name heuristics.
  • Base pod mappings never apply automatically to undeclared subspecs.
  • Parenthesized target and pod calls are accepted only for bounded literal forms in balanced static Ruby scopes. Interpolation, variables, raw control characters, non-ASCII whitespace, excessive scope nesting, multiline literals or continuations, unrecognized executable statements, CocoaPods DSL method shadowing, unsupported enclosing blocks or heredocs, external or extra options and expression tails, postfix conditions, semicolons, and unbalanced syntax remain non-automatic. Ruby block comments and __END__ data are ignored only at valid column-zero markers and cannot create dependencies.
  • Project and workspace selection never follows a reference outside --path; widen --path explicitly if a legitimate workspace spans a broader repository root.
  • PkgLift removes only exact migrated pod declarations. It deliberately preserves target blocks, unrelated Ruby, and CocoaPods integration for pods that remain.
  • PkgLift does not run pod install automatically.
  • Objective-C and mixed targets are automatic only for mappings with explicit matching consumer-language evidence. Current bundled C-family coverage is intentionally limited.

Roadmap

See ROADMAP.md, the analysis-only Podspec semantic model, the v0.5.0 tracker, the v0.4.0 release tracker, and the v0.3.0 release tracker for planned scope and release evidence.

Contributing

Contributions are welcome. See CONTRIBUTING.md to get started and SUPPORT.md to choose the correct support or reporting path.

License

PkgLift is licensed under the MIT License. See LICENSE.


Note: PkgLift is an independent open-source project and is not affiliated with Apple Inc. or the CocoaPods organization.