
swift-ecosystem
by takeokunn
takeokunn's nixos-configuration
SKILL.md
name: Swift Ecosystem description: This skill should be used when working with Swift projects, "Package.swift", "swift build/test/run", "swiftc", SwiftLint, SwiftFormat, or Swift language patterns. Provides comprehensive Swift ecosystem patterns and best practices for cross-platform CLI and library development. version: 0.1.0
<swift_language> <type_system> Structs and enums are value types (copied); classes are reference types (shared) Prefer structs for data models without identity Use classes only when reference semantics or inheritance is required Enums with associated values for algebraic data types
<concept name="optionals">
<description>Swift's nil-safety through Optional type</description>
<pattern name="safe_unwrapping">
<example>
// if-let binding
if let value = optionalValue {
use(value)
}
// guard-let for early exit
guard let value = optionalValue else { return }
// nil-coalescing
let value = optionalValue ?? defaultValue
// optional chaining
let result = object?.property?.method()
</example>
</pattern>
<anti_pattern name="force_unwrap">
<description>Using ! to force unwrap optionals</description>
<instead>Use if-let, guard-let, or ?? instead of force unwrapping</instead>
</anti_pattern>
</concept>
<concept name="protocols">
<description>Define behavior contracts for types</description>
<pattern name="protocol_oriented">
<description>Prefer composition with protocols over class inheritance</description>
<example>
protocol Identifiable {
var id: String { get }
}
protocol Timestamped {
var createdAt: Date { get }
}
struct User: Identifiable, Timestamped {
let id: String
let createdAt: Date
let name: String
}
</example>
</pattern>
<pattern name="protocol_extensions">
<description>Provide default implementations via extensions</description>
<example>
protocol Describable {
var description: String { get }
}
extension Describable {
var description: String {
String(describing: self)
}
}
</example>
</pattern>
</concept>
<concept name="generics">
<description>Type-safe reusable code with type parameters</description>
<pattern name="generic_constraints">
<example>
func process<T: Codable & Sendable>(_ item: T) -> Data {
try! JSONEncoder().encode(item)
}
func compare<T>(_ a: T, _ b: T) -> Bool where T: Comparable {
a < b
}
</example>
</pattern>
</concept>
<concept name="noncopyable">
<description>Types with unique ownership using ~Copyable (Swift 6+)</description>
<example>
struct UniqueResource: ~Copyable {
consuming func release() { /* takes ownership */ }
}
func process(borrowing data: SomeData) { /* read-only */ }
func consume(consuming data: SomeData) { /* takes ownership */ }
</example>
<rules priority="critical">
<rule>Use for resources requiring unique ownership (file handles, locks)</rule>
<rule>Mark methods with borrowing/consuming for explicit ownership</rule>
</rules>
</concept>
</type_system>
<error_handling> Use throws for recoverable errors enum ParseError: Error { case invalidFormat case missingField(String) }
func parse(_input: String) throws -> Config {
guard !input.isEmpty else {
throw ParseError.invalidFormat
}
// parsing logic
}
// Calling
do {
let config = try parse(input)
} catch ParseError.invalidFormat {
// handle specific error
} catch {
// handle other errors
}
</example>
</pattern>
<pattern name="result_type">
<description>Use Result for async error handling or when throws is inconvenient</description>
<example>
func fetch(url: URL) -> Result<Data, NetworkError> {
// implementation
}
switch fetch(url: someURL) {
case .success(let data):
process(data)
case .failure(let error):
handle(error)
}
</example>
</pattern>
<pattern name="typed_throws">
<description>Specify exact error type in function signature (Swift 6+)</description>
<example>
func parse(_ input: String) throws(ParseError) -> Config {
guard !input.isEmpty else { throw ParseError.invalidFormat }
// parsing logic
}
// Caller knows exactly which errors to handle
do {
let config = try parse(input)
} catch {
// error is typed as ParseError, not any Error
switch error {
case .invalidFormat: handleInvalidFormat()
case .missingField(let name): handleMissing(name)
}
}
</example>
</pattern>
</error_handling>
// Calling
Task {
do {
let data = try await fetchData()
} catch {
// handle error
}
}
</example>
</pattern>
<pattern name="actors">
<description>Thread-safe mutable state with actors</description>
<example>
actor Counter {
private var value = 0
func increment() {
value += 1
}
func getValue() -> Int {
value
}
}
let counter = Counter()
await counter.increment()
let value = await counter.getValue()
</example>
</pattern>
<pattern name="sendable">
<description>Mark types safe for concurrent access</description>
<example>
// Implicitly Sendable (value types with Sendable properties)
struct Config: Sendable {
let timeout: Int
let retries: Int
}
// Explicitly mark as Sendable
final class ImmutableCache: Sendable {
let data: [String: String]
init(data: [String: String]) {
self.data = data
}
}
</example>
</pattern>
<pattern name="task_groups">
<description>Parallel execution with structured concurrency</description>
<example>
func processAll(_ items: [Item]) async throws -> [Result] {
try await withThrowingTaskGroup(of: Result.self) { group in
for item in items {
group.addTask {
try await process(item)
}
}
return try await group.reduce(into: []) { $0.append($1) }
}
}
</example>
</pattern>
<rules priority="critical">
<rule>Use async/await over completion handlers for new code</rule>
<rule>Use actors for shared mutable state instead of locks</rule>
<rule>Mark types as Sendable when they cross concurrency boundaries</rule>
</rules>
<memory_management> Prevent retain cycles in closures and delegates class Controller { var onComplete: (() -> Void)?
func setup() {
service.fetch { [weak self] result in
self?.handleResult(result)
}
}
}
</example>
</pattern>
<pattern name="unowned_references">
<description>Non-optional weak reference when lifetime is guaranteed</description>
<example>
class Parent {
var child: Child?
}
class Child {
unowned let parent: Parent
init(parent: Parent) {
self.parent = parent
}
}
</example>
</pattern>
<rules priority="critical">
<rule>Always use [weak self] in escaping closures unless self lifetime is guaranteed</rule>
<rule>Use unowned only when you can guarantee the referenced object outlives the closure</rule>
</rules>
</memory_management>
<common_patterns> Fluent API for complex object construction struct RequestBuilder { private var method: String = "GET" private var headers: [String: String] = [:]
func method(_ m: String) -> RequestBuilder {
var copy = self
copy.method = m
return copy
}
func header(_ key: String, _ value: String) -> RequestBuilder {
var copy = self
copy.headers[key] = value
return copy
}
func build() -> Request {
Request(method: method, headers: headers)
}
}
</example>
</pattern>
<pattern name="result_builder">
<description>DSL construction with @resultBuilder</description>
<example>
@resultBuilder
struct ArrayBuilder<Element> {
static func buildBlock(_ components: Element...) -> [Element] {
components
}
}
func buildArray<T>(@ArrayBuilder<T> _content: () -> [T]) -> [T] {
content()
}
</example>
</pattern>
<pattern name="property_wrappers">
<description>Encapsulate property access patterns</description>
<example>
@propertyWrapper
struct Clamped<Value: Comparable> {
private var value: Value
private let range: ClosedRange<Value>
var wrappedValue: Value {
get { value }
set { value = min(max(newValue, range.lowerBound), range.upperBound) }
}
init(wrappedValue: Value, _ range: ClosedRange<Value>) {
self.range = range
self.value = min(max(wrappedValue, range.lowerBound), range.upperBound)
}
}
struct Volume {
@Clamped(0...100) var level: Int = 50
}
</example>
</pattern>
</common_patterns>
<anti_patterns> Using ! to force unwrap optionals Use if-let, guard-let, or nil-coalescing
<avoid name="force_try">
<description>Using try! to ignore errors</description>
<instead>Use do-catch or propagate with throws</instead>
</avoid>
<avoid name="class_for_data">
<description>Using class for simple data containers</description>
<instead>Use struct for value semantics</instead>
</avoid>
<avoid name="any_abuse">
<description>Overusing Any or AnyObject types</description>
<instead>Use generics or protocols with associated types</instead>
</avoid>
<avoid name="retain_cycles">
<description>Strong reference cycles in closures</description>
<instead>Use [weak self] or [unowned self] capture lists</instead>
</avoid>
</anti_patterns> </swift_language>
<decision_tree name="package_type"> What are you building? Library (.library product) Executable (.executable product) Multiple products with shared target </decision_tree>
<decision_tree name="reference_type_choice"> What is the relationship between objects? Use strong reference Use weak reference Use unowned reference </decision_tree>
<decision_tree name="type_choice"> What kind of type do you need? Use struct (value type) Use class (reference type) or actor Use enum with associated values Use ~Copyable struct (Swift 6+) </decision_tree>
<swift_package_manager> <project_structure> <standard_layout> . ├── Package.swift ├── Package.resolved ├── Sources/ │ ├── MyLibrary/ │ │ └── MyLibrary.swift │ └── MyCLI/ │ └── main.swift ├── Tests/ │ └── MyLibraryTests/ │ └── MyLibraryTests.swift └── Plugins/ └── MyPlugin/ └── plugin.swift </standard_layout>
<module_organization>
<pattern name="single_target">
<description>Simple library or executable</description>
</pattern>
<pattern name="multi_target">
<description>Library with CLI tool or multiple modules</description>
</pattern>
</module_organization>
</project_structure>
<package_swift> <basic_structure> // swift-tools-version: 6.0 import PackageDescription
// For cross-platform (macOS + Linux), omit platforms array entirely
// Only specify platforms when using platform-specific APIs
let package = Package(
name: "MyPackage",
platforms: [
.macOS(.v14)
],
products: [
.library(
name: "MyLibrary",
targets: ["MyLibrary"]
),
.executable(
name: "my-cli",
targets: ["MyCLI"]
)
],
dependencies: [
.package(url: "https://github.com/apple/swift-argument-parser", from: "1.5.0"),
.package(url: "https://github.com/apple/swift-log", from: "1.6.0")
],
targets: [
.target(
name: "MyLibrary",
dependencies: [
.product(name: "Logging", package: "swift-log")
]
),
.executableTarget(
name: "MyCLI",
dependencies: [
"MyLibrary",
.product(name: "ArgumentParser", package: "swift-argument-parser")
]
),
.testTarget(
name: "MyLibraryTests",
dependencies: ["MyLibrary"]
)
]
)
</basic_structure>
<dependency_specification>
// Exact version
.package(url: "...", exact: "1.2.3")
// Version range
.package(url: "...", from: "1.0.0") // 1.0.0 ..< 2.0.0
.package(url: "...", "1.0.0"..<"2.0.0")
// Branch or revision
.package(url: "...", branch: "main")
.package(url: "...", revision: "abc123")
// Local package
.package(path: "../LocalPackage")
</dependency_specification>
<swift_settings>
.target(
name: "MyTarget",
swiftSettings: [
.enableUpcomingFeature("StrictConcurrency"),
.enableExperimentalFeature("AccessLevelOnImport"),
.unsafeFlags(["-warnings-as-errors"], .when(configuration: .release))
]
)
</swift_settings>
</package_swift>
<configuration>
<file_reference>.swiftlint.yml</file_reference>
disabled_rules:
- trailing_whitespace
- line_length
opt_in_rules:
- empty_count
- closure_spacing
- force_unwrapping
included:
- Sources
- Tests
excluded:
- .build
- Packages
line_length:
warning: 120
error: 200
type_body_length:
warning: 300
error: 500
file_length:
warning: 500
error: 1000
</configuration>
<common_rules>
<rule name="force_unwrapping">Disallow force unwrapping with !</rule>
<rule name="force_try">Disallow force try with try!</rule>
<rule name="force_cast">Disallow force casting with as!</rule>
<rule name="empty_count">Prefer isEmpty over count == 0</rule>
<rule name="closure_spacing">Ensure spacing in closures</rule>
</common_rules>
<configuration>
<file_reference>.swiftformat</file_reference>
--swiftversion 6.0
--indent 4
--indentcase false
--trimwhitespace always
--voidtype void
--wraparguments before-first
--wrapcollections before-first
--maxwidth 120
--self remove
--importgrouping testable-last
--semicolons never
--commas always
</configuration>
<common_options>
<option name="--swiftversion">Target Swift version</option>
<option name="--indent">Indentation width (default: 4)</option>
<option name="--maxwidth">Maximum line width</option>
<option name="--self">Self keyword insertion (remove/insert)</option>
<option name="--wraparguments">Argument wrapping style</option>
</common_options>
<sourcekit_lsp> Language server for IDE integration Bundled with Swift toolchain
<vscode_setup>
<step>Install Swift extension (official)</step>
<step>Extension uses SourceKit-LSP automatically</step>
<step>Run swift build to generate index</step>
</vscode_setup>
<features>
<feature>Code completion</feature>
<feature>Jump to definition</feature>
<feature>Find references</feature>
<feature>Diagnostics</feature>
<feature>Code actions</feature>
</features>
</sourcekit_lsp>
<other_tools> Modern testing framework (Swift 6+) import Testing
@Test func addition() {
#expect(1 + 1 == 2)
}
@Test("Descriptive name")
func subtraction() throws {
let result = try compute()
#expect(result > 0)
}
</example>
</tool>
<tool name="swift-format">
<description>Apple's official formatter (alternative to SwiftFormat)</description>
<note>Built into Xcode 16; use swift-format command</note>
</tool>
<tool name="swift-docc">
<description>Documentation compiler for Swift</description>
<usage>swift package generate-documentation</usage>
</tool>
</other_tools>
<pattern name="basic_test">
<example>
import Testing
@Test func addition() {
#expect(1 + 1 == 2)
}
@Test("Descriptive name")
func subtraction() throws {
let result = try compute()
#expect(result > 0)
}
</example>
</pattern>
<pattern name="parameterized_test">
<example>
@Test(arguments: [1, 2, 3])
func multipleInputs(value: Int) {
#expect(value > 0)
}
</example>
</pattern>
<pattern name="test_suite">
<example>
@Suite("Calculator Tests")
struct CalculatorTests {
@Test func add() { #expect(1 + 1 == 2) }
@Test func multiply() { #expect(2 * 3 == 6) }
}
</example>
</pattern>
<pattern name="async_test">
<example>
@Test func fetchData() async throws {
let data = try await service.fetch()
#expect(!data.isEmpty)
}
</example>
</pattern>
<note>swift-testing does not yet support performance testing or UI testing</note>
</swift_testing>
<migration>
<step>Replace XCTAssert with #expect</step>
<step>Replace XCTAssertEqual with #expect(a == b)</step>
<step>Replace XCTestCase class with @Test functions</step>
<step>Use @Suite for test grouping</step>
</migration>
<best_practices> Use swift-testing for new test code Organize tests in Tests/ directory with TestTarget suffix Use @Test for individual test functions Use @Suite for grouping related tests Use parameterized tests for testing multiple inputs </best_practices>
<context7_integration> Use Context7 MCP for up-to-date Swift documentation
<swift_libraries> </swift_libraries>
<usage_patterns> resolve-library-id libraryName="swift" get-library-docs context7CompatibleLibraryID="/swiftlang/swift" topic="concurrency"
<pattern name="package_configuration">
<step>get-library-docs context7CompatibleLibraryID="/swiftlang/swift" topic="Package.swift"</step>
</pattern>
<pattern name="library_usage">
<step>get-library-docs context7CompatibleLibraryID="/alamofire/alamofire" topic="request"</step>
</pattern>
</usage_patterns> </context7_integration>
<best_practices> Use swift build for compilation; swift test for testing Run swiftlint before committing Format with swiftformat for consistent style Prefer value types (structs) over reference types (classes) Use async/await for asynchronous code Mark types as Sendable for concurrency safety Document public API with /// doc comments Write tests alongside implementation Use Swift Testing framework for new test code Specify swift-tools-version in Package.swift </best_practices>
<error_escalation> SwiftLint warning about style Fix warning, maintain idiomatic code Type safety error or optional handling issue Redesign with proper types, use safe unwrapping Breaking change in public API Stop, present migration options to user Force unwrap or unsafe code in library Block operation, require safe alternatives </error_escalation>
<related_skills> Navigate protocol implementations and module structure Fetch Swift language and library documentation Debug type errors, optional handling, and concurrency issues </related_skills>
Score
Total Score
Based on repository quality metrics
SKILL.mdファイルが含まれている
ライセンスが設定されている
100文字以上の説明がある
GitHub Stars 100以上
1ヶ月以内に更新
10回以上フォークされている
オープンIssueが50未満
プログラミング言語が設定されている
1つ以上のタグが設定されている
Reviews
Reviews coming soon


