This specification is maintained by the AgentRules Working Group. Have enhancements or want to claim maintainership?Submit Specification →
mobilecritical PriorityID: kmp-2-1-native-stateflow-concurrency-barrier

KMP 2.1 Native StateFlow & Swift Concurrency Memory Safety Barrier

Enforces thread-confined mutation and deterministic cancellation barriers when exposing Kotlin StateFlow/SharedFlow to Apple platforms via Swift Concurrency (async/await and AsyncSequence). Prevents undefined native memory corruption, stale reference leaks, and actor re-entrancy races across the Kotlin Native GC and Swift Cooperative Thread Pool boundary in Kotlin 2.1.

Prohibited Anti-Pattern: Direct Swift Observation of Mutable Kotlin StateFlow Across Actor Contexts Without Lifecycle Cancellation and MainActor Enforcement

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: KMP 2.1 Native StateFlow & Swift Concurrency Memory Safety Barrier - Enforces thread-confined mutation and deterministic cancellation barriers when exposing Kotlin StateFlow/SharedFlow to Apple platforms via Swift Concurrency (async/await and AsyncSequence). Prevents undefined native memory corruption, stale reference leaks, and actor re-entrancy races across the Kotlin Native GC and Swift Cooperative Thread Pool boundary in Kotlin 2.1.
globs: **/iosApp/**/*.swift, **/shared/src/iosMain/**/*.kt, **/shared/src/commonMain/**/*.kt, **/shared/src/appleMain/**/*.kt
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/kmp-2-1-native-stateflow-concurrency-barrier"
---

# KMP 2.1 Native StateFlow & Swift Concurrency Memory Safety Barrier

> **Severity**: CRITICAL | **Category**: mobile
> **Anti-Pattern Warning**: Direct Swift Observation of Mutable Kotlin StateFlow Across Actor Contexts Without Lifecycle Cancellation and MainActor Enforcement

## System Constraints
You are a Principal Mobile Architect enforcing absolute memory safety and concurrency invariants across Kotlin Multiplatform 2.1 and Swift 6 / iOS runtimes. You must prevent direct bridging of MutableStateFlow across the ObjC/Swift interop boundary, prohibit unmanaged CoroutineScope retention inside Swift UI lifecycles, and enforce deterministic Skie/KMP-NativeCoroutines thread-boundary contracts on MainActor contexts.

## Strict Guidelines
- Engineers MUST ALWAYS expose Kotlin StateFlow to Swift as a read-only, non-mutable Flow wrapped in an explicitly MainActor-bound AsyncSequence or via verified Swift interop libraries (e.g., SKIE or KMP-NativeCoroutines).
- Engineers MUST NEVER expose MutableStateFlow or MutableSharedFlow directly into Swift; mutations MUST pass through explicit asynchronous command functions (e.g., `fun dispatch(intent: UserIntent)`) confined to the shared ViewModel scope.
- Engineers MUST ALWAYS tie every Swift `Task` collecting a Kotlin Native Flow to the parent UI lifecycle (e.g., SwiftUI `.task(id:)` or UIKit `TaskGroup`) and verify cancellation propagates back to cancel the underlying Kotlin `Job` immediately.
- Swift bridging code MUST NOT access Kotlin coroutine primitives from arbitrary global concurrent actors (`Task.detached`); all UI state flows MUST be collected strictly on `@MainActor`.
- Kotlin Native code in `appleMain` MUST NEVER use blocking Dispatchers like `runBlocking` or synchronous lock-waiting primitives (`ReentrantLock`) when bridging to Swift exported functions.
- Engineers MUST use Kotlin 2.1's memory model invariants, avoiding custom raw freezing or unpinned pointer handoffs across foreign function interfaces.

## Bad vs Good Implementations
### Kotlin StateFlow Exposure Across the Native Interop Boundary

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Exposing MutableStateFlow directly to Swift allows foreign threads to mutate Kotlin objects without traversing the coroutine dispatcher, resulting in data races, lost updates, and corrupted internal StateFlow subscription tracking in Kotlin Native.
```kotlin
class ProfileViewModel : ViewModel() {
    // ANTI-PATTERN: Exposing mutable state across the interop boundary
    val uiState: MutableStateFlow<ProfileState> = MutableStateFlow(ProfileState.Initial)

    fun updateName(name: String) {
        // Direct mutation without concurrency boundary
        uiState.value = uiState.value.copy(name = name)
    }
}
```

