Skills/spm-to-tuist/SKILL.md
--- name: spm-to-tuist description: Migrates a generative, enum-driven Swift Package Manager (SPM) modular architecture to Tuist while preserving architectural invariants and meta-structure. --- # Intent Migrate a Swift Package Manager (SPM) project to Tuist **without losing its generative architecture model**. The existing SPM setup is not flat. Targets and products are derived from enums, and dependencies are strongly typed through helper abstractions. This migration must preserve not on
npx skillsauth add packtpublishing/ai-driven-swift-architecture Skills/spm-to-tuistInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Migrate a Swift Package Manager (SPM) project to Tuist without losing its generative architecture model.
The existing SPM setup is not flat. Targets and products are derived from enums, and dependencies are strongly typed through helper abstractions.
This migration must preserve not only module boundaries, but also the architectural meta-model.
The following constraints must remain true after migration:
Create a Project.swift file next to your existing Package.swift file.
Example minimal Project.swift:
import ProjectDescription
let project = Project(
name: "App",
targets: [
.target(
name: "App",
destinations: .iOS,
product: .app,
bundleId: "dev.tuist.App",
sources: ["Sources/**/*.swift"]
)
]
)
Important distinctions:
ProjectDescription instead of PackageDescription.Project instance instead of a Package instance.Next, create a Tuist.swift file at the root of the project:
import ProjectDescription
let tuist = Tuist()
The presence of Tuist.swift defines the root of the Tuist project and enables configuration.
At this stage, Swift Package Manager still governs the build.
Tuist has been introduced but has not yet taken ownership of the structure.
The current SPM configuration encodes architecture using enum-driven generation.
Example:
enum DataProduct: String, CaseIterable {
case BasketData
case ProductData
case UserData
}
Targets and products are derived from:
products: DataProduct.allCases.map(\.product)
targets: DataProduct.allCases.map(\.target)
Dependencies are expressed through typed helpers:
.abstraction(.BasketAbstraction)
.utility(.API)
.internal(.BasketData)
The Tuist migration must preserve:
Flattening this structure into manually written targets is not acceptable.
The migration must follow these phases:
The Skill must instruct the AI agent to:
After migration:
tuist installtuist generatetuist graphThe migration is complete only if architectural invariants and meta-structure are preserved.
development
Migrates runtime-based dependency injection using Swinject to compile-time–oriented dependency injection using Factory. Use when refactoring DI containers, composition roots, and dependency lifetimes in a Clean Architecture–oriented Swift project.
development
Migrates RxSwift networking code to native Swift async/await. Use when refactoring Observable-based API code, removing RxSwift dependencies, or modernizing to Swift Concurrency.
development
Cleans and maintains Package.swift files in a Clean Architecture–oriented Swift project. Use when removing obsolete dependencies, refactoring module graphs, or enforcing architectural conventions encoded in Package.swift.
tools
Use when work should span one or more detached tasks but still behave like one job with a single owner context. TaskFlow is the durable flow substrate under authoring layers like Lobster, ACPX, plugins, or plain code. Keep conditional logic in the caller; use TaskFlow for flow identity, child-task linkage, waiting state, revision-checked mutations, and user-facing emergence.