This specification is maintained by the AgentRules Working Group. Have enhancements or want to claim maintainership?Submit Specification →
mobilecritical PriorityID: kmp-swift-export-memory-lifecycle-guardrail-kotlin-multiplat-178

KMP Swift-Export Cross-Runtime ARC/GC Memory Lifecycle Guardrail

Enforces strict lifecycle decoupling and deterministic cancellation bridges between Apple ARC and Kotlin Native GC. Prevents permanent cross-runtime memory leaks caused by circular references between Swift modern concurrency tasks and Kotlin coroutine Flow collectors.

Prohibited Anti-Pattern: Unbounded Swift Concurrency AsyncStream Retaining Kotlin Coroutines Creating Invisible Cross-Runtime Zombie Islands

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: KMP Swift-Export Cross-Runtime ARC/GC Memory Lifecycle Guardrail - Enforces strict lifecycle decoupling and deterministic cancellation bridges between Apple ARC and Kotlin Native GC. Prevents permanent cross-runtime memory leaks caused by circular references between Swift modern concurrency tasks and Kotlin coroutine Flow collectors.
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-export-memory-lifecycle-guardrail-kotlin-multiplat-178"
---

# KMP Swift-Export Cross-Runtime ARC/GC Memory Lifecycle Guardrail

> **Severity**: CRITICAL | **Category**: mobile
> **Anti-Pattern Warning**: Unbounded Swift Concurrency AsyncStream Retaining Kotlin Coroutines Creating Invisible Cross-Runtime Zombie Islands

## System Constraints
You are a Principal Mobile Architect enforcing strict cross-runtime ARC-GC memory safety in Kotlin Multiplatform (KMP) codebases utilizing Swift-Export and Swift Concurrency. Mandate deterministic cancellation bridges, explicit weak captures, and structured teardown to prevent uncollected cross-runtime reference cycles.

## Strict Guidelines
- Engineers MUST ALWAYS bind Swift Concurrency Task cancellation directly to Kotlin coroutine Job cancellation using AsyncStream.onTermination or withTaskCancellationHandler.
- Engineers MUST NOT strongly capture Swift reference types (such as @Observable models, actors, or UIViewController instances) within Kotlin Flow collection closures.
- Swift bridging wrappers MUST manage Swift AsyncStream continuations with explicit termination guards to prevent indefinite retain graph pinning across the Objective-C/Swift-Export boundary.
- Kotlin-exported coroutine bridge classes MUST expose an idempotent, thread-safe close() or cancel() method conforming to Swift's Sendable lifecycle patterns.
- Native Swift UI layers NEVER subscribe to raw Kotlin Flow or StateFlow instances without scoping the subscription to a managed Swift Task tied to a visible view hierarchy lifecycle.

## Bad vs Good Implementations
### Bridging Kotlin StateFlow to Swift AsyncStream with Lifecycle Cancellation

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: The watch closure retains self strongly in Swift ARC, while the Kotlin StateFlow collector retains the closure in Kotlin GC. Because neither garbage collector can traverse the foreign runtime's heap references, an invisible, uncollectable cross-runtime circular retain leak occurs.
```swift
import SwiftUI
import SharedKit

@Observable
final class UserProfileViewModel {
    var state: UserState = .initial
    private let userFlow: KotlinStateFlow<UserState>
    
    init(userFlow: KotlinStateFlow<UserState>) {
        self.userFlow = userFlow
        // ANTI-PATTERN: Strong capture of self across the Swift-Kotlin bridge;
        // Kotlin GC holds the observer closure, while Swift ARC holds userFlow.
        // No cancellation hook exists, pinning both runtimes permanently.
        userFlow.watch { state in
            self.state = state
        }
    }
}
```

