This specification is maintained by the AgentRules Working Group. Have enhancements or want to claim maintainership?Submit Specification →
mobilecritical PriorityID: kmp-swift-export-structured-concurrency-bridge

Kotlin Multiplatform 2.1 Swift Export Structured Concurrency Invariants

Enforces deterministic bidirectional lifecycle and cancellation binding between Apple Swift Structured Concurrency (Task trees) and Kotlin Native Coroutine Jobs under Kotlin 2.1 Swift Export. Eliminates cross-runtime ARC-to-GC memory leaks, dangling coroutine scopes, and thread-pool exhaustion caused by unpropagated task cancellations across the FFI boundary.

Prohibited Anti-Pattern: Dangling Kotlin Coroutine Jobs and Leaked Continuations from Unpropagated Swift Task Cancellation

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: Kotlin Multiplatform 2.1 Swift Export Structured Concurrency Invariants - Enforces deterministic bidirectional lifecycle and cancellation binding between Apple Swift Structured Concurrency (Task trees) and Kotlin Native Coroutine Jobs under Kotlin 2.1 Swift Export. Eliminates cross-runtime ARC-to-GC memory leaks, dangling coroutine scopes, and thread-pool exhaustion caused by unpropagated task cancellations across the FFI boundary.
globs: **/*.kt, **/*.swift
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/kmp-swift-export-structured-concurrency-bridge"
---

# Kotlin Multiplatform 2.1 Swift Export Structured Concurrency Invariants

> **Severity**: CRITICAL | **Category**: mobile
> **Anti-Pattern Warning**: Dangling Kotlin Coroutine Jobs and Leaked Continuations from Unpropagated Swift Task Cancellation

## System Constraints
You are a Principal Software Architect enforcing bidirectional structured concurrency invariants for Kotlin Multiplatform 2.1 Swift Export. In KMP 2.1, Kotlin suspend functions exported to Swift async functions or bridged via custom Native runtimes must guarantee that Swift Task cancellation deterministically cancels the underlying Kotlin Coroutine Job, and Kotlin CancellationExceptions cleanly translate to Swift CancellationError without dangling Kotlin Continuation references or retaining strong cycles across ARC and Kotlin Garbage Collection.

## Strict Guidelines
- Engineers MUST ALWAYS wire Swift Task cancellation directly into the underlying Kotlin Job cancellation using `withTaskCancellationHandler` or an explicit cancellation token when crossing the KMP FFI boundary.
- Engineers MUST NOT allow Kotlin suspend continuations to remain suspended indefinitely when a Swift caller cancels, which prevents Kotlin GC and iOS ARC from releasing cross-runtime boundary closures.
- Swift bridging code MUST map Kotlin `kotlinx.coroutines.CancellationException` directly into Swift `CancellationError` rather than letting it manifest as an unhandled generic NSError or runtime exception.
- Kotlin-exposed APIs for Swift consumption MUST NOT use global unbounded scopes (`GlobalScope`); all operations MUST be rooted in an explicit, lifecycle-aware `CoroutineScope` owned by a tracked boundary controller.
- Engineers MUST ALWAYS avoid blocking the Swift MainActor or Darwin thread pool waiting synchronously for a Kotlin Coroutine result, preventing bidirectional dispatcher deadlocks.
- Shared state exposed between Swift actors and Kotlin Coroutine contexts MUST be immutable or mediated through thread-safe atomics / Kotlin 2.1 freeze-free state holders.

## Bad vs Good Implementations
### Bridging Swift Task Cancellation to Kotlin Coroutine Job

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Directly calling an unmanaged cross-runtime suspend function without a cancellation handler leaves the Kotlin Job running if the Swift Task is cancelled. The held Kotlin Continuation keeps the ARC reference alive, inducing cross-runtime memory leaks and wasted I/O resources.
```swift
// ANTI-PATTERN: Leaks Kotlin coroutine and cross-runtime reference on cancellation
import SharedKit

func fetchUserData(userId: String) async throws -> UserProfile {
    // Invoking exported suspend function directly across Swift Export boundary
    // When the enclosing Swift Task is cancelled, the Kotlin Coroutine continues executing,
    // retaining Swift ARC pointers and Kotlin objects until completion or deadlock.
    let userBridge = SharedKit.UserManager()
    return try await userBridge.getUserProfile(id: userId)
}
```

#### Production Standard (Correct)
> **Standard**: Using `withTaskCancellationHandler` establishes a bidirectional lifecycle link. If the Swift Task is cancelled, `activeJob?.cancel()` is immediately triggered on the Kotlin side, tearing down coroutine resources and translating `CancellationException` to Swift's standard `CancellationError`.
```swift
// PRODUCTION STANDARD: Explicit Swift Task Cancellation Handled via Kotlin Job Bridge
import SharedKit

func fetchUserData(userId: String) async throws -> UserProfile {
    let userBridge = SharedKit.UserManager()
    var activeJob: SharedKit.Job? = nil

    return try await withTaskCancellationHandler {
        // Cooperative execution with Kotlin cancellation mapping
        return try await withCheckedThrowingContinuation { continuation in
            activeJob = userBridge.getUserProfileCancellable(id: userId) { profile, error in
                if let error = error {
                    if error.isKotlinCancellationException() {
                        continuation.resume(throwing: CancellationError())
                    } else {
                        continuation.resume(throwing: error)
                    }
                } else if let profile = profile {
                    continuation.resume(returning: profile)
                } else {
                    continuation.resume(throwing: FatalBridgeError.unexpectedNilResult)
                }
            }
        }
    } onCancel: {
        // Swift Task cancellation directly cancels the Kotlin Job hierarchy
        activeJob?.cancel(cause: nil)
    }
}
```

