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-memory-ownership

KMP 2.1 Direct Swift Export Memory Ownership and Immutability Guardrail

Enforces strict value-type immutability and explicit lifecycle scopes across the Direct Swift Export ABI boundary in Kotlin Multiplatform 2.1. Crossing the boundary between Swift native tasks and Kotlin coroutine dispatchers with mutable state or unmanaged references creates memory ownership desynchronizations, reference cycles across ARC and Kotlin GC, and race conditions.

Prohibited Anti-Pattern: Exposing Shared Mutable Classes and Unscoped Continuations Across the Direct Swift Export Boundary

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: KMP 2.1 Direct Swift Export Memory Ownership and Immutability Guardrail - Enforces strict value-type immutability and explicit lifecycle scopes across the Direct Swift Export ABI boundary in Kotlin Multiplatform 2.1. Crossing the boundary between Swift native tasks and Kotlin coroutine dispatchers with mutable state or unmanaged references creates memory ownership desynchronizations, reference cycles across ARC and Kotlin GC, and race conditions.
globs: shared/src/**/*.{kt,kts}, iosApp/**/*.{swift}
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/kmp-2-1-swift-export-memory-ownership"
---

# KMP 2.1 Direct Swift Export Memory Ownership and Immutability Guardrail

> **Severity**: CRITICAL | **Category**: mobile
> **Anti-Pattern Warning**: Exposing Shared Mutable Classes and Unscoped Continuations Across the Direct Swift Export Boundary

## System Constraints
You are a Principal Software Architect enforcing production-grade Kotlin Multiplatform 2.1 Direct Swift Export memory ownership invariants. The direct Swift Export ABI generates native Swift representations of Kotlin declarations. Because Swift utilizes Automatic Reference Counting (ARC) and Swift Concurrency Tasks while Kotlin/Native uses a concurrent tracing garbage collector and Coroutine Scopes, any shared mutable state or detached continuation across the boundary causes memory leaks, thread contention, and undefined behavior. You must strictly mandate value-type immutability, scoped lifecycle bridging, and clean cancellation mechanics across the ABI.

## Strict Guidelines
- Engineers MUST ALWAYS expose only deeply immutable value types (Kotlin data classes containing exclusively read-only 'val' fields of primitive or immutable types) across the Swift Export boundary.
- Engineers MUST NOT expose Kotlin classes with mutable properties ('var'), mutable collections ('MutableList', 'MutableMap'), or state containers ('MutableStateFlow') to Swift Export.
- Code MUST bridge Kotlin Coroutine Flows to Swift AsyncSequence using explicit cancellation handlers that bind Swift Task cancellation directly to the underlying Kotlin Job.
- Services MUST scope Kotlin CoroutineScopes to explicit platform lifecycles and NEVER rely on GlobalScope or unbounded CoroutineScope instances across the native boundary.
- Components NEVER store direct Swift object references in long-lived Kotlin state or vice-versa without using weak references or explicit deterministic disposal protocols to avoid cross-runtime ARC/GC retention cycles.

## Bad vs Good Implementations
### Cross-Boundary State Exposure and Lifecycle Bridging

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Exposing mutable reference types ('var' fields and 'MutableStateFlow') and unmanaged GlobalScope launches causes data races between Swift native actors and Kotlin worker threads. Swift has no deterministic mechanism to cancel or observe the unmanaged GlobalScope lifecycle.
```kotlin
// Anti-Pattern: Exposing mutable state and unmanaged coroutines across Swift Export
package com.example.kmp.boundary

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*

class UserSessionManager {
    // VIOLATION: Mutable state exposed across Swift ABI creates ARC/GC race conditions
    var currentUser: UserAccount? = null
    val sessionStream = MutableStateFlow<UserAccount?>(null)

    // VIOLATION: Unscoped async execution; Swift caller cannot propagate cancellation
    fun updateUserProfile(name: String, email: String) {
        GlobalScope.launch {
            val updated = UserAccount(name, email)
            currentUser = updated
            sessionStream.value = updated
        }
    }
}

class UserAccount(var name: String, var email: String)
```

