$npx -y skills add twostraws/Swift-Concurrency-Agent-Skill --skill swift-concurrency-proReviews Swift code for concurrency correctness, modern API usage, and common async/await pitfalls. Use when reading, writing, or reviewing Swift concurrency code.
| 1 | Review Swift concurrency code for correctness, modern API usage, and adherence to project conventions. Report only genuine problems - do not nitpick or invent issues. |
| 2 | |
| 3 | Review process: |
| 4 | |
| 5 | 1. Scan for known-dangerous patterns using `references/hotspots.md` to prioritize what to inspect. |
| 6 | 1. Check for recent Swift 6.2 concurrency behavior using `references/new-features.md`. |
| 7 | 1. Validate actor usage for reentrancy and isolation correctness using `references/actors.md`. |
| 8 | 1. Ensure structured concurrency is preferred over unstructured where appropriate using `references/structured.md`. |
| 9 | 1. Check unstructured task usage for correctness using `references/unstructured.md`. |
| 10 | 1. Verify cancellation is handled correctly using `references/cancellation.md`. |
| 11 | 1. Validate async stream and continuation usage using `references/async-streams.md`. |
| 12 | 1. Check bridging code between sync and async worlds using `references/bridging.md`. |
| 13 | 1. Review any legacy concurrency migrations using `references/interop.md`. |
| 14 | 1. Cross-check against common failure modes using `references/bug-patterns.md`. |
| 15 | 1. If the project has strict-concurrency errors, map diagnostics to fixes using `references/diagnostics.md`. |
| 16 | 1. If reviewing tests, check async test patterns using `references/testing.md`. |
| 17 | |
| 18 | If doing a partial review, load only the relevant reference files. |
| 19 | |
| 20 | |
| 21 | ## Core Instructions |
| 22 | |
| 23 | - Target Swift 6.2 or later with strict concurrency checking. |
| 24 | - If code spans multiple targets or packages, compare their concurrency build settings before assuming behavior should match. |
| 25 | - Prefer structured concurrency (task groups) over unstructured (`Task {}`). |
| 26 | - Prefer Swift concurrency over Grand Central Dispatch for new code. GCD is still acceptable in low-level code, framework interop, or performance-critical synchronous work where queues and locks are the right tool – don't flag these as errors. |
| 27 | - If an API offers both `async`/`await` and closure-based variants, always prefer `async`/`await`. |
| 28 | - Do not introduce third-party concurrency frameworks without asking first. |
| 29 | - Do not suggest `@unchecked Sendable` to fix compiler errors. It silences the diagnostic without fixing the underlying race. Prefer actors, value types, or `sending` parameters instead. The only legitimate use is for types with internal locking that are provably thread-safe. |
| 30 | |
| 31 | |
| 32 | ## Output Format |
| 33 | |
| 34 | Organize findings by file. For each issue: |
| 35 | |
| 36 | 1. State the file and relevant line(s). |
| 37 | 2. Name the rule being violated. |
| 38 | 3. Show a brief before/after code fix. |
| 39 | |
| 40 | Skip files with no issues. End with a prioritized summary of the most impactful changes to make first. |
| 41 | |
| 42 | Example output: |
| 43 | |
| 44 | ### DataLoader.swift |
| 45 | |
| 46 | **Line 18: Actor reentrancy – state may have changed across the `await`.** |
| 47 | |
| 48 | ```swift |
| 49 | // Before |
| 50 | actor Cache { |
| 51 | var items: [String: Data] = [:] |
| 52 | |
| 53 | func fetch(_ key: String) async throws -> Data { |
| 54 | if items[key] == nil { |
| 55 | items[key] = try await download(key) |
| 56 | } |
| 57 | return items[key]! |
| 58 | } |
| 59 | } |
| 60 | |
| 61 | // After |
| 62 | actor Cache { |
| 63 | var items: [String: Data] = [:] |
| 64 | |
| 65 | func fetch(_ key: String) async throws -> Data { |
| 66 | if let existing = items[key] { return existing } |
| 67 | let data = try await download(key) |
| 68 | items[key] = data |
| 69 | return data |
| 70 | } |
| 71 | } |
| 72 | ``` |
| 73 | |
| 74 | **Line 34: Use `withTaskGroup` instead of creating tasks in a loop.** |
| 75 | |
| 76 | ```swift |
| 77 | // Before |
| 78 | for url in urls { |
| 79 | Task { try await fetch(url) } |
| 80 | } |
| 81 | |
| 82 | // After |
| 83 | try await withThrowingTaskGroup(of: Data.self) { group in |
| 84 | for url in urls { |
| 85 | group.addTask { try await fetch(url) } |
| 86 | } |
| 87 | |
| 88 | for try await result in group { |
| 89 | process(result) |
| 90 | } |
| 91 | } |
| 92 | ``` |
| 93 | |
| 94 | ### Summary |
| 95 | |
| 96 | 1. **Correctness (high):** Actor reentrancy bug on line 18 may cause duplicate downloads and a force-unwrap crash. |
| 97 | 2. **Structure (medium):** Unstructured tasks in loop on line 34 lose cancellation propagation. |
| 98 | |
| 99 | End of example. |
| 100 | |
| 101 | |
| 102 | ## References |
| 103 | |
| 104 | - `references/hotspots.md` - Grep targets for code review: known-dangerous patterns and what to check for each. |
| 105 | - `references/new-features.md` - Swift 6.2 changes that alter review advice: default actor isolation, isolated conformances, caller-actor async behavior, `@concurrent`, `Task.immediate`, task naming, and priority escalation. |
| 106 | - `references/actors.md` - Actor reentrancy, shared-state annotations, global actor inference, and isolation patterns. |
| 107 | - `references/structured.md` - Task groups over loops, discarding task groups, concurrency limits. |
| 108 | - `references/unstructured.md` - Task vs Task.detached, when Task {} is a code smell. |
| 109 | - `references/cancellation.md` - Cancellation propagation, cooperative checking, broken cancellation patterns. |
| 110 | - `references/async-streams.md` - AsyncStream factory, continuation lifecycle, back-pressure. |
| 111 | - `references/bridging.md` - |