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

Kotlin Multiplatform Swift Coroutine Scope and Task Cancellation Bridging

Enforces deterministic structured concurrency bridging between Swift Task lifecycles and Kotlin CoroutineScopes. Prevents orphaned background execution, thread starvation, and memory leaks caused by unpropagated Swift async Task cancellation into Kotlin/Native Job hierarchies.

Prohibited Anti-Pattern: Orphaned Kotlin Jobs Executing Indefinitely After Swift Task Cancellation or SwiftUI View Dismissal

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: Kotlin Multiplatform Swift Coroutine Scope and Task Cancellation Bridging - Enforces deterministic structured concurrency bridging between Swift Task lifecycles and Kotlin CoroutineScopes. Prevents orphaned background execution, thread starvation, and memory leaks caused by unpropagated Swift async Task cancellation into Kotlin/Native Job hierarchies.
globs: iosApp/**/*.swift, shared/src/iosMain/**/*.kt, shared/src/commonMain/**/*.kt
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/kmp-swift-coroutine-scope-cancellation-standard"
---

# Kotlin Multiplatform Swift Coroutine Scope and Task Cancellation Bridging

> **Severity**: CRITICAL | **Category**: mobile
> **Anti-Pattern Warning**: Orphaned Kotlin Jobs Executing Indefinitely After Swift Task Cancellation or SwiftUI View Dismissal

## System Constraints
You are a Principal Mobile Architect enforcing strict structured concurrency contracts across Kotlin Multiplatform and Swift boundaries. You mandate that all Kotlin suspend functions and Flow emissions exposed to Swift via Objective-C/Swift interop MUST tie directly into Swift Task cancellation lifecycles using deterministic Job cancellation handlers or certified interop toolchains (SKIE or KMP-NativeCoroutines). Raw unmanaged Kotlin CoroutineScope instances MUST NEVER outlive their parent Swift Task or UI lifecycle.

## Strict Guidelines
- Engineers MUST ALWAYS bridge Swift Task cancellation directly to the underlying Kotlin Job using withTaskCancellationHandler or an equivalent deterministic token.
- Engineers MUST NOT rely on default Kotlin/Native Obj-C async bridging for long-running or streaming operations, as default Swift async interop does not propagate task.cancel() to Kotlin Coroutines.
- Flows exposed to Swift MUST be wrapped with active cancellation tokens that invoke Job.cancel() immediately upon SwiftUI .onDisappear or AsyncSequence termination.
- Kotlin Common code MUST expose explicit disposable handles (e.g., Job.asCancellable() or SKIE-generated async wrappers) for any suspend function invoked by iOS runtimes.
- Swift ViewModels and UI controllers MUST cancel their bound Task handles inside deinit or onDisappear to eliminate orphaned background processing.

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

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Default Swift async wrappers generated by Kotlin/Native compiler do not propagate Swift Task cancellation down to the Kotlin Job. When the user navigates away and the SwiftUI Task cancels, the Kotlin Coroutine continues executing, wasting CPU, network, and memory.
```swift
import SwiftUI
import SharedKit

struct UserProfileView: View {
    @State private var profile: UserProfile?
    let userId: String
    let repository: UserRepository

    var body: some View {
        VStack {
            if let profile = profile {
                Text(profile.name)
            } else {
                ProgressView()
            }
        }
        .task {
            // CRITICAL DEFECT: Default KMP ObjC-export async wrapper does NOT cancel
            // the underlying Kotlin Job when this SwiftUI Task is cancelled on view dismissal.
            // The Kotlin network request and database update run to completion in the background.
            do {
                self.profile = try await repository.fetchProfile(id: userId)
            } catch {
                print("Fetch failed: \(error)")
            }
        }
    }
}
```

