This specification is maintained by the AgentRules Working Group. Have enhancements or want to claim maintainership?Submit Specification →
mobilecritical PriorityID: kmp-native-dual-gc-cross-bridge-lifecycle

Kotlin/Native to Swift ARC Dual-GC Bridge Lifecycle Detachment Invariant

Governs the boundary between Kotlin/Native concurrent tracing GC and Swift Automatic Reference Counting (ARC) to prevent cross-runtime reference cycles and memory leaks. Requires explicit lifecycle detachment, deterministic cancellation of asynchronous subscriptions, and weak callback references across the Objective-C/Swift bridge.

Prohibited Anti-Pattern: Unbounded Cross-Bridge Closures and Undisposed Flow Observers Between Kotlin GC and Swift ARC

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: Kotlin/Native to Swift ARC Dual-GC Bridge Lifecycle Detachment Invariant - Governs the boundary between Kotlin/Native concurrent tracing GC and Swift Automatic Reference Counting (ARC) to prevent cross-runtime reference cycles and memory leaks. Requires explicit lifecycle detachment, deterministic cancellation of asynchronous subscriptions, and weak callback references across the Objective-C/Swift bridge.
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-native-dual-gc-cross-bridge-lifecycle"
---

# Kotlin/Native to Swift ARC Dual-GC Bridge Lifecycle Detachment Invariant

> **Severity**: CRITICAL | **Category**: mobile
> **Anti-Pattern Warning**: Unbounded Cross-Bridge Closures and Undisposed Flow Observers Between Kotlin GC and Swift ARC

## System Constraints
You are a Principal Software Architect enforcing Kotlin Multiplatform (KMP) Kotlin/Native Dual-GC Cross-Bridge invariants. The Swift/Objective-C ARC runtime and the Kotlin/Native concurrent tracing GC do not possess unified heap visibility; reference cycles spanning the boundary cannot be detected or collected automatically. Mandate strict deterministic lifecycle teardown, explicit disposable/cancellation tokens, weak capture semantics on all cross-bridge delegates, and zero circular strong dependencies between Kotlin ViewModels and Swift UI hosts.

## Strict Guidelines
- Engineers MUST ALWAYS implement and invoke an explicit deterministic detachment mechanism (such as `DisposableHandle.dispose()`, `Job.cancel()`, or a dedicated `detach()` lifecycle method) in Swift `deinit` or SwiftUI `onDisappear` for any Kotlin Flow, coroutine, or listener.
- Engineers MUST NOT capture Swift instances strongly inside closures or delegate adapters passed into Kotlin/Native exported objects.
- Swift wrapper classes binding Kotlin state SHOULD store bridge references inside a single lifecycle-scoped container that nullifies references upon view hierarchy dismissal.
- Services MUST ensure any Kotlin coroutine scope bridged to iOS terminates when the associated Swift UI coordinator is dismantled, preventing orphan coroutines from retaining Swift bridge handles indefinitely.
- Components NEVER rely on Swift ARC deinit or Kotlin finalizers alone to resolve cross-boundary cycles; circular references between ARC proxies and Kotlin heap references permanently pin native memory.

## Bad vs Good Implementations
### SwiftUI ViewModel Observing Kotlin CommonFlow Across Bridge

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: The Kotlin Flow watcher creates an Objective-C block wrapper retaining 'self' strongly, while 'ProfileViewModel' retains 'kotlinViewModel'. Because ARC and Kotlin GC have disjoint heaps, neither runtime detects the cycle, causing permanent native heap leaks and runaway coroutine execution.
```swift
import SwiftUI
import SharedKit

final class ProfileViewModel: ObservableObject {
    @Published var uiState: ProfileUiState = .initial
    private let kotlinViewModel: SharedProfileViewModel
    
    init(kotlinViewModel: SharedProfileViewModel) {
        self.kotlinViewModel = kotlinViewModel
        // ANTI-PATTERN: Strong capture of self in Kotlin callback closure;
        // DisposableHandle is ignored. Kotlin/Native GC retains proxy; Swift ARC retains Kotlin object.
        // Neither GC nor ARC can detect this cross-runtime cycle.
        kotlinViewModel.uiState.watch { state in
            self.uiState = state
        }
    }
}
```