### Kotlin Side Cancellable Bridge Scope for Swift Export

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Using GlobalScope removes structured concurrency guarantees. Swift cannot signal cancellation back into Kotlin, leading to background thread pollution and uncollectible ARC closures across the KMP runtime.
```kotlin
// ANTI-PATTERN: Uncancellable suspend invocation exposed to Swift
package com.platform.bridge

import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch

class UserManager {
    // Leaks execution; cannot be cancelled from Swift runtime
    fun getUserProfileAsync(id: String, callback: (UserProfile?, Throwable?) -> Unit) {
        GlobalScope.launch {
            val profile = repository.fetchProfile(id)
            callback(profile, null)
        }
    }
}
```

#### Production Standard (Correct)
> **Standard**: Returns a Coroutine `Job` reference across the KMP bridge and handles `CancellationException` explicitly, ensuring the Swift caller receives the exact cancellation signal and Swift Export memory boundaries are cleaned up immediately.
```kotlin
// PRODUCTION STANDARD: Return explicit Job handle to Swift caller
package com.platform.bridge

import kotlinx.coroutines.*

class UserManager(private val supervisorScope: CoroutineScope) {
    /**
     * Returns a [Job] handle that Swift structured concurrency binds to
     * via `withTaskCancellationHandler`.
     */
    fun getUserProfileCancellable(
        id: String,
        callback: (UserProfile?, Throwable?) -> Unit
    ): Job {
        return supervisorScope.launch(Dispatchers.Default) {
            try {
                val profile = repository.fetchProfile(id)
                callback(profile, null)
            } catch (e: CancellationException) {
                callback(null, e)
                throw e
            } catch (t: Throwable) {
                callback(null, t)
            }
        }
    }
}
```

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: Kotlin Multiplatform 2.1 Swift Export Structured Concurrency Invariants

Kotlin Multiplatform 2.1 Swift Export Structured Concurrency Invariants defines an industrial-grade behavioral standard for mobile engineering. Enforces deterministic bidirectional lifecycle and cancellation binding between Apple Swift Structured Concurrency (Task trees) and Kotlin Native Coroutine Jobs under Kotlin 2.1 Swift Export. Eliminates cross-runtime ARC-to-GC memory leaks, dangling coroutine scopes, and thread-pool exhaustion caused by unpropagated task cancellations across the FFI boundary. 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: Dangling Kotlin Coroutine Jobs and Leaked Continuations from Unpropagated Swift Task Cancellation 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 DriftDangling Kotlin Coroutine Jobs and Leaked Continuations from Unpropagated Swift Task CancellationCritical
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 wire Swift Task cancellation directly into the underlying Kotlin Job cancellation using `withTaskCancellationHandler` or an explicit cancellation token when crossing the KMP FFI boundary.

Engineers MUST ALWAYS wire Swift Task cancellation directly into the underlying Kotlin Job cancellation using `withTaskCancellationHandler` or an explicit cancellation token when crossing the KMP FFI boundary.

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 allow Kotlin suspend continuations to remain suspended indefinitely when a Swift caller cancels, which prevents Kotlin GC and iOS ARC from releasing cross-runtime boundary closures.

Engineers MUST NOT allow Kotlin suspend continuations to remain suspended indefinitely when a Swift caller cancels, which prevents Kotlin GC and iOS ARC from releasing cross-runtime boundary closures.

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

Swift bridging code MUST map Kotlin `kotlinx.coroutines.CancellationException` directly into Swift `CancellationError` rather than letting it manifest as an unhandled generic NSError or runtime exception.

Swift bridging code MUST map Kotlin `kotlinx.coroutines.CancellationException` directly into Swift `CancellationError` rather than letting it manifest as an unhandled generic NSError or runtime exception.

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

Kotlin-exposed APIs for Swift consumption MUST NOT use global unbounded scopes (`GlobalScope`)

Kotlin-exposed APIs for Swift consumption MUST NOT use global unbounded scopes (`GlobalScope`); all operations MUST be rooted in an explicit, lifecycle-aware `CoroutineScope` owned by a tracked boundary controller.

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 ALWAYS avoid blocking the Swift MainActor or Darwin thread pool waiting synchronously for a Kotlin Coroutine result, preventing bidirectional dispatcher deadlocks.

Engineers MUST ALWAYS avoid blocking the Swift MainActor or Darwin thread pool waiting synchronously for a Kotlin Coroutine result, preventing bidirectional dispatcher deadlocks.

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

Shared state exposed between Swift actors and Kotlin Coroutine contexts MUST be immutable or mediated through thread-safe atomics / Kotlin 2.1 freeze-free state holders.

Shared state exposed between Swift actors and Kotlin Coroutine contexts MUST be immutable or mediated through thread-safe atomics / Kotlin 2.1 freeze-free state holders.

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 Kotlin Multiplatform 2.1 Swift Export Structured Concurrency Invariants critical for AI coding assistants?

Enforces deterministic bidirectional lifecycle and cancellation binding between Apple Swift Structured Concurrency (Task trees) and Kotlin Native Coroutine Jobs under Kotlin 2.1 Swift Export. Eliminates cross-runtime ARC-to-GC memory leaks, dangling coroutine scopes, and thread-pool exhaustion caused by unpropagated task cancellations across the FFI boundary. 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 (Dangling Kotlin Coroutine Jobs and Leaked Continuations from Unpropagated Swift Task Cancellation) 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

Kotlin