Swift
When your agent starts coding, you gotta let it cook
npx -y skills add ndisisnd/cook --skill swiftAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 2 stars2 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Swift 6.x language standards and code quality conventions. Use when writing or reviewing any Swift code — optionals, error handling, concurrency (actors, Sendable, @MainActor), value types, protocols and generics, memory management, naming, and access control.
SKILL.md
8.0 KB, as published. Nobody here has run it
Swift Standards
Default load: this file only; pull refs (see References) on demand.
Swift owns language-level correctness only: optionals, errors, concurrency semantics, value/reference types, protocols and generics, ARC, naming, access control. Platform and app-shape concerns — scenes/windows, SwiftUI architecture, sandboxing, distribution, persistence, localization — live in standards/macos/. Universal rules stay in standards/global/.
Scope: these rules apply in full to new targets and modules. In existing code, match established conventions; propose migrations (language mode, ObservableObject → @Observable, deployment targets, dependency swaps) as separate explicit tasks — never as a side effect of a feature change.
Priority: P0 — Language Correctness
Language Mode, Isolation & Concurrency
P0 rules → refs/concurrency.md — load for any concurrency, isolation, or language-mode task.
Availability
- Gate every API newer than the deployment target with
if #available/@availableand a real fallback path. Annotate declarations rather than sprinkling runtime checks. Never raise the deployment target to dodge a check.
Optionals
- Never force-unwrap (
!) or force-cast (as!) in production paths. If non-nil is a true invariant, useguard let x else { preconditionFailure("why") }so failure carries a message. - No implicitly unwrapped optionals (
T!) in new pure-Swift code; acceptable only for UI-lifecycle objects (@IBOutlet) and Obj-C bridging. guard letfor early-exit preconditions (happy path stays unindented);if letfor genuine branching. Use shorthand:if let user,guard let self.- Prefer
??and optional chaining; neverif x != nilfollowed byx!. - Return empty collections, not optional collections, unless nil vs empty is semantically meaningful.
Error Handling
- Untyped
throwsis the default. Typed throws (throws(E)) only for closed error domains in libraries, generic error propagation (a typed alternative torethrows), and measured hot paths — error domains grow, and typed errors become breaking changes. - Never
try!outside tests.try?only when nil is a genuinely acceptable outcome — never to discard an error that matters. Don't returnnilto signal failure — throw. Resultis for storing an error or crossing a non-throwing boundary — not a general replacement forthrows. Convert withResult(catching:)/.get().- Domain errors are enums/structs with associated values; user-facing errors conform to
LocalizedError, separating user message from debug detail. - Use
deferfor cleanup that must run on every exit path, including thrown errors.
Value Types First
- Default to
struct/enum. Useclassonly for identity (===), shared mutable state, deinit-based resource lifetime, or framework/Obj-C interop. - Mark classes
finalunless subclassing is a designed contract. Preferletovervareverywhere. - A struct holding a class reference does not have value semantics — enforce COW or don't pretend. COW mechanics and custom-COW rules →
refs/performance.md.
Memory Management
P0 rules → refs/memory-management.md — load when writing delegates, stored closures, timers, or long-lived tasks.
Protocols & Generics
- Prefer, in order: concrete types →
some(opaque/generics) →any(existentials). Neveranywheresomecompiles. - Use primary associated types (
some Collection<String>) to constrain opaque and existential types. - Constrain generic parameters as tightly as the implementation needs (
<T: Equatable>), never an unconstrained<T>that force-casts internally. - Don't extract a protocol until there are ≥2 real conformers or a genuine test seam; struct-of-closures dependencies are a valid alternative for seams.
- Protocol-extension methods that aren't requirements are statically dispatched — declare customization points as protocol requirements.
Enums & Type Safety
- Switch exhaustively over your own enums — avoid
defaultso the compiler flags new cases;@unknown defaultfor non-frozen SDK enums. - No stringly-typed APIs: enums,
Notification.Nameconstants, key paths, and typed wrappers over raw strings/dictionaries. NoAny/AnyObjectpayloads crossing module boundaries. - Codable: synthesized conformance +
CodingKeys; set strategies on the encoder/decoder, don't hand-write keys; manualinit(from:)only for versioned/polymorphic payloads; keep wire DTOs separate from domain models; never force-decode data crossing a trust boundary (network, user files, IPC) — compile-time-bundled resources may instead fail fast with a message.
Access Control
- Least access first:
private→internal→package(cross-module within a package) →public/open(openonly when external subclassing is a supported contract). private(set)for externally-read-only state. Avoidfileprivate.- Library code: explicit access modifier and
///doc comment on every public declaration.
Priority: P1 — Style & Conventions
P1 rules → refs/language-conventions.md — load when authoring APIs or reviewing naming/structure/style.
Anti-Patterns
!,as!,try!outside tests; IUO stored properties in new codetry?to discard errors that matter; returningnilto signal failureDispatchQueue.main.async/ semaphores / GCD state-queues inside async codeTask.detachedas a habit; fire-and-forgetTask {}sprawl with no cancellation@unchecked Sendable/nonisolated(unsafe)without a lock and a justification comment- Blanket
[weak self]everywhere — or missing it on stored/long-running closures unownedwhere lifetime is not provable;unowned(unsafe)ever- Actors wrapping trivial state; check-then-mutate split across
await - Introducing Combine in new code; mixing Combine and structured concurrency in one flow
- Protocols with one conformer;
anywheresomecompiles; unconstrained<T>that force-casts internally - Non-
finalclasses with no subclassing design;classwhere astructwould do - Stringly-typed identifiers;
Anyin public signatures; dictionary-shaped models - God singletons (
Shared.instanceservice locators) — initializer/environment injection;static let sharedonly for stateless system facades (URLSession.shared) NotificationCenteras an app-internal event bus- Unguarded use of APIs newer than the deployment target
print()/NSLogin production — useos.Loggerwith privacy annotations
References
Load only what the task requires:
- concurrency — P0 concurrency + isolation rules, Swift 6 migration, actors/reentrancy, Sendable, tasks, AsyncStream, continuations
- memory-management — P0 ARC rules, weak/unowned, retain-cycle sources, leak diagnosis
- language-conventions — P1 naming (API Design Guidelines) and structure/style conventions
- testing — Swift Testing, XCTest boundaries, fakes, async test patterns
- tooling — SwiftLint, swift-format, SPM hygiene, build settings, CI ordering
- performance — existential boxing, ARC traffic, COW, collection costs, Instruments
- interop — C/Obj-C/CF ownership, pointer lifetimes,
@objcdiscipline, KVO