#### Production Standard (Correct)
> **Standard**: Enforces dual-GC isolation: [weak self] breaks the ARC-to-Kotlin closure cycle, the DisposableHandle is explicitly stored, and Swift deinit/detach guarantees deterministic disposal of the Kotlin coroutine collector.
```swift
import SwiftUI
import SharedKit

final class ProfileViewModel: ObservableObject {
    @Published var uiState: ProfileUiState = .initial
    private let kotlinViewModel: SharedProfileViewModel
    private var stateWatcherTask: SharedKit.DisposableHandle?
    
    init(kotlinViewModel: SharedProfileViewModel) {
        self.kotlinViewModel = kotlinViewModel
    }
    
    func startObserving() {
        // Invariant: Weak capture of Swift target + explicit DisposableHandle tracking
        stateWatcherTask = kotlinViewModel.uiState.watch { [weak self] state in
            guard let self = self else { return }
            self.uiState = state
        }
    }
    
    func detach() {
        // Invariant: Deterministic cross-bridge detachment
        stateWatcherTask?.dispose()
        stateWatcherTask = nil
        kotlinViewModel.onCleared()
    }
    
    deinit {
        detach()
    }
}
```

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/Native to Swift ARC Dual-GC Bridge Lifecycle Detachment Invariant

Kotlin/Native to Swift ARC Dual-GC Bridge Lifecycle Detachment Invariant defines an industrial-grade behavioral standard for mobile engineering. Governs the boundary between Kotlin/Native concurrent tracing GC and Swift Automatic Reference Counting (ARC) to prevent cross-runtime reference cycles and memory leaks. Requires explicit lifecycle detachment, deterministic cancellation of asynchronous subscriptions, and weak callback references across the Objective-C/Swift bridge. 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 Cross-Bridge Closures and Undisposed Flow Observers Between Kotlin GC and Swift ARC 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 Cross-Bridge Closures and Undisposed Flow Observers Between Kotlin GC and Swift ARCCritical
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 and invoke an explicit deterministic detachment mechanism (such as `DisposableHandle.dispose()`, `Job.cancel()`, or a dedicated `detach()` lifecycle method) in Swift `deinit` or SwiftUI `onDisappear` for any Kotlin Flow, coroutine, or listener.

Engineers MUST ALWAYS implement and invoke an explicit deterministic detachment mechanism (such as `DisposableHandle.dispose()`, `Job.cancel()`, or a dedicated `detach()` lifecycle method) in Swift `deinit` or SwiftUI `onDisappear` for any Kotlin Flow, coroutine, or listener.

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 capture Swift instances strongly inside closures or delegate adapters passed into Kotlin/Native exported objects.

Engineers MUST NOT capture Swift instances strongly inside closures or delegate adapters passed into Kotlin/Native exported objects.

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 wrapper classes binding Kotlin state SHOULD store bridge references inside a single lifecycle-scoped container that nullifies references upon view hierarchy dismissal.

Swift wrapper classes binding Kotlin state SHOULD store bridge references inside a single lifecycle-scoped container that nullifies references upon view hierarchy 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.
4

Services MUST ensure any Kotlin coroutine scope bridged to iOS terminates when the associated Swift UI coordinator is dismantled, preventing orphan coroutines from retaining Swift bridge handles indefinitely.

Services MUST ensure any Kotlin coroutine scope bridged to iOS terminates when the associated Swift UI coordinator is dismantled, preventing orphan coroutines from retaining Swift bridge handles indefinitely.

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

Components NEVER rely on Swift ARC deinit or Kotlin finalizers alone to resolve cross-boundary cycles

Components NEVER rely on Swift ARC deinit or Kotlin finalizers alone to resolve cross-boundary cycles; circular references between ARC proxies and Kotlin heap references permanently pin native memory.

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/Native to Swift ARC Dual-GC Bridge Lifecycle Detachment Invariant critical for AI coding assistants?

Governs the boundary between Kotlin/Native concurrent tracing GC and Swift Automatic Reference Counting (ARC) to prevent cross-runtime reference cycles and memory leaks. Requires explicit lifecycle detachment, deterministic cancellation of asynchronous subscriptions, and weak callback references across the Objective-C/Swift bridge. 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 Cross-Bridge Closures and Undisposed Flow Observers Between Kotlin GC and Swift ARC) 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/Native