npx claudepluginhub charleswiltgen/axiom --plugin axiomThis skill uses the workspace's default tool permissions.
Claude frequently generates outdated Swift patterns from its training data. This skill corrects the most common ones — patterns that compile fine but use legacy APIs when modern equivalents are clearer, more efficient, or more correct.
Provides Ktor server patterns for routing DSL, plugins (auth, CORS, serialization), Koin DI, WebSockets, services, and testApplication testing.
Conducts multi-source web research with firecrawl and exa MCPs: searches, scrapes pages, synthesizes cited reports. For deep dives, competitive analysis, tech evaluations, or due diligence.
Provides demand forecasting, safety stock optimization, replenishment planning, and promotional lift estimation for multi-location retailers managing 300-800 SKUs.
Claude frequently generates outdated Swift patterns from its training data. This skill corrects the most common ones — patterns that compile fine but use legacy APIs when modern equivalents are clearer, more efficient, or more correct.
Philosophy: "Don't repeat what LLMs already know — focus on edge cases, surprises, soft deprecations." (Paul Hudson)
| Old Pattern | Modern Swift | Since | Why |
|---|---|---|---|
Date() | Date.now | 5.6 | Clearer intent |
filter { }.count | count(where:) | 5.0 | Single pass, no intermediate allocation |
replacingOccurrences(of:with:) | replacing(_:with:) | 5.7 | Swift native, no Foundation bridge |
CGFloat | Double | 5.5 | Implicit bridging; exceptions: optionals, inout, ObjC-bridged APIs |
Task.sleep(nanoseconds:) | Task.sleep(for: .seconds(1)) | 5.7 | Type-safe Duration API |
DateFormatter() | .formatted() / FormatStyle | 5.5 | No instance management, localizable by default |
String(format: "%.2f", val) | val.formatted(.number.precision(.fractionLength(2))) | 5.5 | Type-safe, localized |
localizedCaseInsensitiveContains() | localizedStandardContains() | 5.0 | Handles diacritics, ligatures, width variants |
"\(firstName) \(lastName)" | PersonNameComponents with .formatted() | 5.5 | Respects locale name ordering |
"yyyy-MM-dd" with DateFormatter | try Date(string, strategy: .iso8601) | 5.6 | Modern parsing (throws); use "y" not "yyyy" for display |
contains() on user input | localizedStandardContains() | 5.0 | Required for correct text search/filtering |
| Old Pattern | Modern Swift | Since |
|---|---|---|
if let value = value { | if let value { | 5.7 |
Explicit return in single-expression | Omit return; if/switch are expressions | 5.9 |
Circle() in modifiers | .circle (static member lookup) | 5.5 |
import UIKit alongside import SwiftUI | Often not needed — SwiftUI re-exports most UIKit/AppKit types. Retain for UIKit-only APIs (UIApplication, etc.) | 5.5 |
| Old Pattern | Modern Foundation | Since |
|---|---|---|
FileManager.default.urls(for: .documentDirectory, ...) | URL.documentsDirectory | 5.7 |
url.appendingPathComponent("file") | url.appending(path: "file") | 5.7 |
books.sorted { $0.author < $1.author } (repeated) | Conform to Comparable, call .sorted() | — |
"yyyy" in date format for display | "y" — correct in all calendar systems | — |
ContentUnavailableView.search(text: searchText) (iOS 17+) automatically includes the search term — no need to compose a custom stringLabeledContent in Forms (iOS 16+) provides consistent label alignment without manual HStack layoutconfirmationDialog() must attach to triggering UI — Liquid Glass morphing animations depend on the source elementWrite Swift 6.3-first code, not Swift 5-era code. These defaults apply to ALL new Swift code, not just when concurrency errors appear.
| Default | Rationale |
|---|---|
| Assume strict concurrency and MainActor default isolation for app/UI modules | Swift 6.3 language mode; Xcode 26+ default for new projects |
| Prefer async/await over GCD, DispatchGroup, and callback pyramids | GCD is a bridge pattern for legacy APIs, not default architecture |
Async does not mean background — use @concurrent (Swift 6.2+) to force off-main | Async functions resume on the same actor they were called from |
Prefer structured concurrency (async let, TaskGroup) over unstructured Task {} | Structured tasks propagate cancellation and errors automatically |
Do not use Task.detached unless there is a specific, stated reason | Loses actor context, priority, and task-local values |
| Prefer Sendable structs/enums for data that crosses actor boundaries | Value types are inherently safe to share |
| Use actors only for truly shared mutable state across concurrency domains | Don't make every class an actor — UI code stays @MainActor |
Treat @unchecked Sendable, @preconcurrency, nonisolated(unsafe) as temporary bridge tools | Each should have a removal ticket, not be permanent |
| Do not add escape hatches just to silence compiler errors | They hide data races that crash in production |
For detailed patterns, decision trees, and error-specific guidance, see axiom-swift-concurrency.
These patterns appear frequently in Claude-generated code:
DateFormatter instances inline — Use .formatted() or FormatStyle instead. If a formatter must exist, make it static let.DispatchQueue.main.async — Use @MainActor or MainActor.run. GCD is a bridge pattern, not a default.DispatchQueue.global().async for background work — Use @concurrent (Swift 6.2+) or extract to an actor.Task.detached to "make it background" — Use @concurrent. Task.detached loses actor context.CGFloat for SwiftUI parameters — Double works everywhere since Swift 5.5 implicit bridging.guard let x = x else — Use guard let x else shorthand.return.Task {} in loops — Use TaskGroup for dynamic parallel work.@unchecked Sendable to silence warnings — Convert to actor or proper Sendable type.Skills: axiom-swift-performance, axiom-swift-concurrency, axiom-swiftui-architecture