#### Production Standard (Correct)
> **Standard**: UserAccountSnapshot is deeply immutable, guaranteeing thread safety across the ABI. The update method returns a SessionCancellable that permits Swift Concurrency Tasks to bind Task cancellation directly to the underlying Kotlin Job, preventing GC/ARC retain cycles and orphan coroutines.
```kotlin
// Production Guardrail: Deeply immutable value projections and structured cancellation hooks
package com.example.kmp.boundary

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*

// INVARIANT: Pure immutable data projection mapped cleanly to Swift struct-like ABI
data class UserAccountSnapshot(
    val name: String,
    val email: String
)

interface SessionCancellable {
    fun cancel()
}

class UserSessionManager(
    private val scope: CoroutineScope
) {
    private val _sessionFlow = MutableStateFlow<UserAccountSnapshot?>(null)
    
    // INVARIANT: Expose read-only Flow projection across Swift Export
    val sessionFlow: StateFlow<UserAccountSnapshot?> = _sessionFlow.asStateFlow()

    // INVARIANT: Deterministic Swift-cancellable bridge with immutable arguments
    fun updateUserProfile(
        name: String,
        email: String,
        onComplete: (Result<UserAccountSnapshot>) -> Unit
    ): SessionCancellable {
        val job = scope.launch {
            try {
                val snapshot = UserAccountSnapshot(name = name, email = email)
                _sessionFlow.value = snapshot
                onComplete(Result.success(snapshot))
            } catch (t: Throwable) {
                onComplete(Result.failure(t))
            }
        }
        return object : SessionCancellable {
            override fun cancel() = job.cancel()
        }
    }
}
```

Architectural Specification & Invariant Rationale

Architectural Invariant Design: KMP 2.1 Direct Swift Export Memory Ownership and Immutability Guardrail

KMP 2.1 Direct Swift Export Memory Ownership and Immutability Guardrail defines an industrial-grade behavioral standard for mobile engineering. Enforces strict value-type immutability and explicit lifecycle scopes across the Direct Swift Export ABI boundary in Kotlin Multiplatform 2.1. Crossing the boundary between Swift native tasks and Kotlin coroutine dispatchers with mutable state or unmanaged references creates memory ownership desynchronizations, reference cycles across ARC and Kotlin GC, and race conditions. 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: Exposing Shared Mutable Classes and Unscoped Continuations Across the Direct Swift Export Boundary 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 DriftExposing Shared Mutable Classes and Unscoped Continuations Across the Direct Swift Export BoundaryCritical
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 expose only deeply immutable value types (Kotlin data classes containing exclusively read-only 'val' fields of primitive or immutable types) across the Swift Export boundary.

Engineers MUST ALWAYS expose only deeply immutable value types (Kotlin data classes containing exclusively read-only 'val' fields of primitive or immutable types) across the 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.
2

Engineers MUST NOT expose Kotlin classes with mutable properties ('var'), mutable collections ('MutableList', 'MutableMap'), or state containers ('MutableStateFlow') to Swift Export.

Engineers MUST NOT expose Kotlin classes with mutable properties ('var'), mutable collections ('MutableList', 'MutableMap'), or state containers ('MutableStateFlow') to Swift Export.

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 MUST bridge Kotlin Coroutine Flows to Swift AsyncSequence using explicit cancellation handlers that bind Swift Task cancellation directly to the underlying Kotlin Job.

Code MUST bridge Kotlin Coroutine Flows to Swift AsyncSequence using explicit cancellation handlers that bind Swift Task cancellation directly to the underlying Kotlin Job.

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 scope Kotlin CoroutineScopes to explicit platform lifecycles and NEVER rely on GlobalScope or unbounded CoroutineScope instances across the native boundary.

Services MUST scope Kotlin CoroutineScopes to explicit platform lifecycles and NEVER rely on GlobalScope or unbounded CoroutineScope instances across the native 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.
5

Components NEVER store direct Swift object references in long-lived Kotlin state or vice-versa without using weak references or explicit deterministic disposal protocols to avoid cross-runtime ARC/GC retention cycles.

Components NEVER store direct Swift object references in long-lived Kotlin state or vice-versa without using weak references or explicit deterministic disposal protocols to avoid cross-runtime ARC/GC retention cycles.

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 2.1 Direct Swift Export Memory Ownership and Immutability Guardrail critical for AI coding assistants?

Enforces strict value-type immutability and explicit lifecycle scopes across the Direct Swift Export ABI boundary in Kotlin Multiplatform 2.1. Crossing the boundary between Swift native tasks and Kotlin coroutine dispatchers with mutable state or unmanaged references creates memory ownership desynchronizations, reference cycles across ARC and Kotlin GC, and race conditions. 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 (Exposing Shared Mutable Classes and Unscoped Continuations Across the Direct Swift Export Boundary) 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