#### Production Standard (Correct)
> **Standard**: Maintains strict encapsulation: uiState is immutable from the native boundary. Mutations occur strictly through `_uiState.update` inside the safe `viewModelScope` on `Dispatchers.Main.immediate`.
```kotlin
class ProfileViewModel : ViewModel() {
    private val _uiState = MutableStateFlow<ProfileState>(ProfileState.Initial)
    // Converted to read-only StateFlow before exporting to native targets
    val uiState: StateFlow<ProfileState> = _uiState.asStateFlow()

    fun handleIntent(intent: ProfileIntent) {
        viewModelScope.launch(Dispatchers.Main.immediate) {
            when (intent) {
                is ProfileIntent.UpdateName -> {
                    _uiState.update { it.copy(name = intent.name) }
                }
            }
        }
    }
}
```

### SwiftUI Consumption and Lifecycle Cancellation Barrier

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Using `Task.detached` spawns a concurrent thread outside Swift's cooperative MainActor, leading to race conditions on UI state. The loop lacks automatic cancellation on view dismissal, leaking the underlying Kotlin coroutine subscriber indefinitely.
```swift
struct ProfileView: View {
    @StateObject private var viewModel = ProfileViewModel()
    @State private var state: ProfileState = .initial

    var body: some View {
        Text(state.name)
            .onAppear {
                // ANTI-PATTERN: Unscoped background task leaks Job & bypasses MainActor
                Task.detached {
                    for await item in viewModel.uiState {
                        // Direct mutation of view state from non-isolated background thread
                        state = item
                    }
                }
            }
    }
}
```

#### Production Standard (Correct)
> **Standard**: Using `.task` binds the observation directly to the SwiftUI lifecycle, guaranteeing immediate coroutine cancellation when the view leaves the hierarchy. `@MainActor` ensures memory-safe state assignment without actor re-entrancy issues.
```swift
struct ProfileView: View {
    @StateObject private var viewModel = ProfileViewModel()
    @State private var state: ProfileState = .initial

    var body: some View {
        Text(state.name)
            // Concurrency barrier: Automatically ties cancellation to SwiftUI lifecycle
            .task {
                await observeState()
            }
    }

    @MainActor
    private func observeState() async {
        do {
            for await item in viewModel.uiState {
                self.state = item
            }
        } catch is CancellationError {
            // Gracefully handled; underlying Kotlin coroutine Job is cancelled
        } catch {
            assertionFailure("Unexpected stream failure: \(error)")
        }
    }
}
```

Architectural Specification & Invariant Rationale

Architectural Invariant Design: KMP 2.1 Native StateFlow & Swift Concurrency Memory Safety Barrier

KMP 2.1 Native StateFlow & Swift Concurrency Memory Safety Barrier defines an industrial-grade behavioral standard for mobile engineering. Enforces thread-confined mutation and deterministic cancellation barriers when exposing Kotlin StateFlow/SharedFlow to Apple platforms via Swift Concurrency (async/await and AsyncSequence). Prevents undefined native memory corruption, stale reference leaks, and actor re-entrancy races across the Kotlin Native GC and Swift Cooperative Thread Pool boundary in Kotlin 2.1. Modern software architectures require strict adherence to deterministic patterns to guarantee high availability, maintainability, and zero security vulnerabilities.

Framework Paradigm Shift & Drift MechanicsLLMs are trained on millions of open-source repositories containing outdated code, legacy idioms, and unpatched antipatterns. When coding assistants generate implementations for this stack, they default to common statistical tokens: Direct Swift Observation of Mutable Kotlin StateFlow Across Actor Contexts Without Lifecycle Cancellation and MainActor Enforcement Without an explicit system instruction file, developers spend hours debugging silent failures.
Failure Modes & Production Blast Radius

Hazard Analysis: What Breaks Without This Rule

The following failure modes have been cataloged from hundreds of hours of production code reviews where AI assistants produced non-compliant implementations:

Failure ModeAI Symptom (The Anti-Pattern)SeverityProduction Impact & Remedy
AI Hallucination & Deprecation DriftDirect Swift Observation of Mutable Kotlin StateFlow Across Actor Contexts Without Lifecycle Cancellation and MainActor EnforcementCritical
Violating this industrial standard introduces regression bugs, security risks, and unexpected runtime failures in production.
Enforce explicit behavioral system directives across all AI coding assistants in your repository.
Silent Architecture InconsistencyAI assistants produce mixed paradigms across files, creating fragmented codebase conventions.Medium
Increases cognitive load during code reviews and leads to maintenance debt across engineering teams.
Pin project conventions in .cursor/rules, CLAUDE.md, and AGENTS.md so all team agents follow identical guardrails.
Architectural Directives in Detail

Step-by-Step Production Directives

