---
name: swift-6-2-approachable-concurrency
description: "Migrate Swift codebases to 6.2 strict concurrency — approachable-concurrency flags, Sendable/actor fixes, no data races. Migrates existing Swift code to 6.2 strict concurrency for the Xcode 26 App Store mandate: enables approachable-concurrency build settings (defaultIsolation = MainActor, NonisolatedNonsendingByDefault), resolves Sendable and actor-isolation diagnostics with correct fix-its, and adopts nonisolated(nonsending), @concurrent, sending parameters, and Mutex/global-actor isolation without introducing data races. Covers SWIFT_APPROACHABLE_CONCURRENCY and SWIFT_DEFAULT_ACTOR_ISOLATION flags, staged StrictConcurrency upgrade paths, @preconcurrency import bridging, and untangling @Sendable closure captures."
license: MIT
---

# Swift 6.2 Concurrency Migrator

Migrate an existing Swift codebase to Swift 6.2's strict concurrency model, with a focus on the "approachable concurrency" settings Apple surfaced for the Xcode 26 toolchain. This skill is for iOS, macOS, and Swift Package authors who are bumping their Swift language mode to 6 and need to clear the wave of `Sendable` and actor-isolation diagnostics without introducing data races or sprinkling `@unchecked Sendable` everywhere.

## When to use it

- You flipped `SWIFT_VERSION` (or `swift-tools-version`) to 6 and the build erupted with isolation errors.
- You want to adopt `defaultIsolation = MainActor` so UI-layer types are main-actor by default instead of annotating each one.
- A library you ship needs to be clean under strict concurrency for downstream consumers.
- You're getting "sending 'self' risks causing data races" or "non-sendable type cannot cross actor boundary" and want correct fixes rather than suppression.

## What it does

The skill works module by module rather than all at once. It enables the approachable-concurrency build settings: `SWIFT_APPROACHABLE_CONCURRENCY = YES`, the `NonisolatedNonsendingByDefault` upcoming feature, and `defaultIsolation` (typically `MainActor`) via the build setting in Xcode or `defaultIsolation(MainActor.self)` in a Package.swift Swift settings block. It then compiles, parses the emitted diagnostics, and applies the *correct* remedy for each: conforming value types to `Sendable`, marking reference types with `@unchecked Sendable` only when genuinely safe, isolating mutable state to an `actor` or `@MainActor`, and adding `nonisolated` / `nonisolated(unsafe)` where a stored property is provably race-free (e.g. a constant or externally synchronized cache).

It distinguishes real races from false positives, prefers `nonisolated(nonsending)` semantics for async functions that shouldn't hop actors, and avoids the lazy fixes (`@preconcurrency import`, blanket `@unchecked`) unless nothing safer applies.

## Usage

```bash
curl -fsSL --create-dirs -o ~/.claude/skills/swift-6-2-approachable-concurrency/SKILL.md https://claudeskil.com/skills/swift-6-2-approachable-concurrency/SKILL.md

# then, in your project:
claude "migrate the Networking target to Swift 6.2 strict concurrency"
```

In Package.swift the skill produces settings like:

```swift
.target(
    name: "Networking",
    swiftSettings: [
        .defaultIsolation(MainActor.self),
        .enableUpcomingFeature("NonisolatedNonsendingByDefault"),
    ]
)
```

## Tips & gotchas

- Migrate one target at a time and keep each in `-warnings-as-errors` triage mode; the diagnostic count for an app-wide flip is misleading.
- `defaultIsolation = MainActor` is great for UI modules but wrong for networking/model layers — apply it selectively, not at the package root.
- `nonisolated(unsafe)` silences the compiler but turns off its checking; the skill flags every use so you can audit them later.
- Global `let` constants of non-Sendable type still error — they often need the type itself made Sendable, not the global annotated.

## FAQ

**Does this change runtime behavior?**
Adopting `MainActor` default isolation can move work onto the main thread. The skill calls out hot paths where that matters so you can mark them `nonisolated`.

**Will it touch my language mode?**
It can set Swift 6 mode, but you can keep language mode 5 and just enable the upcoming features incrementally — useful for staged rollouts.

**What about third-party dependencies that aren't Sendable yet?**
Where unavoidable it uses scoped `@preconcurrency import`, flagged for removal once the dependency updates.
