Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Review and fix Swift concurrency issues such as actor isolation and Sendable violations.
.claude/skills/davila7-swift-concurrency-expert/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-02 | ✗→✓ | ▲ Improved | 29% | 0% |
| case-04 | ✗→✓ | ▲ Improved | 20% | 0% |
| case-20 | ✗→✓ | ▲ Improved | 26% | 0% |
| case-01 | ✓→✓ | = Same ✓ | 6% | 0% |
| case-03 | ✓→✓ | = Same ✓ | 13% | 0% |
Review and fix Swift Concurrency issues in Swift 6.2+ codebases by applying actor isolation, Sendable safety, and modern concurrency patterns with minimal behavior changes.
Sendable, @MainActor, or async migration.@MainActor, actor, nonisolated) and whether a default actor isolation mode is enabled.Prefer edits that preserve existing behavior while satisfying data-race safety.
Common fixes:
@MainActor.extension Foo: @MainActor SomeProtocol).@MainActor or move into an actor.@concurrent async function on a nonisolated type or use an actor to guard mutable state.Sendable conformance only when correct; avoid @unchecked Sendable unless you can prove thread safety.UI-bound type — adding @MainActor
swift// Before: data-race warning because ViewModel is accessed from the main thread // but has no actor isolation class ViewModel: ObservableObject { @Published var title: String = "" func load() { title = "Loaded" } } // After: annotate the whole type so all stored state and methods are // automatically isolated to the main actor @MainActor class ViewModel: ObservableObject { @Published var title: String = "" func load() { title = "Loaded" } }
Protocol conformance isolation
swift// Before: compiler error — SomeProtocol method is nonisolated but the // conforming type is @MainActor @MainActor class Foo: SomeProtocol { func protocolMethod() { /* accesses main-actor state */ } } // After: scope the conformance to @MainActor so the requirement is // satisfied inside the correct isolation context @MainActor extension Foo: SomeProtocol { func protocolMethod() { /* safely accesses main-actor state */ } }
Background work with @concurrent
swift// Before: expensive computation blocks the main actor @MainActor func processData(_ input: [Int]) -> [Int] { input.map { heavyTransform($0) } // runs on main thread } // After: hop off the main actor for the heavy work, then return the result // The caller awaits the result and stays on its own actor nonisolated func processData(_ input: [Int]) async -> [Int] { await Task.detached(priority: .userInitiated) { input.map { heavyTransform($0) } }.value } // Or, using a @concurrent async function (Swift 6.2+): @concurrent func processData(_ input: [Int]) async -> [Int] { input.map { heavyTransform($0) } }
references/swift-6-2-concurrency.md for Swift 6.2 changes, patterns, and examples.references/approachable-concurrency.md when the project is opted into approachable concurrency mode.references/swiftui-concurrency-tour-wwdc.md for SwiftUI-specific concurrency guidance.| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | pass→pass | 10,367 | 5,450 | -47% | 1 | 1 | 0% | 1,968 | 2,085 | +6% | 0 | 0 | — |
case-02 | fail→pass | 11,741 | 10,508 | -11% | 1 | 1 | 0% | 2,347 | 3,026 | +29% | 0 | 0 | — |
case-03 | pass→pass | 7,341 | 3,029 | -59% | 1 | 1 | 0% | 1,350 | 1,530 | +13% | 0 | 0 | — |
case-04 | fail→pass | 11,597 | 7,779 | -33% | 1 | 1 | 0% | 2,118 | 2,536 | +20% | 0 | 0 | — |
case-05 | pass→pass | 9,364 | 4,915 | -48% | 1 | 1 | 0% | 1,758 | 1,967 | +12% | 0 | 0 | — |
case-06 | pass→pass | 11,921 | 8,528 | -28% | 1 | 1 | 0% | 2,074 | 2,541 | +23% | 0 | 0 | — |
case-07 | pass→pass | 4,633 | 4,907 | +6% | 1 | 1 | 0% | 902 | 1,957 | +117% | 0 | 0 | — |
case-08 | pass→pass | 12,204 | 10,232 | -16% | 1 | 1 | 0% | 2,566 | 3,023 | +18% | 0 | 0 | — |
case-09 | pass→pass | 5,859 | 4,404 | -25% | 1 | 1 | 0% | 1,311 | 1,840 | +40% | 0 | 0 | — |
case-10 | pass→pass | 8,359 | 5,910 | -29% | 1 | 1 | 0% | 1,591 | 2,042 | +28% | 0 | 0 | — |
case-11 | pass→pass | 3,396 | 3,553 | +5% | 1 | 1 | 0% | 570 | 1,529 | +168% | 0 | 0 | — |
case-12 | pass→pass | 9,069 | 7,365 | -19% | 1 | 1 | 0% | 1,621 | 2,286 | +41% | 0 | 0 | — |
case-13 | pass→pass | 3,469 | 2,510 | -28% | 1 | 1 | 0% | 595 | 1,434 | +141% | 0 | 0 | — |
case-14 | pass→pass | 4,969 | 4,457 | -10% | 1 | 1 | 0% | 962 | 1,746 | +81% | 0 | 0 | — |
case-15 | pass→pass | 8,194 | 3,986 | -51% | 1 | 1 | 0% | 1,424 | 1,628 | +14% | 0 | 0 | — |
case-16 | pass→pass | 4,010 | 2,886 | -28% | 1 | 1 | 0% | 671 | 1,460 | +118% | 0 | 0 | — |
case-17 | pass→pass | 6,242 | 4,476 | -28% | 1 | 1 | 0% | 1,166 | 1,840 | +58% | 0 | 0 | — |
case-18 | pass→pass | 4,523 | 3,627 | -20% | 1 | 1 | 0% | 738 | 1,532 | +108% | 0 | 0 | — |
case-19 | pass→pass | 3,856 | 4,619 | +20% | 1 | 1 | 0% | 773 | 1,877 | +143% | 0 | 0 | — |
case-20 | fail→pass | 12,428 | 11,661 | -6% | 1 | 1 | 0% | 2,482 | 3,130 | +26% | 0 | 0 | — |
case-21 | pass→pass | 17,958 | 6,010 | -67% | 1 | 1 | 0% | 3,021 | 2,023 | -33% | 0 | 0 | — |
case-22 | pass→pass | 7,002 | 6,674 | -5% | 1 | 1 | 0% | 1,285 | 2,182 | +70% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +14 percentage points is the difference between those two pass rates over the 22 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.