agentsclimarketplace

Swift concurrency

Skill pszypowicz/claude-skills/plugins/swift-concurrency/skills/swift-concurrency

A small Claude Code marketplace: ado, swift-concurrency, modern-swift, go-dev, worktrees.

Install
npx -y skills add pszypowicz/claude-skills --skill swift-concurrency

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 0 stars0 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

Diagnose data races, convert callback-based code to async/await, implement actor isolation patterns, resolve Sendable conformance issues, fix @Observable + @MainActor interaction problems, and guide Swift 6 migration. Use when developers mention: (1) Swift Concurrency, async/await, actors, or tasks, (2) "use Swift Concurrency" or "modern concurrency patterns", (3) migrating to Swift 6, (4) data races or thread safety issues, (5) refactoring closures to async/await, (6) @MainActor, Sendable, or actor isolation, (7) @Observable with concurrency or actor isolation, (8) concurrent code architecture or performance optimization, (9) concurrency-related linter warnings (SwiftLint or similar), (10) SwiftUI view model patterns with Observation framework.

SKILL.md

13.1 KB, ~2.9k tokens by cl100k_base, as published. Nobody here has run it

Swift Concurrency

Fast Path

Before proposing a fix:

  1. Analyze Package.swift or .pbxproj to determine Swift language mode, strict concurrency level, default isolation, and upcoming features. Do this always, not only for migration work.
  2. Capture the exact diagnostic and offending symbol.
  3. Determine the isolation boundary: @MainActor, custom actor, actor instance isolation, or nonisolated.
  4. Confirm whether the code is UI-bound or intended to run off the main actor.
  5. Check if @Observable is in play - it changes how isolation inference works on the type.

Project settings that change concurrency behavior:

