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

Kotlin Multiplatform 2.1 Swift Export ARC and Lifecycle Invariant

Enforces deterministic lifecycle boundaries and weak reference semantics across Kotlin Multiplatform 2.1 Direct Swift Export interfaces. Prevents permanent cross-runtime memory leaks caused by retain cycles bridging Swift Automatic Reference Counting (ARC) and Kotlin Native Garbage Collection (GC).

Prohibited Anti-Pattern: Cross-Runtime Retain Cycles via Strong Closures and Unscoped Kotlin Export References in Swift

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: Kotlin Multiplatform 2.1 Swift Export ARC and Lifecycle Invariant - Enforces deterministic lifecycle boundaries and weak reference semantics across Kotlin Multiplatform 2.1 Direct Swift Export interfaces. Prevents permanent cross-runtime memory leaks caused by retain cycles bridging Swift Automatic Reference Counting (ARC) and Kotlin Native Garbage Collection (GC).
globs: iosApp/**/*.swift, shared/src/commonMain/kotlin/**/*.kt, shared/src/iosMain/kotlin/**/*.kt
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/kmp-2-1-swift-export-arc-invariants"
---

# Kotlin Multiplatform 2.1 Swift Export ARC and Lifecycle Invariant

> **Severity**: CRITICAL | **Category**: mobile
> **Anti-Pattern Warning**: Cross-Runtime Retain Cycles via Strong Closures and Unscoped Kotlin Export References in Swift

## System Constraints
You are a Principal Mobile Architect enforcing Kotlin Multiplatform 2.1 Swift Export ARC Invariants. Mandate strict cross-runtime boundary isolation, deterministic reference invalidation, and explicit weak-capture semantics. Prevent cross-runtime retain cycles between Swift ARC and Kotlin Native GC where neither runtime's collector can trace the foreign heap.

## Strict Guidelines
- Engineers MUST ALWAYS capture Swift dependencies weakly (`[weak self]`) within closures passed across Swift Export boundaries into Kotlin.
- Engineers MUST NOT store strong Kotlin exported instances inside Swift closures or long-lived singletons that are directly or indirectly observed by that same Kotlin instance.
- Code SHOULD enforce deterministic resource disassociation using an explicit `Disposable` or `cancellable` token pattern when bridging Kotlin flows or callbacks into Swift.
- Services MUST explicitly clear callback references and event listeners in Kotlin when a lifecycle scope completes or when Swift components signal teardown in `deinit`.
- Components NEVER bridge bi-directional delegate relationships across the Swift Export boundary without making at least one leg of the bridge a `WeakReference` on the Kotlin side or `weak` on the Swift side.

## Bad vs Good Implementations
### Bridging Kotlin StateFlow/Callbacks to Swift with Deterministic ARC Disassociation

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: The Swift object strongly retains the exported Kotlin UserSessionManager instance. Passing a closure without [weak self] creates a strong Swift ARC reference retained by the Kotlin GC heap. Neither Swift ARC nor Kotlin Native GC can traverse the foreign runtime's reference graph to break the circular dependency.
```swift
// Anti-Pattern: Strong Swift-to-Kotlin retain cycle across KMP 2.1 Swift Export boundary
final class UserViewModel {
    private let sessionManager: UserSessionManager // Exported Kotlin 2.1 class
    private var sessionToken: String? = nil

    init(sessionManager: UserSessionManager) {
        self.sessionManager = sessionManager
        // BAD: Passing strong self closure directly into Kotlin exported boundary
        // Kotlin GC tracks closure wrapper; Swift ARC tracks sessionManager -> Permanent Leak
        self.sessionManager.observeSessionState {
            self.sessionToken = $0.token
            self.handleStateChange($0)
        }
    }

    private func handleStateChange(_ state: SessionState) {
        // Update UI state
    }
}
```

#### Production Standard (Correct)
> **Standard**: Explicitly captures [weak self] inside the Swift callback closure passed to Kotlin. Retains an ExportedCancellable handle that is deterministically invoked inside Swift's deinit, cleanly severing the Swift ARC reference from the Kotlin GC object graph.
```swift
// Production Fix: Deterministic lifecycle subscription with explicit weak ARC capture and cancellation
final class UserViewModel {
    private let sessionManager: UserSessionManager // Exported Kotlin 2.1 class
    private var sessionToken: String? = nil
    private var observationHandle: ExportedCancellable? = nil

    init(sessionManager: UserSessionManager) {
        self.sessionManager = sessionManager
        
        // GOOD: Explicit weak self prevents Swift retain cycle; returned handle guarantees cleanup
        self.observationHandle = self.sessionManager.observeSessionState { [weak self] state in
            guard let self = self else { return }
            self.sessionToken = state.token
            self.handleStateChange(state)
        }
    }

    private func handleStateChange(_ state: SessionState) {
        // Update UI state safely
    }

    deinit {
        // Explicitly sever the cross-runtime bridge before ARC finalization
        observationHandle?.cancel()
        observationHandle = nil
    }
}
```

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 ARC and Lifecycle Invariant

Kotlin Multiplatform 2.1 Swift Export ARC and Lifecycle Invariant defines an industrial-grade behavioral standard for mobile engineering. Enforces deterministic lifecycle boundaries and weak reference semantics across Kotlin Multiplatform 2.1 Direct Swift Export interfaces. Prevents permanent cross-runtime memory leaks caused by retain cycles bridging Swift Automatic Reference Counting (ARC) and Kotlin Native Garbage Collection (GC). 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: Cross-Runtime Retain Cycles via Strong Closures and Unscoped Kotlin Export References in Swift 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 DriftCross-Runtime Retain Cycles via Strong Closures and Unscoped Kotlin Export References in SwiftCritical
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 capture Swift dependencies weakly (`[weak self]`) within closures passed across Swift Export boundaries into Kotlin.

Engineers MUST ALWAYS capture Swift dependencies weakly (`[weak self]`) within closures passed across Swift Export boundaries into Kotlin.

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 store strong Kotlin exported instances inside Swift closures or long-lived singletons that are directly or indirectly observed by that same Kotlin instance.

Engineers MUST NOT store strong Kotlin exported instances inside Swift closures or long-lived singletons that are directly or indirectly observed by that same Kotlin instance.

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

Code SHOULD enforce deterministic resource disassociation using an explicit `Disposable` or `cancellable` token pattern when bridging Kotlin flows or callbacks into Swift.

Code SHOULD enforce deterministic resource disassociation using an explicit `Disposable` or `cancellable` token pattern when bridging Kotlin flows or callbacks into Swift.

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 explicitly clear callback references and event listeners in Kotlin when a lifecycle scope completes or when Swift components signal teardown in `deinit`.

Services MUST explicitly clear callback references and event listeners in Kotlin when a lifecycle scope completes or when Swift components signal teardown in `deinit`.

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 bridge bi-directional delegate relationships across the Swift Export boundary without making at least one leg of the bridge a `WeakReference` on the Kotlin side or `weak` on the Swift side.

Components NEVER bridge bi-directional delegate relationships across the Swift Export boundary without making at least one leg of the bridge a `WeakReference` on the Kotlin side or `weak` on the Swift side.

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 ARC and Lifecycle Invariant critical for AI coding assistants?

Enforces deterministic lifecycle boundaries and weak reference semantics across Kotlin Multiplatform 2.1 Direct Swift Export interfaces. Prevents permanent cross-runtime memory leaks caused by retain cycles bridging Swift Automatic Reference Counting (ARC) and Kotlin Native Garbage Collection (GC). 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 (Cross-Runtime Retain Cycles via Strong Closures and Unscoped Kotlin Export References in Swift) 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