swift-concurrency
Skill0 starsChanged 2 months agoMITView on GitHub
Load this whenever Swift concurrency code is being written, fixed, migrated, or reviewed. Diagnoses and fixes Swift Concurrency issues (tasks, actors, @MainActor, Sendable, data races, thread safety, concurrency-related compiler and linter warnings), refactors callback-based code to async/await, guides Swift 6/6.2 migration, AND reviews Swift code for concurrency correctness, modern API usage, and async/await pitfalls. If the code touches `async`, `await`, `actor`, `Task`, `Sendable`, or a strict-concurrency diagnostic, check here first — don't guess at isolation rules from memory.
25 other projects use a version of this, 14 of them edited.
Adopted by
Most recently taken up by
- tornikegomareli/Skillsedited, first seen Nov 8, 2026
- uinaf/slopwakeedited, first seen Nov 3, 2026
- igorkulman/pi-skillstheir own version, first seen Nov 1, 2026
- VelimirMueller/claude-skillsedited, first seen Nov 1, 2026
- VelimirMueller/ai-development-skillsedited, first seen Nov 1, 2026
- The-Artificer-of-Ciphers-LLC/skills-from-the-artificeredited, first seen Nov 1, 2026
Used with
Projects with it also use swiftdata, swiftui-expert-skill and 9 more.
Other files people use alongside this one.
Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
Prisma-Labs-DevSkillswiftdata
API reference: SwiftData. Query for @Model, ModelContext, @Query, schema migrations.
Also in 3 projects that use this
xfstudioSkillswiftui-expert-skill
Write, review, or improve SwiftUI code following best practices for state management, view composition, performance, modern APIs, Swift concurrency, and iOS 26+ Liquid Glass adoption. Use when building new SwiftUI features, refactoring existing views, reviewing code quality, or adopting modern SwiftUI patterns.
Also in 8 projects that use this
eugenepyvovarovSkillswift-concurrency-expert
Swift Concurrency review and remediation for Swift 6.2+. Use when asked to review Swift Concurrency usage, improve concurrency compliance, or fix Swift concurrency compiler errors in a feature or file.
Also in 4 projects that use this
AvdLeeSkillswift-testing-expert
Expert guidance for Swift Testing: test structure, #expect/#require macros, traits and tags, parameterized tests, test plans, parallel execution, async waiting patterns, and XCTest migration. Use when writing new Swift tests, modernizing XCTest suites, debugging flaky tests, or improving test quality and maintainability in Apple-platform or Swift server projects.
Also in 3 projects that use this
dadederkSkillios-accessibility
Expert guidance on iOS accessibility best practices, patterns, and implementation. Use when developers mention: (1) iOS accessibility, VoiceOver, Dynamic Type, or assistive technologies, (2) accessibility labels, traits, hints, or values, (3) automated accessibility testing, auditing, or manual testing, (4) Switch Control, Voice Control, or Full Keyboard Access, (5) inclusive design or accessibility culture, (6) making apps work for users with disabilities.
Also in 3 projects that use this
twostrawsSkillswiftdata-pro
Writes, reviews, and improves SwiftData code using modern APIs and best practices. Use when reading, writing, or reviewing projects that use SwiftData.
Also in 3 projects that use this
Other versions25 projects use a version of this.
Word for word · 0
None found.
Edited · 14
- Provenance-Emu/Provenance★ 6.4k87% same
- pluk-inc/markdown-preview★ 2.8k94% same
- pluk-inc/md-preview.app★ 2.8k94% same
- AvdLee/Swift-Concurrency-Agent-Skill★ 1.7k92% same
- AFK-surf/OpenBridge★ 43018% same
- nonameplum/agent-skills★ 1718% same
- VelimirMueller/ai-development-skills★ 792% same
- VelimirMueller/claude-skills★ 792% same
- The-Artificer-of-Ciphers-LLC/skills-from-the-artificer★ 694% same
- tornikegomareli/Skills★ 294% same
4 more not listed
Wrote their own version · 11
- Prisma-Labs-Dev/apple-skills★ 336same name
- jamesrochabrun/skills★ 209same name
- pepicrft/fuckingapproachableswiftconcurrency★ 156same name
- wendylabsinc/claude-skills★ 62same name
- rusel95/ios-agent-skills★ 13same name
- pluginagentmarketplace/custom-plugin-swift★ 9same name
- thienqo/ios-skills★ 4same name
- igorkulman/pi-skills★ 3same name
- piemonte/skills★ 1same name
- apexbymanish/claude-ai-agents-ios★ 0same name
1 more not listed
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository21 other files it gives its agents.
- animateSkill
- composable-architectureSkill
- find-animation-opportunitiesSkill
- generating-swift-package-docsSkill
- hapticsSkill
- improve-animationsSkill
- ios-26-platformSkill
- ios-higSkill
- ios-simulator-skillSkill
- localizationSkill
- review-animationsSkill
- spm-build-analysisSkill
- storekitSkill
- swift-dataSkill
- swift-diagnosticsSkill
- swift-networkingSkill
- swift-styleSkill
- swift-testingSkill
- swiftuiSkill
- write-swiftSkill
- xcode-buildSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
26 rules. 0 are common, 12 are distinctive, and 14 are very specific to this project.
0
Common
Most of the 24 edited versions we read keep these.
12
Distinctive
This author's own choices. Worth a look.
14
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 11
Before proposing a fix:
- Very specific: line 34
Do not recommend @MainActor as a blanket fix.
- Very specific: line 35
Prefer structured concurrency over unstructured tasks.
- Distinctive: line 36
Prefer async/await over a closure-based variant whenever an API offers both.
- Distinctive: line 39
Do not introduce third-party concurrency frameworks without asking first.
- Distinctive: line 45
Use Quick Fix Mode when all of these are true:
- Distinctive: line 81
If the fix may change behavior, document the invariant and add verification steps.
- Distinctive: line 85
Prefer changes that preserve behavior while satisfying data-race safety:
- Very specific: line 90
Sendability issues: prefer immutable values and explicit boundaries over @unchecked Sendable.
- Very specific: line 130
If anything in that prefix needs @MainActor, keep the inherited @MainActor start.
- Very specific: line 131
If nothing in that prefix needs @MainActor, prefer Task { @concurrent in ...
- Distinctive: line 177
If a fix introduces new warnings, resolve them before continuing.
- Distinctive: line 183
Use Review Mode when asked to review, audit, or critique existing concurrency code rather than fix one named diagnostic.
- Very specific: line 188
Check whether recent Swift 6.2 behavior changes the right answer (default isolation, @concurrent, isolated conformances) — …
- Very specific: line 191
Verify cancellation is propagated and checked correctly — references/tasks.md.
- Very specific: line 193
Check bridging code between sync and async worlds (continuations, @unchecked Sendable) — references/sendable.md, references/migration.md.
- Very specific: line 196
If the project has strict-concurrency errors, map diagnostics to fixes — references/diagnostics.md.
- Very specific: line 197
If reviewing tests, check async test patterns — references/testing.md.
- Very specific: line 202
If an API offers both async/await and closure-based variants, flag call sites still using the closure form.
- Very specific: line 203
Don't flag GCD, locks, or Task.detached on sight — check the context first (see Fast Path guardrails).
- Distinctive: line 268
When changing concurrency code:
- Distinctive: line 272
Run tests, especially actor-, lifetime-, and cancellation-sensitive tests.
- Distinctive: line 273
Use Instruments for performance claims instead of guessing.
- Distinctive: line 274
Verify deallocation and cancellation behavior for long-lived tasks.
- Very specific: line 275
Check Task.isCancelled in long-running operations.
- Very specific: line 276
Never use semaphores or ad hoc locking in async contexts when actor isolation or Mutex would express ownership more safely.
“Common” is measured: kept by at least 6 in 10 of the 24 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Swift Concurrency
This skill covers two jobs: fixing concurrency problems in code you're changing, and reviewing concurrency code you didn't write for correctness. Use Quick Fix Mode / When Quick Fixes Fail for the former, Review Mode for the latter. Both share the same reference files below.
Fast Path
Before proposing a fix:
- Analyze
Package.swiftor.pbxprojto determine Swift language mode, strict concurrency level, default isolation, and upcoming features. Do this always, not only for migration work. - Capture the exact diagnostic and offending symbol.
- Determine the isolation boundary:
@MainActor, custom actor, actor instance isolation, ornonisolated. - Confirm whether the code is UI-bound or intended to run off the main actor. When spawning unstructured tasks, inspect the synchronous prefix (everything before the first
await): start on@MainActoronly when that prefix truly needs main-actor access; otherwise useTask { @concurrent in ... }and hop back withMainActor.runonly after the suspension. A trivial non-main line (for example,print) followed by main-actor work in the same prefix is not a reason to use@concurrent. For delayed retries, timers, and backoff tasks, separate the waiting from the UI mutation. The sleep often belongs off the main actor even when the final state update belongs on it.
Project settings that change concurrency behavior:
| Setting | SwiftPM (Package.swift) | Xcode (.pbxproj) |
| Language mode | swiftLanguageVersions 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_* |
| Approachable Concurrency | N/A (use individual upcoming features) | SWIFT_APPROACHABLE_CONCURRENCY |
Xcode 26 note: New projects created in Xcode 26 will often start with
SWIFT_DEFAULT_ACTOR_ISOLATION = MainActorandSWIFT_APPROACHABLE_CONCURRENCY = YESenabled by default. Treat these as likely defaults for newly created projects, not as confirmed settings.
If any of these are unknown, ask the developer to confirm them before giving migration-sensitive guidance. Do not guess, even for new Xcode 26 projects. If code spans multiple targets or packages, compare their concurrency build settings before assuming behavior should match across them — a fix that's correct in one module can be wrong in a neighbor with a different default isolation.
Guardrails:
- Do not recommend
@MainActoras a blanket fix. Justify why the code is truly UI-bound. - Prefer structured concurrency over unstructured tasks. Use
Task.detachedonly with a clear reason. - Prefer async/await over a closure-based variant whenever an API offers both.
- GCD (
DispatchQueue, locks, serial queues) is still a legitimate tool in low-level libraries, framework interop, and performance-critical synchronous sections — don't flag it just because it's notasync/await. Seereferences/migration.mdfor when to actually convert it. - If recommending
@preconcurrency,@unchecked Sendable, ornonisolated(unsafe), require a documented safety invariant and a follow-up removal plan.@unchecked Sendable's only broadly legitimate use is a type with its own internal locking that's provably thread-safe — check whether Swift 6 region-based isolation already makes it unnecessary before reaching for it. - Do not introduce third-party concurrency frameworks without asking first.
- Optimize for the smallest safe change. Do not refactor unrelated architecture during migration.
- Course references are for deeper learning only. Use them sparingly and only when they clearly help answer the developer's question.
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.
For open-ended "review this code" requests rather than a specific fix, use Review Mode below instead.
Common Diagnostics
| Diagnostic | First check | Smallest safe fix | Escalate to |
Main actor-isolated ... cannot be used from a nonisolated context | Is 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 protocol | Must 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 races | What isolation boundary is being crossed? | Keep access inside one actor, or convert the transferred value to an immutable/value type. | references/sendable.md, references/diagnostics.md |
Static property 'x' is not concurrency-safe | Is it UI state, a true constant, or genuinely unsynchronized? | @MainActor annotation, Sendable conformance if truly immutable, or nonisolated(unsafe) as a last resort. | references/sendable.md, references/diagnostics.md |
SwiftLint async_without_await | Is 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 contexts | Is this legacy XCTest async waiting? | Replace with await fulfillment(of:) or Swift Testing equivalents. | references/testing.md |
| Core Data concurrency warnings | Are NSManagedObject instances crossing contexts or actors? | Pass NSManagedObjectID or map to a Sendable value type. | references/core-data.md |
Thread.current unavailable from asynchronous contexts | Are you debugging by thread instead of isolation? | Reason in terms of isolation and use Instruments/debugger instead. | references/threading.md |
| SwiftLint concurrency-related warnings | Which specific lint rule triggered? | Use references/linting.md for rule intent and preferred fixes; avoid dummy awaits. | references/linting.md |
... cannot satisfy conformance requirement for a 'Sendable' type parameter (SendableMetatype) | Does the conformance carry global-actor isolation? | Remove actor isolation from the conformance, or avoid passing the metatype across isolation boundaries. See SendableMetatype section in references/actors.md. | references/actors.md |
For compiler-error messages not in this table, or for an ordered "try these fixes in order" walkthrough, see references/diagnostics.md.
When Quick Fixes Fail
- Gather project settings if not already confirmed.
- Re-evaluate which isolation boundaries the type crosses.
- Route to the matching reference file for a deeper fix.
- 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@MainActoronly if the state is UI-owned. - Background work: when work must hop off caller isolation, use an
asyncAPI marked@concurrent; when work can safely inherit caller isolation, usenonisolatedwithout@concurrent. When spawning aTask, match entry isolation to its synchronous prefix. If nothing before the firstawaitneeds the main actor, useTask { @concurrent in ... }and hop back viaawait MainActor.run { ... }for the UI update. If the prefix mixes a trivial non-main statement with main-actor work, keep the inherited@MainActorstart—splitting the cheap line off-main is not worth an extra hop. - Sendability issues: prefer immutable values and explicit boundaries over
@unchecked Sendable.
Concurrency Tool Selection
| Need | Tool | Key Guidance |
| Single async operation | async/await | Default choice for sequential async work |
| Fixed parallel operations | async let | Known count at compile time; auto-cancelled on throw |
| Dynamic parallel operations | withTaskGroup | Unknown count; structured — cancels children on scope exit |
| Sync → async bridge | Task { } | Inherits actor context; use Task.detached only with documented reason |
| Shared mutable state | actor | Prefer over locks/queues; keep isolated sections small |
| UI-bound state | @MainActor | Only for truly UI-related code; justify isolation |
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)
}
}Task entry isolation
Match a Task's entry isolation to its synchronous prefix (everything from { to the first await).
- If anything in that prefix needs
@MainActor, keep the inherited@MainActorstart. - If nothing in that prefix needs
@MainActor, preferTask { @concurrent in ... }and hop back only for UI-owned mutation.
// ❌ Synchronous prefix is empty; first work hops away
Task {
await hopToOtherIsolationDomain()
}
// ❌ Synchronous prefix is only `print` (trivial, non-main); first await hops away
Task {
print("Also not main-thread-bound")
await hopToOtherIsolationDomain()
}
// ✅ Start off the main actor, hop back only for UI work
Task { @concurrent in
await hopToOtherIsolationDomain()
await MainActor.run { updateUI() }
}
// ✅ Synchronous prefix DOES contain main-actor work — keep inheritance
Task {
print("debug") // trivial, non-main — rides along
self.isLoading = true // needs @MainActor, before any await
await fetchData()
}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:
- Build — Run
swift buildor Xcode build to surface new diagnostics - Fix — Address one category of error at a time (e.g., all Sendable issues first)
- Rebuild — Confirm the fix compiles cleanly before moving on
- Test — Run the test suite to catch regressions (
swift testor Cmd+U) - 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.
Review Mode
Use Review Mode when asked to review, audit, or critique existing concurrency code rather than fix one named diagnostic. Report only genuine problems — do not nitpick or invent issues. If doing a partial review, load only the reference files relevant to what changed.
Review order (skip steps that don't apply):
- Scan for known-dangerous patterns to prioritize what to inspect —
references/hotspots.md. - Check whether recent Swift 6.2 behavior changes the right answer (default isolation,
@concurrent, isolated conformances) —references/actors.md,references/threading.md. - Validate actor usage for reentrancy, isolation, and global/static state —
references/actors.md. - Confirm structured concurrency (task groups) is preferred over unstructured (
Task {},Task.detached) where appropriate —references/tasks.md. - Verify cancellation is propagated and checked correctly —
references/tasks.md. - Validate async stream, sequence, and continuation usage —
references/async-sequences.md. - Check bridging code between sync and async worlds (continuations,
@unchecked Sendable) —references/sendable.md,references/migration.md. - Review any legacy-concurrency migrations (GCD, delegates, Combine) —
references/migration.md. - Cross-check against common failure modes —
references/bug-patterns.md. - If the project has strict-concurrency errors, map diagnostics to fixes —
references/diagnostics.md. - If reviewing tests, check async test patterns —
references/testing.md.
Review-specific guardrails, in addition to the Fast Path guardrails above:
- Target Swift 6.2+ with strict concurrency checking unless the project's settings say otherwise (see Fast Path step 1).
- If an API offers both
async/awaitand closure-based variants, flag call sites still using the closure form. - Don't flag GCD, locks, or
Task.detachedon sight — check the context first (see Fast Path guardrails).
Review Output Format
Organize findings by file. For each issue: state the file and line(s), name the rule being violated, and show a brief before/after fix. Skip files with no issues. End with a prioritized summary — highest-impact fix first.
### DataLoader.swift
**Line 18: Actor reentrancy — state may have changed across the `await`.**
// Before
actor Cache {
var items: [String: Data] = [:]
func fetch(_ key: String) async throws -> Data {
if items[key] == nil { items[key] = try await download(key) }
return items[key]!
}
}
// After
actor Cache {
var items: [String: Data] = [:]
func fetch(_ key: String) async throws -> Data {
if let existing = items[key] { return existing }
let data = try await download(key)
items[key] = data
return data
}
}
### Summary
1. **Correctness (high):** Actor reentrancy bug on line 18 may cause duplicate downloads and a force-unwrap crash.Reference Router
Open the smallest reference that matches the question:
- Foundations
references/async-await-basics.md— async/await syntax, execution order, async let, URLSession patternsreferences/tasks.md— Task lifecycle, cancellation,withTaskCancellationHandler, priorities, task groups, structured vs unstructured,Task.immediate, task namingreferences/actors.md— Actor isolation, @MainActor, global actors, reentrancy (incl. in-flight-task dedup), custom executors, Mutexreferences/sendable.md— Sendable conformance, value/reference types, @unchecked, region isolationreferences/threading.md— Execution model, suspension points, Swift 6.2 isolation behavior
- Streams
references/async-sequences.md— AsyncSequence, AsyncStream (incl.makeStream(of:)), when to use vs regular async methodsreferences/async-algorithms.md— Debounce, throttle, merge, combineLatest, channels, timers
- Applied topics
references/testing.md— Swift Testing first, XCTest fallback, leak checks, race detection with Thread Sanitizerreferences/performance.md— Profiling with Instruments, reducing suspension points, execution strategiesreferences/memory-management.md— Retain cycles in tasks, memory safety patternsreferences/core-data.md— NSManagedObject sendability, custom executors, isolation conflicts
- Migration and tooling
references/migration.md— Swift 6 migration strategy, closure/delegate-to-async conversion, continuation resume rules, @preconcurrency, GCD and FRP migrationreferences/linting.md— Concurrency-focused lint rules and SwiftLintasync_without_await
- Review
references/hotspots.md— Grep targets for code review: known-dangerous patterns and what to check for eachreferences/bug-patterns.md— Common concurrency failure modes and their fixes, for fast review scanningreferences/diagnostics.md— Strict-concurrency compiler errors mapped to ordered, "try this first" fixes
- Glossary
references/glossary.md— Quick definitions of core concurrency terms
Verification Checklist
When changing concurrency code:
- Re-check build settings before interpreting diagnostics.
- Build and clear one category of errors before moving on. Do not batch unrelated fixes into the same change.
- Run tests, especially actor-, lifetime-, and cancellation-sensitive tests.
- Use Instruments for performance claims instead of guessing.
- Verify deallocation and cancellation behavior for long-lived tasks.
- Check
Task.isCancelledin long-running operations. - Never use semaphores or ad hoc locking in async contexts when actor isolation or
Mutexwould express ownership more safely.
Note: This skill is based on the comprehensive Swift Concurrency Course by Antoine van der Lee, and incorporates review methodology from the Swift Concurrency Agent Skill by Paul Hudson.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

