Swift packages
Add, update and remove Swift packages, and keep them in a sochi.toml file that stays in step with your Xcode project.
sochi manages Swift packages in the Xcode project itself, so Xcode sees exactly what it would if you’d added them there. It also keeps a short, readable list of them in sochi.toml, next to your project, that you can edit by hand and review in pull requests.
Add a package
Section titled “Add a package”sochi add package pointfreeco/swift-dependenciessochi add package https://github.com/apple/swift-collections --exact 1.1.4 --product OrderedCollectionssochi add package ../MyKitThe source can be:
owner/repo, which means a GitHub repository.- Any repository URL.
- A local folder with a
Package.swift. The path is stored relative to the project.
Without a version rule, sochi looks up the newest release tag and uses “up to next major” from it, the same default as Xcode. Or pass one rule:
| Option | Means |
|---|---|
--from 1.4.0 |
Up to the next major version: 1.4.0 up to, but not including, 2.0.0. |
--minor 1.4.0 |
Up to the next minor version: 1.4.0 up to, but not including, 1.5.0. |
--exact 1.4.0 |
Only 1.4.0. |
--range "1.0.0..<1.8.0" |
Any version in the range. |
--branch main |
The latest commit on a branch. |
--revision 4f1c2a9 |
One exact commit. |
sochi reads the package’s products before changing anything. If it has a single library, that one is linked. If it has several, choose with --product, which you can repeat. The package is linked to the app target unless you pass --target. Adding the same package to a second target keeps the products the first target already uses.
After writing, sochi resolves the packages with xcodebuild and checks each product against the package’s manifest. If resolving fails, it puts every file back, including Package.resolved, and shows xcodebuild’s errors.
See your packages
Section titled “See your packages”sochi packagesswift-dependencies from 1.17.1 → 1.17.1 App: Dependenciesswift-collections exactly 1.1.4 → 1.1.4 App: OrderedCollectionsmykit local App: MyKitEach line shows the rule, the version Package.resolved currently pins, and which targets use which products. If a package differs from sochi.toml, the line says so.
Update packages
Section titled “Update packages”sochi update # every packagesochi update swift-dependencies # only theseupdate moves packages to the newest versions their rules allow, the same as Xcode’s “Update to Latest Package Versions”. It changes only Package.resolved, never the rules in sochi.toml. To allow a newer major version, change the rule.
Remove a package
Section titled “Remove a package”sochi remove package swift-collectionssochi remove package swift-collections --target Widget # only stop Widget using itUse the name sochi packages shows. Matching ignores case.
sochi.toml
Section titled “sochi.toml”The first package command creates sochi.toml next to your project:
# sochi.toml: your project's packages, kept in sync with the Xcode project by sochi.# Edit it by hand or with `sochi add package`; Package.resolved stays the lockfile.
[packages.swift-dependencies]url = "https://github.com/pointfreeco/swift-dependencies"from = "1.17.1"products = { App = ["Dependencies"], Forecast = ["Dependencies"] }
[packages.mykit]path = "../MyKit"products = { App = ["MyKit"] }products maps each target to the library products it links. The sochi.toml reference lists every key.
Package.resolved stays the lockfile. Commit both files.
Keeping both sides in step
Section titled “Keeping both sides in step”You can change packages in three places: sochi.toml, Xcode, or a sochi command. sochi sync carries changes across in both directions:
- A package you edited or added in
sochi.tomlis written into the project. - A package you added or changed in Xcode is written into
sochi.toml. - A package removed on one side is removed from the other.
sochi syncsochi sync --dry-runYou rarely need to run it yourself. sochi run and sochi build sync first whenever a sochi.toml exists.
To tell which side changed, sochi keeps a private record of the last sync on your Mac. If both sides changed the same package since then, it stops without writing anything and shows you both versions:
sochi.toml and the project disagree, and sochi won't guess which is right. Edit one to match the other, then sync: • swift-dependencies: sochi.toml has from 1.17.1, the project has exactly 1.16.0Make the two match, then run sochi sync again.
On a fresh clone or a new Mac there’s no record yet, so the first sync only adds packages and never removes any.
Starting from an existing project
Section titled “Starting from an existing project”If your project already has packages, run:
sochi syncWith no sochi.toml, this creates one from the project’s packages.
Limits
Section titled “Limits”- Package commands need a single
.xcodeproj. A workspace with several projects is ambiguous. - Local packages added the pre-Xcode 15 way are listed, but left for Xcode to manage.