This specification is maintained by the AgentRules Working Group. Have enhancements or want to claim maintainership?Submit Specification →
mobilecritical PriorityID: kmp-darwin-memory-coroutine-cancellation-guardrail

KMP Native Memory Alignment and Swift Async/Await Cooperative Cancellation Guardrail

Enforces strict cooperative cancellation semantics and native object lifetime management across the Kotlin/Native and Swift ABI boundary. Eliminates unmanaged reference cycles in Darwin GC integration and prevents task suspension leaks by binding Swift Task cancellations directly to Kotlin Job lifecycles. Mandates defensive dispatch patterns to protect the Darwin main thread from JNI-like frozen pointer deadlocks and unbounded ARC retention.

Prohibited Anti-Pattern: Bridging Kotlin Suspend Functions to Swift Async via Unbounded Task Wrappers and Unmanaged Closures

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: KMP Native Memory Alignment and Swift Async/Await Cooperative Cancellation Guardrail - Enforces strict cooperative cancellation semantics and native object lifetime management across the Kotlin/Native and Swift ABI boundary. Eliminates unmanaged reference cycles in Darwin GC integration and prevents task suspension leaks by binding Swift Task cancellations directly to Kotlin Job lifecycles. Mandates defensive dispatch patterns to protect the Darwin main thread from JNI-like frozen pointer deadlocks and unbounded ARC retention.
globs: **/*.kt, **/*.swift, **/iosMain/**/*.kt, **/commonMain/**/*.kt, **/iosApp/**/*.swift
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/kmp-darwin-memory-coroutine-cancellation-guardrail"
---

# KMP Native Memory Alignment and Swift Async/Await Cooperative Cancellation Guardrail

> **Severity**: CRITICAL | **Category**: mobile
> **Anti-Pattern Warning**: Bridging Kotlin Suspend Functions to Swift Async via Unbounded Task Wrappers and Unmanaged Closures

## System Constraints
You are a Principal Software Architect enforcing production safety at the Kotlin Multiplatform (KMP) and Darwin/Swift interop boundary. You must systematically eliminate thread deadlocks, orphan coroutine execution, and ARC-to-Kotlin GC memory leaks. Mandate that every Kotlin suspend function bridged to Swift async/await implements bidirectional cancellation propagation using native Job handles and withTaskCancellationHandler. Ensure Darwin interop wrappers never capture strong references to long-lived Kotlin native objects within escaping Swift closures.

## Strict Guidelines
- Engineers MUST ALWAYS implement `withTaskCancellationHandler` in Swift when wrapping Kotlin suspend functions or CoroutineScope executions to ensure native `Job.cancel()` is invoked immediately on task abort.
- Engineers MUST NOT bridge Kotlin Flows to Swift `AsyncSequence` without wrapping the collector in an explicit lifecycle-bound scope that tears down coroutine collection upon Swift task teardown or view dismissal.
- Engineers MUST NEVER capture strong references to Kotlin Native root objects or CoroutineScope holders within escaping Darwin escaping closures or detached `Task` blocks.
- Bridged Darwin execution SHOULD use `Dispatchers.Main.immediate` on the Kotlin side instead of generic `Dispatchers.Main` to prevent event-loop re-entrancy latency and retain-cycle deadlocks on iOS.
- Engineers MUST explicitly verify that custom Objective-C/Swift bridge adapters implement `SKIE` or `KMP-NativeCoroutines` cancellation patterns rather than raw `UnsafeContinuation` calls lacking cancellation delegate bindings.

## Bad vs Good Implementations
### Swift async/await Bridge to Kotlin Coroutine with Cooperative Cancellation

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: The continuation wrapper executes the Kotlin coroutine without retaining the returned Kotlin `Cancellable` or `Job`. When the parent Swift `Task` cancels, the underlying Kotlin coroutine remains active in background memory, and the completion closure retains native references indefinitely, leaking Darwin ARC memory and starving CPU threads.
```swift
import Shared

final class ProfileViewModel: ObservableObject {
    private let repository: UserRepository
    
    init(repository: UserRepository) {
        self.repository = repository
    }
    
    func fetchUser(userId: String) async throws -> UserProfile {
        // CRITICAL BUG: Uses raw UnsafeContinuation without Task cancellation tracking.
        // If the Swift view dismisses or the Task cancels, the Kotlin Coroutine
        // keeps running, retaining native pointers and causing GC memory leaks.
        return try await withCheckedThrowingContinuation { continuation in
            repository.getUserProfile(id: userId) { profile, error in
                if let error = error {
                    continuation.resume(throwing: error)
                } else if let profile = profile {
                    continuation.resume(returning: profile)
                }
            }
        }
    }
}
```

#### Production Standard (Correct)
> **Standard**: Using `withTaskCancellationHandler` establishes explicit bidirectional lifecycle propagation. When the Swift runtime cancels the outer task, `job?.cancel(cause: nil)` executes promptly, allowing Kotlin's coroutine engine to terminate and release unmanaged native heap allocations immediately.
```swift
import Shared

final class ProfileViewModel: ObservableObject {
    private let repository: UserRepository
    
    init(repository: UserRepository) {
        self.repository = repository
    }
    
    func fetchUser(userId: String) async throws -> UserProfile {
        var job: Shared.Job? = nil
        
        return try await withTaskCancellationHandler {
            return try await withCheckedThrowingContinuation { continuation in
                job = repository.getUserProfile(id: userId) { profile, error in
                    if let error = error {
                        continuation.resume(throwing: error)
                    } else if let profile = profile {
                        continuation.resume(returning: profile)
                    }
                }
            }
        } onCancel: {
            // Fix: Immediately forward cancellation to native Kotlin coroutine job
            job?.cancel(cause: nil)
        }
    }
}
```

