swift-concurrency-developer
Expert guidance on Swift concurrency using the Office Building mental model. Use when working with actors, isolation, Sendable, TaskGroups, or fixing concurrency warnings and data race issues.
Install
mkdir -p .claude/skills/swift-concurrency-developer && curl -L -o skill.zip "https://mcp.directory/api/skills/download/6699" && unzip -o skill.zip -d .claude/skills/swift-concurrency-developer && rm skill.zipInstalls to .claude/skills/swift-concurrency-developer
About this skill
Swift Concurrency Developer (Smart Router)
Purpose
Expert guidance on Swift's concurrency system using the "Office Building" mental model from Fucking Approachable Swift Concurrency, combined with comprehensive reference material from Swift Concurrency Course.
When Auto-Activated
- Working with actors, isolation, Sendable, TaskGroups
- Keywords:
actor,isolation,Sendable,TaskGroup,nonisolated,async let - Fixing concurrency warnings or data race issues
Agent Behavior Contract (Follow These Rules)
- Analyze the project/package file to find out which Swift language mode (Swift 5.x vs Swift 6) and which Xcode/Swift toolchain is used when advice depends on it.
- Before proposing fixes, identify the isolation boundary:
@MainActor, custom actor, actor instance isolation, or nonisolated. - Do not recommend
@MainActoras a blanket fix. Justify why main-actor isolation is correct for the code. - Prefer structured concurrency (child tasks, task groups) over unstructured tasks. Use
Task.detachedonly with a clear reason. - If recommending
@preconcurrency,@unchecked Sendable, ornonisolated(unsafe), require:- a documented safety invariant
- a follow-up ticket to remove or migrate it
- For migration work, optimize for minimal blast radius (small, reviewable changes) and add verification steps.
- Course references are for deeper learning only. Use them sparingly and only when they clearly help answer the developer's question.
Project Settings Discovery
When analyzing Swift projects for concurrency issues:
-
Project Settings Discovery
- Use
ReadonPackage.swiftfor SwiftPM settings (tools version, strict concurrency flags, upcoming features) - Use
GrepforSWIFT_STRICT_CONCURRENCYorSWIFT_DEFAULT_ACTOR_ISOLATIONin.pbxprojfiles
- Use
-
Manual checks
- SwiftPM: Check
Package.swiftfor.enableExperimentalFeature("StrictConcurrency=targeted")or similar - Xcode projects: Search
project.pbxprojforSWIFT_DEFAULT_ACTOR_ISOLATION,SWIFT_STRICT_CONCURRENCY
- SwiftPM: Check
Core Mental Model: The Office Building
Think of your app as an office building where isolation domains are private offices with locks:
| Concept | Office Analogy | Swift |
|---|---|---|
| MainActor | Front desk (handles all UI) | @MainActor |
| actor | Department offices (Accounting, Legal) | actor BankAccount { } |
| nonisolated | Hallways (shared space) | nonisolated func name() |
| Sendable | Photocopies (safe to share) | struct User: Sendable |
| Non-Sendable | Original documents (stay in one office) | class Counter { } |
Key insight: You can't barge into someone's office. You knock (await) and wait.
Quick Decision Tree
When a developer needs concurrency guidance:
-
Starting fresh with async code?
- Read
references/async-await-basics.mdfor foundational patterns - For parallel operations →
references/tasks.md(async let, task groups)
- Read
-
Protecting shared mutable state?
- Need to protect class-based state →
references/actors.md(actors, @MainActor) - Need thread-safe value passing →
references/sendable.md(Sendable conformance)
- Need to protect class-based state →
-
Managing async operations?
- Structured async work →
references/tasks.md(Task, child tasks, cancellation) - Streaming data →
references/async-sequences.md(AsyncSequence, AsyncStream)
- Structured async work →
-
Working with legacy frameworks?
- Core Data integration →
references/core-data.md - General migration →
references/migration.md
- Core Data integration →
-
Performance or debugging issues?
- Slow async code →
references/performance.md(profiling, suspension points) - Testing concerns →
references/testing.md(XCTest, Swift Testing)
- Slow async code →
-
Understanding threading behavior?
- Read
references/threading.mdfor thread/task relationship and isolation
- Read
-
Memory issues with tasks?
- Read
references/memory-management.mdfor retain cycle prevention
- Read
Triage-First Playbook (Common Errors -> Next Best Move)
- SwiftLint concurrency-related warnings
- Use
references/linting.mdfor rule intent and preferred fixes; avoid dummy awaits as "fixes".
- Use
- "Sending value of non-Sendable type ... risks causing data races"
- First: identify where the value crosses an isolation boundary
- Then: use
references/sendable.mdandreferences/threading.md
- "Main actor-isolated ... cannot be used from a nonisolated context"
- First: decide if it truly belongs on
@MainActor - Then: use
references/actors.md(global actors,nonisolated, isolated parameters)
- First: decide if it truly belongs on
- XCTest async errors like "wait(...) is unavailable from asynchronous contexts"
- Use
references/testing.md(await fulfillment(of:)and Swift Testing patterns)
- Use
- Core Data concurrency warnings/errors
- Use
references/core-data.md(DAO/NSManagedObjectID, default isolation conflicts)
- Use
Quick Patterns
Async/Await
func fetchUser(id: Int) async throws -> User {
let (data, _) = try await URLSession.shared.data(from: url)
return try JSONDecoder().decode(User.self, from: data)
}
Parallel Work with async let
async let avatar = fetchImage("avatar.jpg")
async let banner = fetchImage("banner.jpg")
return Profile(avatar: try await avatar, banner: try await banner)
Tasks
// SwiftUI - cancels when view disappears
.task { avatar = await downloadAvatar() }
// Manual task (inherits actor context)
Task { await saveProfile() }
TaskGroup for Dynamic Parallel Work
try await withThrowingTaskGroup(of: Void.self) { group in
group.addTask { avatar = try await downloadAvatar() }
group.addTask { bio = try await fetchBio() }
try await group.waitForAll()
}
Actors
actor BankAccount {
var balance: Double = 0
func deposit(_ amount: Double) { balance += amount }
// No await needed - can access directly inside actor
nonisolated func bankName() -> String { "Acme Bank" }
}
await account.deposit(100) // Must await from outside
let name = account.bankName() // No await needed
Sendable Types
// Automatically Sendable - value type
struct User: Sendable {
let id: Int
let name: String
}
// Thread-safe class with internal synchronization
final class ThreadSafeCache: @unchecked Sendable {
private let lock = NSLock()
private var storage: [String: Data] = [:]
}
Common Mistakes
1. Thinking async = background
// WRONG: Still blocks main thread!
@MainActor func slowFunction() async {
let result = expensiveCalculation() // Synchronous = blocking
}
// CORRECT: Use detached task for CPU-heavy work
Task.detached(priority: .userInitiated) {
let result = expensiveCalculation()
await MainActor.run { updateUI(result) }
}
Production impact: Apps get rejected for "became unresponsive." See
references/production-pitfalls.mdsection 2.
2. Creating too many actors
Most things can live on MainActor. Only create actors when you have shared mutable state that can't be on MainActor.
3. Using MainActor.run unnecessarily
// WRONG
await MainActor.run { self.data = data }
// CORRECT - annotate the function
@MainActor func loadData() async { self.data = await fetchData() }
4. Blocking the cooperative thread pool (violates runtime contract)
Never use DispatchSemaphore, DispatchGroup.wait(), or condition variables in async code.
Why: These primitives hide dependencies from the runtime. The cooperative thread pool has a contract that threads will always make forward progress. Blocking primitives violate this contract and can cause deadlock.
// ❌ DANGEROUS: Can deadlock the cooperative pool
let semaphore = DispatchSemaphore(value: 0)
Task {
await doWork()
semaphore.signal()
}
semaphore.wait() // Thread blocked, runtime unaware
// ✅ Use async/await instead
let result = await doWork()
Debug tip: Set LIBDISPATCH_COOPERATIVE_POOL_STRICT=1 to catch blocking calls during development.
5. Creating unnecessary Tasks
// WRONG - unstructured
Task { await fetchUsers() }
Task { await fetchPosts() }
// CORRECT - structured concurrency
async let users = fetchUsers()
async let posts = fetchPosts()
await (users, posts)
6. Making everything Sendable
Not everything needs to cross boundaries. Ask if data actually moves between isolation domains.
7. Not batching MainActor hops
The main thread is separate from the cooperative thread pool. Each hop to/from MainActor requires a full context switch.
// ❌ Multiple context switches
for item in items {
let processed = await processItem(item)
await MainActor.run { displayItem(processed) } // Context switch per item
}
// ✅ Single context switch
let processed = await processAllItems(items)
await MainActor.run {
for item in processed { displayItem(item) }
}
8. Async for loops silently losing data
Using try? or empty catch {} in async loops swallows failures. Users lose data with zero indication. Acceptable for fire-and-forget (cache warming, analytics), dangerous for uploads/sync/migration. See references/production-pitfalls.md section 1.
9. Ignoring Task cancellation in long-running loops
for await under .task modifier is safe (structured concurrency propagates cancellation). But for await or while loops in stored Task { } properties need explicit Task.isCancelled checks. See references/production-pitfalls.md section 3.
10. Manual migration pitfalls (@preconcurrency + DispatchQueue mixing)
@preconcurrency and nonisolated(unsafe) hide real data races. Mixing DispatchQueue with async/await creates confusing execution contexts. Always document safety invariants and plan removal. See references/production-pitfalls.md section 4.
11. Task
Content truncated.
More by anyproto
View all skills by anyproto →You might also like
flutter-development
aj-geddes
Build beautiful cross-platform mobile apps with Flutter and Dart. Covers widgets, state management with Provider/BLoC, navigation, API integration, and material design.
drawio-diagrams-enhanced
jgtolentino
Create professional draw.io (diagrams.net) diagrams in XML format (.drawio files) with integrated PMP/PMBOK methodologies, extensive visual asset libraries, and industry-standard professional templates. Use this skill when users ask to create flowcharts, swimlane diagrams, cross-functional flowcharts, org charts, network diagrams, UML diagrams, BPMN, project management diagrams (WBS, Gantt, PERT, RACI), risk matrices, stakeholder maps, or any other visual diagram in draw.io format. This skill includes access to custom shape libraries for icons, clipart, and professional symbols.
ui-ux-pro-max
nextlevelbuilder
"UI/UX design intelligence. 50 styles, 21 palettes, 50 font pairings, 20 charts, 8 stacks (React, Next.js, Vue, Svelte, SwiftUI, React Native, Flutter, Tailwind). Actions: plan, build, create, design, implement, review, fix, improve, optimize, enhance, refactor, check UI/UX code. Projects: website, landing page, dashboard, admin panel, e-commerce, SaaS, portfolio, blog, mobile app, .html, .tsx, .vue, .svelte. Elements: button, modal, navbar, sidebar, card, table, form, chart. Styles: glassmorphism, claymorphism, minimalism, brutalism, neumorphism, bento grid, dark mode, responsive, skeuomorphism, flat design. Topics: color palette, accessibility, animation, layout, typography, font pairing, spacing, hover, shadow, gradient."
godot
bfollington
This skill should be used when working on Godot Engine projects. It provides specialized knowledge of Godot's file formats (.gd, .tscn, .tres), architecture patterns (component-based, signal-driven, resource-based), common pitfalls, validation tools, code templates, and CLI workflows. The `godot` command is available for running the game, validating scripts, importing resources, and exporting builds. Use this skill for tasks involving Godot game development, debugging scene/resource files, implementing game systems, or creating new Godot components.
nano-banana-pro
garg-aayush
Generate and edit images using Google's Nano Banana Pro (Gemini 3 Pro Image) API. Use when the user asks to generate, create, edit, modify, change, alter, or update images. Also use when user references an existing image file and asks to modify it in any way (e.g., "modify this image", "change the background", "replace X with Y"). Supports both text-to-image generation and image-to-image editing with configurable resolution (1K default, 2K, or 4K for high resolution). DO NOT read the image file first - use this skill directly with the --input-image parameter.
fastapi-templates
wshobson
Create production-ready FastAPI projects with async patterns, dependency injection, and comprehensive error handling. Use when building new FastAPI applications or setting up backend API projects.
Related MCP Servers
Browse all serversConnect Blender to Claude AI for seamless 3D modeling. Use AI 3D model generator tools for faster, intuitive, interactiv
Test website accessibility and ensure WCAG compliance with Axe Accessibility, a web accessibility checker with detailed
Get expert React Native software guidance with tools for component analysis, performance, debugging, and migration betwe
Streamline your team software process with Spec-Driven Development, optimizing the software development life cycle using
Cairo Coder: Expert Cairo and Starknet development support, smart contract creation, and code refactoring via the Cairo
Discover Build Vault: your searchable knowledge base for The Build Podcast. Semantic search, filters & expert insights a
Stay ahead of the MCP ecosystem
Get weekly updates on new skills and servers.