This specification is maintained by the AgentRules Working Group. Have enhancements or want to claim maintainership?Submit Specification →
mobilecritical PriorityID: kmp-retained-state-lifecycle-restoration-standard

KMP Retained State Lifecycle & Process Restoration Standard

Enforces deterministic lifecycle-bound cancellation and serialized state restoration across Kotlin Multiplatform targets. Prevents coroutine execution leaks during iOS UIViewController deallocation and state divergence against Android ViewModel process death restoration.

Prohibited Anti-Pattern: Unbounded CoroutineScope leaks on iOS dealloc combined with un-restored ephemeral state across Android process death.

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: KMP Retained State Lifecycle & Process Restoration Standard - Enforces deterministic lifecycle-bound cancellation and serialized state restoration across Kotlin Multiplatform targets. Prevents coroutine execution leaks during iOS UIViewController deallocation and state divergence against Android ViewModel process death restoration.
globs: **/commonMain/**/*.kt, **/androidMain/**/*.kt, **/iosMain/**/*.kt, **/iosApp/**/*.swift
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/kmp-retained-state-lifecycle-restoration-standard"
---

# KMP Retained State Lifecycle & Process Restoration Standard

> **Severity**: CRITICAL | **Category**: mobile
> **Anti-Pattern Warning**: Unbounded CoroutineScope leaks on iOS dealloc combined with un-restored ephemeral state across Android process death.

## System Constraints
You are a Principal Software Architect enforcing KMP Retained State Lifecycle Restoration standards. You must ensure all common state holders enforce dual invariants: structural lifecycle scoping that tears down downstream coroutines when iOS dismisses/deallocates view controllers, and persistent state serialization compatible with Android SavedStateHandle and iOS state preservation contracts.

## Strict Guidelines
- Engineers MUST ALWAYS encapsulate KMP state holders within an explicit retained-instance boundary (such as Decompose InstanceKeeper or lifecycle-aware ViewModel wrapper) that binds CoroutineScope cancellation to host deallocation.
- Engineers MUST NOT bind platform-agnostic StateFlow producers to a global or unmanaged CoroutineScope (`GlobalScope` or unbounded platform singleton).
- Code SHOULD implement dual-layer state restoration: in-memory retained instances for configuration changes, and Parcelable/Serializable state survival for low-memory OS process termination.
- Services MUST expose explicit `close()` or `clear()` hooks invoked immediately when an iOS `UIViewController` executes `deinit` or detects `isMovingFromParent` / `isBeingDismissed`.
- Components NEVER capture platform lifecycle instances (`UIViewController`, `Activity`, `Fragment`) inside common state holders or long-lived coroutine closures.

## Bad vs Good Implementations
### KMP ViewModel Lifecycle Teardown and State Restoration

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: The CoroutineScope is unbounded and never cancelled upon iOS UIViewController deallocation, leaking network observers and memory. Additionally, no serialization anchor exists to restore state after Android process recreation.
```kotlin
// commonMain: Leaks coroutines on iOS and loses state across Android process death
class UserProfileViewModel {
    private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
    private val _uiState = MutableStateFlow(UserProfileState())
    val uiState: StateFlow<UserProfileState> = _uiState.asStateFlow()

    fun loadUser(userId: String) {
        scope.launch {
            // Unmanaged Coroutine: never cancelled when iOS UIViewController is popped/deallocated
            val user = api.fetchUser(userId)
            _uiState.update { it.copy(user = user) }
        }
    }
    // Missing clear/close contract and zero state serialization support
}
```