#### Production Standard (Correct)
> **Standard**: Wraps the Kotlin StateFlow in a lifecycle-aware Swift AsyncStream. The continuation uses [weak continuation] and registers continuation.onTermination to cancel the underlying Kotlin collector. The consuming Task captures self weakly and cleanly cancels upon viewModel deinit.
```swift
import SwiftUI
import SharedKit

@Observable
@MainActor
final class UserProfileViewModel {
    private(set) var state: UserState = .initial
    private var streamTask: Task<Void, Never>?
    
    func bind(to userFlow: KotlinStateFlow<UserState>) {
        streamTask?.cancel()
        
        let stream = AsyncStream<UserState> { continuation in
            let cancellable = userFlow.watch { [weak continuation] state in
                continuation?.yield(state)
            }
            continuation.onTermination = { _ in
                cancellable.cancel()
            }
        }
        
        streamTask = Task { [weak self] in
            for await nextState in stream {
                guard !Task.isCancelled, let self else { break }
                self.state = nextState
            }
        }
    }
    
    deinit {
        streamTask?.cancel()
    }
}
```

Architectural Specification & Invariant Rationale

Architectural Invariant Design: KMP Swift-Export Cross-Runtime ARC/GC Memory Lifecycle Guardrail

KMP Swift-Export Cross-Runtime ARC/GC Memory Lifecycle Guardrail defines an industrial-grade behavioral standard for mobile engineering. Enforces strict lifecycle decoupling and deterministic cancellation bridges between Apple ARC and Kotlin Native GC. Prevents permanent cross-runtime memory leaks caused by circular references between Swift modern concurrency tasks and Kotlin coroutine Flow collectors. 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: Unbounded Swift Concurrency AsyncStream Retaining Kotlin Coroutines Creating Invisible Cross-Runtime Zombie Islands 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 DriftUnbounded Swift Concurrency AsyncStream Retaining Kotlin Coroutines Creating Invisible Cross-Runtime Zombie IslandsCritical
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 bind Swift Concurrency Task cancellation directly to Kotlin coroutine Job cancellation using AsyncStream.onTermination or withTaskCancellationHandler.

Engineers MUST ALWAYS bind Swift Concurrency Task cancellation directly to Kotlin coroutine Job cancellation using AsyncStream.onTermination or withTaskCancellationHandler.

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 strongly capture Swift reference types (such as @Observable models, actors, or UIViewController instances) within Kotlin Flow collection closures.

Engineers MUST NOT strongly capture Swift reference types (such as @Observable models, actors, or UIViewController instances) within Kotlin Flow collection 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 wrappers MUST manage Swift AsyncStream continuations with explicit termination guards to prevent indefinite retain graph pinning across the Objective-C/Swift-Export boundary.

Swift bridging wrappers MUST manage Swift AsyncStream continuations with explicit termination guards to prevent indefinite retain graph pinning across the Objective-C/Swift-Export 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.
4

Kotlin-exported coroutine bridge classes MUST expose an idempotent, thread-safe close() or cancel() method conforming to Swift's Sendable lifecycle patterns.

Kotlin-exported coroutine bridge classes MUST expose an idempotent, thread-safe close() or cancel() method conforming to Swift's Sendable lifecycle patterns.

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

Native Swift UI layers NEVER subscribe to raw Kotlin Flow or StateFlow instances without scoping the subscription to a managed Swift Task tied to a visible view hierarchy lifecycle.

Native Swift UI layers NEVER subscribe to raw Kotlin Flow or StateFlow instances without scoping the subscription to a managed Swift Task tied to a visible view hierarchy lifecycle.

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 Swift-Export Cross-Runtime ARC/GC Memory Lifecycle Guardrail critical for AI coding assistants?

Enforces strict lifecycle decoupling and deterministic cancellation bridges between Apple ARC and Kotlin Native GC. Prevents permanent cross-runtime memory leaks caused by circular references between Swift modern concurrency tasks and Kotlin coroutine Flow collectors. 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 (Unbounded Swift Concurrency AsyncStream Retaining Kotlin Coroutines Creating Invisible Cross-Runtime Zombie Islands) 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