Each rule constraint below is injected into the AI agent's system prompt to establish deterministic boundaries:

1

Engineers MUST ALWAYS expose Kotlin StateFlow to Swift as a read-only, non-mutable Flow wrapped in an explicitly MainActor-bound AsyncSequence or via verified Swift interop libraries (e.g., SKIE or KMP-NativeCoroutines).

Engineers MUST ALWAYS expose Kotlin StateFlow to Swift as a read-only, non-mutable Flow wrapped in an explicitly MainActor-bound AsyncSequence or via verified Swift interop libraries (e.g., SKIE or KMP-NativeCoroutines).

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
2

Engineers MUST NEVER expose MutableStateFlow or MutableSharedFlow directly into Swift

Engineers MUST NEVER expose MutableStateFlow or MutableSharedFlow directly into Swift; mutations MUST pass through explicit asynchronous command functions (e.g., `fun dispatch(intent: UserIntent)`) confined to the shared ViewModel scope.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
3

Engineers MUST ALWAYS tie every Swift `Task` collecting a Kotlin Native Flow to the parent UI lifecycle (e.g., SwiftUI `.task(id

Engineers MUST ALWAYS tie every Swift `Task` collecting a Kotlin Native Flow to the parent UI lifecycle (e.g., SwiftUI `.task(id:)` or UIKit `TaskGroup`) and verify cancellation propagates back to cancel the underlying Kotlin `Job` immediately.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
4

Swift bridging code MUST NOT access Kotlin coroutine primitives from arbitrary global concurrent actors (`Task.detached`)

Swift bridging code MUST NOT access Kotlin coroutine primitives from arbitrary global concurrent actors (`Task.detached`); all UI state flows MUST be collected strictly on `@MainActor`.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
5

Kotlin Native code in `appleMain` MUST NEVER use blocking Dispatchers like `runBlocking` or synchronous lock-waiting primitives (`ReentrantLock`) when bridging to Swift exported functions.

Kotlin Native code in `appleMain` MUST NEVER use blocking Dispatchers like `runBlocking` or synchronous lock-waiting primitives (`ReentrantLock`) when bridging to Swift exported functions.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
6

Engineers MUST use Kotlin 2.1's memory model invariants, avoiding custom raw freezing or unpinned pointer handoffs across foreign function interfaces.

Engineers MUST use Kotlin 2.1's memory model invariants, avoiding custom raw freezing or unpinned pointer handoffs across foreign function interfaces.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
Technical Questions & Answers

Frequently Asked Technical Questions

Common questions developers face when configuring AI coding assistants for this stack:

Q:Why is KMP 2.1 Native StateFlow & Swift Concurrency Memory Safety Barrier critical for AI coding assistants?

Enforces thread-confined mutation and deterministic cancellation barriers when exposing Kotlin StateFlow/SharedFlow to Apple platforms via Swift Concurrency (async/await and AsyncSequence). Prevents undefined native memory corruption, stale reference leaks, and actor re-entrancy races across the Kotlin Native GC and Swift Cooperative Thread Pool boundary in Kotlin 2.1. Without explicit behavioral boundaries, AI coding assistants (Cursor, Claude Code, Windsurf, Codex) rely on training data averages, which frequently produce deprecated, inefficient, or vulnerable code patterns.

Q:How does adopting this rule prevent AI hallucinations?

This rule explicitly declares what the AI must avoid (Direct Swift Observation of Mutable Kotlin StateFlow Across Actor Contexts Without Lifecycle Cancellation and MainActor Enforcement) and prescribes verified positive examples. Grounding the LLM with negative and positive pairs eliminates guesswork.

Q:Which AI coding environments are supported?

This specification is multi-platform compatible: Cursor (.cursor/rules/*.mdc & .cursorrules), Anthropic Claude Code (CLAUDE.md), Windsurf (.windsurfrules), Codex / Cline (AGENTS.md), and GitHub Copilot (.github/copilot-instructions.md).

Q:Can I combine this rule with other technology stacks?

Yes. Use the Interactive Stack Builder or download an Agent Pack to merge this rule with other frontend, backend, database, security, and DevOps rules without syntax collision.

Open Specification · CC BY 4.0·Free for Personal, Team & Commercial In-Repo Use

Citation & Open Source Attribution Guidelines

This specification is licensed under Creative Commons Attribution 4.0 International (CC BY 4.0). You are completely free to adapt and share this rule in your workspace. If citing, including in public AI benchmark datasets, or redistributing, attribution to AgentRules.org is required.

Related MOBILE Rules

View all rules →
1 Rule in Stack

KMP