#### Production Standard (Correct)
> **Standard**: Implements an explicit cancellation hook (`onCleared`) wired to the host lifecycle (iOS dealloc/Android onCleared) and restores serialized state across process death via a deterministic `StateSaver` abstraction.
```kotlin
// commonMain: Production standard utilizing clearable lifecycle and saved state keeper
import kotlinx.serialization.Serializable

@Serializable
data class UserProfileState(val userId: String? = null, val name: String? = null)

interface StateSaver {
    fun <T> register(key: String, strategy: kotlinx.serialization.KSerializer<T>, provider: () -> T)
    fun <T> consume(key: String, strategy: kotlinx.serialization.KSerializer<T>): T?
}

interface CloseableCoroutineScope {
    val scope: CoroutineScope
    fun close()
}

class UserProfileViewModel(
    private val stateSaver: StateSaver,
    private val coroutineScopeProvider: () -> CloseableCoroutineScope
) {
    private val closeableScope = coroutineScopeProvider()
    private val _uiState: MutableStateFlow<UserProfileState>

    init {
        val restored = stateSaver.consume("KEY_STATE", UserProfileState.serializer())
        _uiState = MutableStateFlow(restored ?: UserProfileState())
        stateSaver.register("KEY_STATE", UserProfileState.serializer()) { _uiState.value }
    }

    val uiState: StateFlow<UserProfileState> = _uiState.asStateFlow()

    fun onCleared() {
        closeableScope.close() // Triggered by Android onCleared() or iOS UIViewController deinit
    }
}
```

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: KMP Retained State Lifecycle & Process Restoration Standard

KMP Retained State Lifecycle & Process Restoration Standard defines an industrial-grade behavioral standard for mobile engineering. Enforces deterministic lifecycle-bound cancellation and serialized state restoration across Kotlin Multiplatform targets. Prevents coroutine execution leaks during iOS UIViewController deallocation and state divergence against Android ViewModel process death restoration. 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 CoroutineScope leaks on iOS dealloc combined with un-restored ephemeral state across Android process death. 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 CoroutineScope leaks on iOS dealloc combined with un-restored ephemeral state across Android process death.Critical
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 encapsulate KMP state holders within an explicit retained-instance boundary (such as Decompose InstanceKeeper or lifecycle-aware ViewModel wrapper) that binds CoroutineScope cancellation to host deallocation.

Engineers MUST ALWAYS encapsulate KMP state holders within an explicit retained-instance boundary (such as Decompose InstanceKeeper or lifecycle-aware ViewModel wrapper) that binds CoroutineScope cancellation to host deallocation.

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 bind platform-agnostic StateFlow producers to a global or unmanaged CoroutineScope (`GlobalScope` or unbounded platform singleton).

Engineers MUST NOT bind platform-agnostic StateFlow producers to a global or unmanaged CoroutineScope (`GlobalScope` or unbounded platform singleton).

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 implement dual-layer state restoration

Code SHOULD implement dual-layer state restoration: in-memory retained instances for configuration changes, and Parcelable/Serializable state survival for low-memory OS process 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

Services MUST expose explicit `close()` or `clear()` hooks invoked immediately when an iOS `UIViewController` executes `deinit` or detects `isMovingFromParent` / `isBeingDismissed`.

Services MUST expose explicit `close()` or `clear()` hooks invoked immediately when an iOS `UIViewController` executes `deinit` or detects `isMovingFromParent` / `isBeingDismissed`.

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 capture platform lifecycle instances (`UIViewController`, `Activity`, `Fragment`) inside common state holders or long-lived coroutine closures.

Components NEVER capture platform lifecycle instances (`UIViewController`, `Activity`, `Fragment`) inside common state holders or long-lived coroutine 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.
Technical Questions & Answers

Frequently Asked Technical Questions

Common questions developers face when configuring AI coding assistants for this stack:

Q:Why is KMP Retained State Lifecycle & Process Restoration Standard critical for AI coding assistants?

Enforces deterministic lifecycle-bound cancellation and serialized state restoration across Kotlin Multiplatform targets. Prevents coroutine execution leaks during iOS UIViewController deallocation and state divergence against Android ViewModel process death restoration. 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 CoroutineScope leaks on iOS dealloc combined with un-restored ephemeral state across Android process death.) 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