#### Production Standard (Correct)
> **Standard**: Uses withTaskCancellationHandler to guarantee that whenever the Swift Task is cancelled (e.g. view dismissal or explicit task.cancel()), the Kotlin Job's cancel() method is invoked immediately, stopping execution on the Kotlin side.
```swift
import SwiftUI
import SharedKit

struct UserProfileView: View {
    @State private var profile: UserProfile?
    let userId: String
    let repository: UserRepository

    var body: some View {
        VStack {
            if let profile = profile {
                Text(profile.name)
            } else {
                ProgressView()
            }
        }
        .task {
            // SAFE: Deterministically binds Swift Task lifecycle to Kotlin Job cancellation
            var jobHandle: SharedKit.CancellableJob? = nil
            do {
                try await withTaskCancellationHandler {
                    try Task.checkCancellation()
                    self.profile = try await withCheckedThrowingContinuation { continuation in
                        jobHandle = repository.fetchProfileCancellable(id: userId) { result, error in
                            if let error = error {
                                continuation.resume(throwing: error)
                            } else if let result = result {
                                continuation.resume(returning: result)
                            }
                        }
                    }
                } onCancel: {
                    // Explicitly cancel the underlying Kotlin coroutine scope/job
                    jobHandle?.cancel()
                }
            } catch is CancellationError {
                // Structured concurrency gracefully aborted
            } catch {
                print("Fetch failed: \(error)")
            }
        }
    }
}
```

Architectural Specification & Invariant Rationale

Architectural Invariant Design: Kotlin Multiplatform Swift Coroutine Scope and Task Cancellation Bridging

Kotlin Multiplatform Swift Coroutine Scope and Task Cancellation Bridging defines an industrial-grade behavioral standard for mobile engineering. Enforces deterministic structured concurrency bridging between Swift Task lifecycles and Kotlin CoroutineScopes. Prevents orphaned background execution, thread starvation, and memory leaks caused by unpropagated Swift async Task cancellation into Kotlin/Native Job hierarchies. 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: Orphaned Kotlin Jobs Executing Indefinitely After Swift Task Cancellation or SwiftUI View Dismissal 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 DriftOrphaned Kotlin Jobs Executing Indefinitely After Swift Task Cancellation or SwiftUI View DismissalCritical
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 bridge Swift Task cancellation directly to the underlying Kotlin Job using withTaskCancellationHandler or an equivalent deterministic token.

Engineers MUST ALWAYS bridge Swift Task cancellation directly to the underlying Kotlin Job using withTaskCancellationHandler or an equivalent deterministic token.

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 rely on default Kotlin/Native Obj-C async bridging for long-running or streaming operations, as default Swift async interop does not propagate task.cancel() to Kotlin Coroutines.

Engineers MUST NOT rely on default Kotlin/Native Obj-C async bridging for long-running or streaming operations, as default Swift async interop does not propagate task.cancel() to Kotlin Coroutines.

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

Flows exposed to Swift MUST be wrapped with active cancellation tokens that invoke Job.cancel() immediately upon SwiftUI .onDisappear or AsyncSequence termination.

Flows exposed to Swift MUST be wrapped with active cancellation tokens that invoke Job.cancel() immediately upon SwiftUI .onDisappear or AsyncSequence termination.

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 Common code MUST expose explicit disposable handles (e.g., Job.asCancellable() or SKIE-generated async wrappers) for any suspend function invoked by iOS runtimes.

Kotlin Common code MUST expose explicit disposable handles (e.g., Job.asCancellable() or SKIE-generated async wrappers) for any suspend function invoked by iOS runtimes.

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

Swift ViewModels and UI controllers MUST cancel their bound Task handles inside deinit or onDisappear to eliminate orphaned background processing.

Swift ViewModels and UI controllers MUST cancel their bound Task handles inside deinit or onDisappear to eliminate orphaned background processing.

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 Swift Coroutine Scope and Task Cancellation Bridging critical for AI coding assistants?

Enforces deterministic structured concurrency bridging between Swift Task lifecycles and Kotlin CoroutineScopes. Prevents orphaned background execution, thread starvation, and memory leaks caused by unpropagated Swift async Task cancellation into Kotlin/Native Job hierarchies. 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 (Orphaned Kotlin Jobs Executing Indefinitely After Swift Task Cancellation or SwiftUI View Dismissal) 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