Back to Skills

concurrency-patterns

verified

Expert Swift concurrency decisions: async let vs TaskGroup selection, actor isolation boundaries, @MainActor placement strategies, Sendable conformance judgment calls, and structured vs unstructured task trade-offs. Use when designing concurrent code, debugging data races, or choosing between concurrency patterns. Trigger keywords: async, await, actor, Task, TaskGroup, @MainActor, Sendable, concurrency, data race, isolation, structured concurrency, continuation

View on GitHub

Marketplace

manifest-marketplace

Kaakati/rails-enterprise-dev

Plugin

reactree-ios-dev

development

Repository

Kaakati/rails-enterprise-dev
2stars

plugins/reactree-ios-dev/skills/concurrency-patterns/SKILL.md

Last Verified

January 25, 2026

Install Skill

Select agents to install to:

Scope:
npx add-skill https://github.com/Kaakati/rails-enterprise-dev/blob/main/plugins/reactree-ios-dev/skills/concurrency-patterns/SKILL.md -a claude-code --skill concurrency-patterns

Installation paths:

Claude
.claude/skills/concurrency-patterns/
Powered by add-skill CLI

Instructions

# Concurrency Patterns — Expert Decisions

Expert decision frameworks for Swift concurrency choices. Claude knows async/await syntax — this skill provides judgment calls for pattern selection and isolation boundaries.

---

## Decision Trees

### async let vs TaskGroup

```
Is the number of concurrent operations known at compile time?
├─ YES (2-5 fixed operations)
│  └─ async let
│     async let user = fetchUser()
│     async let posts = fetchPosts()
│     let (user, posts) = await (try user, try posts)
│
└─ NO (dynamic count, array of IDs)
   └─ TaskGroup
      try await withThrowingTaskGroup(of: User.self) { group in
          for id in userIds { group.addTask { ... } }
      }
```

**async let gotcha**: All `async let` values MUST be awaited before scope ends. Forgetting to await silently cancels the task — no error, just missing data.

### Task vs Task.detached

```
Does the new task need to inherit context?
├─ YES (inherit priority, actor, task-locals)
│  └─ Task { }
│     Example: Continue work on same actor
│
└─ NO (fully independent execution)
   └─ Task.detached { }
      Example: Background processing that shouldn't block UI
```

**The trap**: `Task { }` inside `@MainActor` runs on MainActor. For truly background work, use `Task.detached(priority:)`.

### Actor vs Class with Lock

```
Is the mutable state accessed from async contexts?
├─ YES → Actor (compiler-enforced isolation)
│
└─ NO → Is it performance-critical?
   ├─ YES → Class with lock (less overhead)
   │  └─ Consider @unchecked Sendable if crossing boundaries
   │
   └─ NO → Actor (safer, cleaner)
```

**When actors lose**: High-contention scenarios where lock granularity matters. Actor methods are fully isolated — can't lock just part of the state.

### Sendable Conformance

```
Is the type crossing concurrency boundaries?
├─ NO → Don't add Sendable
│
└─ YES → What kind of type?
   ├─ Struct with only Sendable properties
   │  └─ Implicit Sendable (or add explicit)
   │
   ├─ Class with immutabl

Validation Details

Front Matter
Required Fields
Valid Name Format
Valid Description
Has Sections
Allowed Tools
Instruction Length:
9605 chars