### Kotlin Darwin Flow to Swift AsyncSequence Native Scope Binding

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Using `GlobalScope` creates an immortal root reference that Kotlin's GC cannot clean up when Darwin consumers dismiss their views. The escaping Swift callback `onEvent` is perpetually retained, triggering native heap leaks and potential runtime crashes during app backgrounding.
```kotlin
package com.production.shared.flow

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
import platform.darwin.dispatch_async
import platform.darwin.dispatch_get_main_queue

class DataStreamManager(private val dataSource: Flow<String>) {
    // ANTI-PATTERN: GlobalScope retain-cycle with unmanaged Darwin callback bridge
    @OptIn(DelicateCoroutinesApi::class)
    fun collectEvents(onEvent: (String) -> Unit) {
        GlobalScope.launch(Dispatchers.Main) {
            dataSource.collect { item ->
                // Escaping unmanaged callback to Darwin main thread causes memory leak
                onEvent(item)
            }
        }
    }
}
```

#### Production Standard (Correct)
> **Standard**: Passes an explicit lifecycle-bound `CoroutineScope` and returns a `CancellableJob` interface token to the Darwin layer. This guarantees deterministic teardown of flow collectors and breaks strong reference cycles across the Swift/Kotlin boundary.
```kotlin
package com.production.shared.flow

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*

interface CancellableJob {
    fun cancel()
}

class DataStreamManager(private val dataSource: Flow<String>) {
    fun collectEvents(
        coroutineScope: CoroutineScope,
        onEvent: (String) -> Unit
    ): CancellableJob {
        val job = coroutineScope.launch(Dispatchers.Main.immediate) {
            dataSource.collect { item ->
                onEvent(item)
            }
        }
        
        return object : CancellableJob {
            override fun cancel() {
                job.cancel()
            }
        }
    }
}
```

Recommended MCP Servers (mcp-serverlist.com)

Equip agent with system tools to verify code for this stack.

Recommended Agent Skills (askills.dev)

Ready-to-use executable skill functions tailored to this stack.

Architectural Specification & Invariant Rationale

Architectural Invariant Design: KMP Native Memory Alignment and Swift Async/Await Cooperative Cancellation Guardrail

KMP Native Memory Alignment and Swift Async/Await Cooperative Cancellation Guardrail defines an industrial-grade behavioral standard for mobile engineering. Enforces strict cooperative cancellation semantics and native object lifetime management across the Kotlin/Native and Swift ABI boundary. Eliminates unmanaged reference cycles in Darwin GC integration and prevents task suspension leaks by binding Swift Task cancellations directly to Kotlin Job lifecycles. Mandates defensive dispatch patterns to protect the Darwin main thread from JNI-like frozen pointer deadlocks and unbounded ARC retention. 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: Bridging Kotlin Suspend Functions to Swift Async via Unbounded Task Wrappers and Unmanaged Closures 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 DriftBridging Kotlin Suspend Functions to Swift Async via Unbounded Task Wrappers and Unmanaged ClosuresCritical
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 implement `withTaskCancellationHandler` in Swift when wrapping Kotlin suspend functions or CoroutineScope executions to ensure native `Job.cancel()` is invoked immediately on task abort.

Engineers MUST ALWAYS implement `withTaskCancellationHandler` in Swift when wrapping Kotlin suspend functions or CoroutineScope executions to ensure native `Job.cancel()` is invoked immediately on task abort.

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 NOT bridge Kotlin Flows to Swift `AsyncSequence` without wrapping the collector in an explicit lifecycle-bound scope that tears down coroutine collection upon Swift task teardown or view dismissal.

Engineers MUST NOT bridge Kotlin Flows to Swift `AsyncSequence` without wrapping the collector in an explicit lifecycle-bound scope that tears down coroutine collection upon Swift task teardown or view dismissal.

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 NEVER capture strong references to Kotlin Native root objects or CoroutineScope holders within escaping Darwin escaping closures or detached `Task` blocks.

Engineers MUST NEVER capture strong references to Kotlin Native root objects or CoroutineScope holders within escaping Darwin escaping closures or detached `Task` blocks.

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

Bridged Darwin execution SHOULD use `Dispatchers.Main.immediate` on the Kotlin side instead of generic `Dispatchers.Main` to prevent event-loop re-entrancy latency and retain-cycle deadlocks on iOS.

Bridged Darwin execution SHOULD use `Dispatchers.Main.immediate` on the Kotlin side instead of generic `Dispatchers.Main` to prevent event-loop re-entrancy latency and retain-cycle deadlocks on iOS.

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

Engineers MUST explicitly verify that custom Objective-C/Swift bridge adapters implement `SKIE` or `KMP-NativeCoroutines` cancellation patterns rather than raw `UnsafeContinuation` calls lacking cancellation delegate bindings.

Engineers MUST explicitly verify that custom Objective-C/Swift bridge adapters implement `SKIE` or `KMP-NativeCoroutines` cancellation patterns rather than raw `UnsafeContinuation` calls lacking cancellation delegate bindings.

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 Native Memory Alignment and Swift Async/Await Cooperative Cancellation Guardrail critical for AI coding assistants?

Enforces strict cooperative cancellation semantics and native object lifetime management across the Kotlin/Native and Swift ABI boundary. Eliminates unmanaged reference cycles in Darwin GC integration and prevents task suspension leaks by binding Swift Task cancellations directly to Kotlin Job lifecycles. Mandates defensive dispatch patterns to protect the Darwin main thread from JNI-like frozen pointer deadlocks and unbounded ARC retention. 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 (Bridging Kotlin Suspend Functions to Swift Async via Unbounded Task Wrappers and Unmanaged Closures) 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