avdlee/swift-concurrency-agent-skill
Overview
This skill provides expert guidance on Swift Concurrency best practices, patterns, and migration advice for Swift 5.x → Swift 6. It helps diagnose isolation boundaries, Sendable issues, actor usage, and safe refactors to async/await while minimizing risk to large codebases. Use it to produce concrete fixes, verification steps, and migration plans tailored to project build settings.
How this skill works
I inspect project configuration (Package.swift, project.pbxproj) to determine Swift language mode, default actor isolation, and strict concurrency flags before offering fixes. I identify the isolation boundary (@MainActor, custom actor, actor instance, or nonisolated) and prefer structured concurrency, safe Sendable conformance, and minimal-scope changes. Recommendations include concrete code edits, required invariants for unsafe annotations, and a verification checklist for tests and performance.
When to use it
- When developers mention async/await, actors, tasks, or modern concurrency patterns
- When migrating to Swift 6 or enabling strict concurrency checks
- When encountering Sendable or actor-isolation compiler/linter warnings
- When refactoring closures or callbacks into async/await
- When diagnosing data races, thread-safety, or performance issues
Best practices
- Always read build settings first — default isolation and strict concurrency change advice
- Prefer structured concurrency (async let, Task groups) over unstructured Task.detached
- Identify and justify every @MainActor recommendation; do not apply it blindly
- Require documented safety invariants and a follow-up ticket for @preconcurrency or @unchecked Sendable
- Keep actor-isolated sections small to minimize suspension points and context switches
- Run targeted tests and Instruments after changes to verify correctness and performance
Example use cases
- Convert completion-handler APIs to async/await with minimal, stepwise changes
- Resolve SwiftLint async_without_await by adjusting signatures or narrowing suppressions
- Make a cache actor-safe by moving mutable state into an actor and exposing nonisolated read helpers
- Migrate a module to Swift 6 by auditing Sendable conformance and adding small PRs with verification steps
- Optimize parallel network calls using async let or withTaskGroup instead of serial awaits
FAQ
Only when the code truly belongs on the main actor (UI work or main-thread-only APIs). Explain why main-thread guarantees are required and prefer narrow isolation or isolated parameters where possible.
When is Task.detached appropriate?
Use Task.detached only when you explicitly need unstructured work that must ignore the current actor context and you can prove no shared mutable state is accessed. Prefer child tasks and task groups for structured, cancellable work.