.claude/skills/add-context/SKILL.md
Create a new business domain context
npx skillsauth add adamayoung/popcorn add-contextInstall 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.
Guide for creating a new context following clean architecture with Domain-Driven Design.
Ask the user for:
Contexts/Popcorn{Context}/
├── Package.swift
├── Sources/
│ ├── {Context}Domain/ # Layer 1: Pure business logic
│ │ ├── Entities/
│ │ ├── Repositories/
│ │ └── DataSources/
│ ├── {Context}Application/ # Layer 2: Use cases
│ │ ├── UseCases/
│ │ └── {Context}ApplicationFactory.swift
│ ├── {Context}Infrastructure/ # Layer 3: Data sources
│ │ ├── DataSources/
│ │ │ ├── Local/
│ │ │ │ ├── Models/
│ │ │ │ └── Mappers/
│ │ │ └── Protocols/
│ │ ├── Repositories/
│ │ └── {Context}InfrastructureFactory.swift
│ └── {Context}Composition/ # Layer 4: Wiring
│ └── Popcorn{Context}Factory.swift
└── Tests/
└── {Context}ApplicationTests/
// swift-tools-version: 6.0
import PackageDescription
let package = Package(
name: "Popcorn{Context}",
platforms: [
.iOS(.v26),
.macOS(.v26),
.visionOS(.v2)
],
products: [
.library(name: "{Context}Domain", targets: ["{Context}Domain"]),
.library(name: "{Context}Application", targets: ["{Context}Application"]),
.library(name: "{Context}Infrastructure", targets: ["{Context}Infrastructure"]),
.library(name: "{Context}Composition", targets: ["{Context}Composition"])
],
dependencies: [
.package(path: "../../Core/CoreDomain")
],
targets: [
// Domain - NO dependencies (pure business logic)
.target(name: "{Context}Domain"),
// Application - depends on Domain only
.target(
name: "{Context}Application",
dependencies: ["{Context}Domain"]
),
// Infrastructure - depends on Domain only
.target(
name: "{Context}Infrastructure",
dependencies: ["{Context}Domain"]
),
// Composition - depends on all above
.target(
name: "{Context}Composition",
dependencies: [
"{Context}Domain",
"{Context}Application",
"{Context}Infrastructure"
]
),
// Tests
.testTarget(
name: "{Context}ApplicationTests",
dependencies: ["{Context}Application", "{Context}Domain"]
)
]
)
Entities/{Entity}.swift:
public struct {Entity}: Identifiable, Equatable, Sendable {
public let id: Int
public let name: String
// Add properties
public init(id: Int, name: String) {
self.id = id
self.name = name
}
}
Repositories/{Entity}Repository.swift:
public protocol {Entity}Repository: Sendable {
func {entity}(withID id: Int) async throws({Entity}RepositoryError) -> {Entity}
}
public enum {Entity}RepositoryError: Error, Equatable, Sendable {
case notFound
case unknown(Error? = nil)
}
Follow the add-use-case workflow for each use case.
{Context}ApplicationFactory.swift:
public final class {Context}ApplicationFactory: Sendable {
private let {entity}Repository: any {Entity}Repository
public init({entity}Repository: some {Entity}Repository) {
self.{entity}Repository = {entity}Repository
}
public func makeFetch{Entity}UseCase() -> some Fetch{Entity}UseCase {
DefaultFetch{Entity}UseCase({entity}Repository: {entity}Repository)
}
}
DataSources/Protocols/Remote/{Entity}RemoteDataSource.swift:
public protocol {Entity}RemoteDataSource: Sendable {
func {entity}(withID id: Int) async throws({Entity}RemoteDataSourceError) -> {Entity}
}
public enum {Entity}RemoteDataSourceError: Error {
case notFound
case unauthorised
case unknown(Error? = nil)
}
Repositories/Default{Entity}Repository.swift:
final class Default{Entity}Repository: {Entity}Repository {
private let remoteDataSource: any {Entity}RemoteDataSource
private let localDataSource: any {Entity}LocalDataSource
func {entity}(withID id: Int) async throws({Entity}RepositoryError) -> {Entity} {
// Cache-first strategy
}
}
Popcorn{Context}Factory.swift:
public struct Popcorn{Context}Factory: Sendable {
private let applicationFactory: {Context}ApplicationFactory
public init({entity}RemoteDataSource: some {Entity}RemoteDataSource, modelContainer: ModelContainer) {
let infrastructure = {Context}InfrastructureFactory(
remoteDataSource: {entity}RemoteDataSource,
modelContainer: modelContainer
)
self.applicationFactory = {Context}ApplicationFactory(
{entity}Repository: infrastructure.make{Entity}Repository()
)
}
public func makeFetch{Entity}UseCase() -> some Fetch{Entity}UseCase {
applicationFactory.makeFetch{Entity}UseCase()
}
}
Adapters/Contexts/Popcorn{Context}Adapters/
├── Package.swift
├── Sources/
│ └── Popcorn{Context}Adapters/
│ ├── DataSources/
│ │ └── TMDb{Entity}RemoteDataSource.swift
│ └── Popcorn{Context}AdaptersFactory.swift
Create AppDependencies/{Context}/:
{Context}Factory+TCA.swiftAdd the new package to the main Xcode project's package dependencies.
Add all new unit test targets to TestPlans/PopcornUnitTests.xctestplan so tests run as part of the test plan. Add an entry to the testTargets array for each test target:
{
"target" : {
"containerPath" : "container:Contexts\/Popcorn{Context}",
"identifier" : "{Context}ApplicationTests",
"name" : "{Context}ApplicationTests"
}
}
Repeat for each test target (e.g., {Context}DomainTests, {Context}InfrastructureTests). Do NOT add snapshot test targets here — those belong in PopcornSnapshotTests.xctestplan.
$ARGUMENTS
data-ai
Add properties to an existing domain model from TMDb
testing
Run all unit tests
testing
Run UI tests
testing
Run snapshot tests