SettingSwiftPM (Package.swift)Xcode (.pbxproj)
Language modeswiftLanguageVersions or -swift-version (// swift-tools-version: is not a reliable proxy)Swift Language Version
Strict concurrency.enableExperimentalFeature("StrictConcurrency=targeted")SWIFT_STRICT_CONCURRENCY
Default isolation.defaultIsolation(MainActor.self)SWIFT_DEFAULT_ACTOR_ISOLATION
Upcoming features.enableUpcomingFeature("NonisolatedNonsendingByDefault")SWIFT_UPCOMING_FEATURE_*

If any of these are unknown, ask the developer to confirm them before giving migration-sensitive guidance. Do not guess.

Guardrails:

  • Do not recommend @MainActor as a blanket fix. Justify why the code is truly UI-bound.
  • Prefer structured concurrency over unstructured tasks. Use Task.detached only with a clear reason.
  • If recommending @preconcurrency, @unchecked Sendable, or nonisolated(unsafe), require a documented safety invariant and a follow-up removal plan.
  • Optimize for the smallest safe change. Do not refactor unrelated architecture during migration.
  • When @Observable is involved, understand that it does NOT automatically imply @MainActor isolation - the developer must explicitly opt in. Do not conflate the two.

Quick Fix Mode

Use Quick Fix Mode when all of these are true:

  • The issue is localized to one file or one type.
  • The isolation boundary is clear.
  • The fix can be explained in 1-2 behavior-preserving steps.

Skip Quick Fix Mode when any of these are true:

  • Build settings or default isolation are unknown.
  • The issue crosses module boundaries or changes public API behavior.
  • The likely fix depends on unsafe escape hatches.

Common Diagnostics

DiagnosticFirst checkSmallest safe fixEscalate to
Main actor-isolated ... cannot be used from a nonisolated contextIs this truly UI-bound?Isolate the caller to @MainActor or use await MainActor.run { ... } only when main-actor ownership is correct.references/actors.md, references/threading.md
Actor-isolated type does not conform to protocolMust the requirement run on the actor?Prefer isolated conformance (e.g., extension Foo: @MainActor SomeProtocol); use nonisolated only for truly nonisolated requirements.references/actors.md
Sending value of non-Sendable type ... risks causing data racesWhat isolation boundary is being crossed?Keep access inside one actor, or convert the transferred value to an immutable/value type.references/sendable.md, references/threading.md
@Observable class with @MainActor property issuesIs the entire class UI-bound, or just some properties?Apply @MainActor to the whole class if it's a view model; use nonisolated for properties that don't need main actor.references/observable.md
@Observable + async access from backgroundAre you mutating observed properties off the main actor?Route mutations through await MainActor.run {} or isolate the class to @MainActor.references/observable.md
SwiftLint async_without_awaitIs async actually required by protocol, override, or @concurrent?Remove async, or use a narrow suppression with rationale. Never add fake awaits.references/linting.md
wait(...) is unavailable from asynchronous contextsIs this legacy XCTest async waiting?Replace with await fulfillment(of:) or Swift Testing equivalents.references/testing.md
Core Data concurrency warningsAre NSManagedObject instances crossing contexts or actors?Pass NSManagedObjectID or map to a Sendable value type.references/core-data.md
Thread.current unavailable from asynchronous contextsAre you debugging by thread instead of isolation?Reason in terms of isolation and use Instruments/debugger instead.references/threading.md
SwiftLint concurrency-related warningsWhich specific lint rule triggered?Use references/linting.md for rule intent and preferred fixes; avoid dummy awaits.references/linting.md

When Quick Fixes Fail

  1. Gather project settings if not already confirmed.
  2. Re-evaluate which isolation boundaries the type crosses.
  3. Route to the matching reference file for a deeper fix.
  4. If the fix may change behavior, document the invariant and add verification steps.

Smallest Safe Fixes

Prefer changes that preserve behavior while satisfying data-race safety:

  • UI-bound state: isolate the type or member to @MainActor.
  • Shared mutable state: move it behind an actor, or use @MainActor only if the state is UI-owned.
  • Background work: when work must hop off caller isolation, use an async API marked @concurrent; when work can safely inherit caller isolation, use nonisolated without @concurrent.
  • Sendability issues: prefer immutable values and explicit boundaries over @unchecked Sendable.
  • @Observable view models: isolate the entire class to @MainActor when it drives UI; use nonisolated for computed properties or methods that don't touch UI state.

@Observable + @MainActor Quick Guide

This is one of the most common pain points in modern SwiftUI apps. The @Observable macro does NOT infer @MainActor - you must explicitly add it when the class drives UI.

The Core Pattern

// ✅ Correct: @MainActor view model with @Observable
@MainActor @Observable
final class ContentViewModel {
    var items: [Item] = []
    var isLoading = false

    func loadItems() async {
        isLoading = true
        items = await APIClient.fetchItems()
        isLoading = false
    }
}

SwiftUI Integration (Observation framework)

Use @State (not @StateObject) and @Environment (not @EnvironmentObject) with @Observable:

// ✅ Correct Observation-era SwiftUI
struct ContentView: View {
    @State private var viewModel = ContentViewModel()

    var body: some View {
        List(viewModel.items) { item in
            Text(item.name)
        }
        .task { await viewModel.loadItems() }
    }
}

// ✅ Passing via environment
@main
struct MyApp: App {
    @State private var library = Library()

    var body: some Scene {
        WindowGroup {
            LibraryView()
                .environment(library)
        }
    }
}

struct LibraryView: View {
    @Environment(Library.self) private var library

    var body: some View {
        List(library.books) { book in
            BookView(book: book)
        }
    }
}

Bindings with @Bindable

For two-way bindings to @Observable objects, use @Bindable:

struct EditView: View {
    @Bindable var viewModel: ContentViewModel

    var body: some View {
        TextField("Name", text: $viewModel.name)
    }
}

Common Mistakes

// ❌ Missing @MainActor - mutations from async contexts may happen off main thread
@Observable
final class ViewModel {
    var items: [Item] = []  // SwiftUI reads this - must be main-actor-isolated
}

// ❌ Using old ObservableObject patterns with @Observable
@Observable
final class ViewModel: ObservableObject {  // Don't conform to both
    @Published var items: [Item] = []      // @Published is for ObservableObject
}

// ❌ Using @StateObject with @Observable
struct MyView: View {
    @StateObject var vm = ViewModel()  // Use @State instead
}

For the full guide, see references/observable.md.

Concurrency Tool Selection

NeedToolKey Guidance
Single async operationasync/awaitDefault choice for sequential async work
Fixed parallel operationsasync letKnown count at compile time; auto-cancelled on throw
Dynamic parallel operationswithTaskGroupUnknown count; structured - cancels children on scope exit
Sync → async bridgeTask { }Inherits actor context; use Task.detached only with documented reason
Shared mutable stateactorPrefer over locks/queues; keep isolated sections small
UI-bound state@MainActorOnly for truly UI-related code; justify isolation
Observable view model@MainActor @ObservableFor SwiftUI-driving models; use @State not @StateObject

Common Scenarios

Network request with UI update

Task { @concurrent in
    let data = try await fetchData()
    await MainActor.run { self.updateUI(with: data) }
}

Processing array items in parallel

await withTaskGroup(of: ProcessedItem.self) { group in
    for item in items {
        group.addTask { await process(item) }
    }
    for await result in group {
        results.append(result)
    }
}

Swift 6 Migration Quick Guide

Key changes in Swift 6:

  • Strict concurrency checking enabled by default
  • Complete data-race safety at compile time
  • Sendable requirements enforced on boundaries
  • Isolation checking for all async boundaries

Migration Validation Loop

Apply this cycle for each migration change:

  1. Build - Run swift build or Xcode build to surface new diagnostics
  2. Fix - Address one category of error at a time (e.g., all Sendable issues first)
  3. Rebuild - Confirm the fix compiles cleanly before moving on
  4. Test - Run the test suite to catch regressions (swift test or Cmd+U)
  5. Only proceed to the next file/module when all diagnostics are resolved

If a fix introduces new warnings, resolve them before continuing. Never batch multiple unrelated fixes - keep commits small and reviewable.

For detailed migration steps, see references/migration.md.

Reference Router

Open the smallest reference that matches the question:

  • Foundations
    • references/async-await-basics.md - async/await syntax, execution order, async let, URLSession patterns
    • references/tasks.md - Task lifecycle, cancellation, priorities, task groups, structured vs unstructured
    • references/actors.md - Actor isolation, @MainActor, global actors, reentrancy, custom executors, Mutex
    • references/sendable.md - Sendable conformance, value/reference types, @unchecked, region isolation
    • references/threading.md - Execution model, suspension points, Swift 6.2 isolation behavior
  • Observation
    • references/observable.md - @Observable + @MainActor patterns, SwiftUI integration, async access, migration from ObservableObject
  • Streams
    • references/async-sequences.md - AsyncSequence, AsyncStream, when to use vs regular async methods
    • references/async-algorithms.md - Debounce, throttle, merge, combineLatest, channels, timers
  • Applied topics
    • references/testing.md - Swift Testing first, XCTest fallback, leak checks
    • references/performance.md - Profiling with Instruments, reducing suspension points, execution strategies
    • references/memory-management.md - Retain cycles in tasks, memory safety patterns
    • references/core-data.md - NSManagedObject sendability, custom executors, isolation conflicts
  • Migration and tooling
    • references/migration.md - Swift 6 migration strategy, closure-to-async conversion, @preconcurrency, FRP migration
    • references/linting.md - Concurrency-focused lint rules and SwiftLint async_without_await
  • Glossary
    • references/glossary.md - Quick definitions of core concurrency terms

Verification Checklist

When changing concurrency code:

  1. Re-check build settings before interpreting diagnostics.
  2. Build and clear one category of errors before moving on. Do not batch unrelated fixes into the same change.
  3. Run tests, especially actor-, lifetime-, and cancellation-sensitive tests.
  4. Use Instruments for performance claims instead of guessing.
  5. Verify deallocation and cancellation behavior for long-lived tasks.
  6. Check Task.isCancelled in long-running operations.
  7. Never use semaphores or ad hoc locking in async contexts when actor isolation or Mutex would express ownership more safely.
  8. When using @Observable, verify that UI-driving properties are accessed on @MainActor.

What ships with it: 16 files

204.0 KB alongside SKILL.md

Gives 0 of the 12 instructions most performance cost skills give in ~2.9k tokens

Counted across 803 of the 1,058 authors here whose files we hold, read 2026-08-07

  • Keep skill files under 500 lines or tokensin 82 of 803, across 16 files
  • Use imperative form in instructionsin 80 of 803, across 9 files
  • Draft assertions while test runs are in progressin 75 of 803, across 9 files
  • Create two to three realistic test promptsin 74 of 803, across 9 files
  • Write skill descriptions to be pushyin 72 of 803, across 7 files
  • Save test cases to evals JSONin 72 of 803, across 6 files
  • Ask questions about edge cases and input formatsin 72 of 803, across 7 files
  • Save timing data immediately when runs completein 70 of 803, across 5 files
  • Include all trigger conditions in the skill descriptionin 69 of 803, across 3 files
  • Launch all test runs in a single turn or simultaneouslyin 69 of 803, across 3 files
  • Capture intent before writing a skillin 67 of 803, across 1 file
  • Import directly instead of barrel filesin 52 of 803, across 15 files

Said here and by no other author read

  • confirm whether the code is ui-bound
  • check if the observable macro is used
  • require documented safety invariants for unsafe escape hatches
  • resolve new warnings before continuing
  • open the smallest matching reference file for deeper fixes

Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once. Length counted with cl100k_base; the agent that loads this file may tokenize it differently.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.