skills/compose-state-hoisting/SKILL.md
Compose state management with a strong state-hoisting preference for Kotlin Compose (Android, Multiplatform, Compose for Web). Use for refactors or new UI that needs clear state ownership, unidirectional data flow, saved state decisions, or guidance on remember/retain/rememberSaveable/rememberSerializable, and for designing stateless composables with event callbacks.
npx skillsauth add alexandru/skills compose-state-hoistingInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Apply state hoisting and unidirectional data flow to Compose UIs, choosing the right state owner, lifespan, and saving strategy.
For condensed reference and examples, see references/compose-state-guidance.md.
value and event callbacks; state goes down, events go up.remember only for ephemeral UI state.retain or rememberSaveable and document why.rememberSaveable/SavedStateHandle.remember and retain for the same object.value: T and onValueChange: (T) -> Unit (or more specific event lambdas).CompositionLocal to avoid passing parameters through many layers. Use sparingly; prefer explicit parameter passing when practical.remember: survives recomposition only; same instance. Use for composition-scoped objects and small internal UI state. Do not use for user input that must be preserved.retain: survives recomposition + window/configuration changes (Android: activity recreation), not process death. Use for non-serializable objects (players, caches, flows, lambdas). Do not retain platform-specific lifecycle objects (Android: Activity, View, Fragment, ViewModel, Context, Lifecycle). Do not retain objects that were already created with remember by the caller—retain and remember are mutually exclusive for the same object.rememberSaveable / rememberSerializable: survives recomposition + configuration changes + process death (Android) by saving to the platform's saved state mechanism (Android: Bundle; other platforms may vary). Use for user input or UI state that cannot be reloaded from another source. Restored objects are equal but not the same instance.Remember Keys: Control when state resets by passing keys to remember(key1, key2) { }. State recreates when any key changes. Omit keys only when state should survive all recompositions.
rememberSaveable for UI state hoisted in composables or plain state holders; save only minimal, small data.SavedStateHandle in a ViewModel for UI element state that must survive process death; keep it small and session-scoped (not persistent app data).State<T> before reading in composables.Flow: use collectAsState (platform-agnostic, always collects) or collectAsStateWithLifecycle (Android only, lifecycle-aware, pauses collection when UI is not visible).LiveData (Android): use observeAsState.State<T> via produceState.onRemembered / onRetained, not in constructors or remember/retain lambdas.onForgotten / onRetired; handle onAbandoned for canceled compositions.rememberX() to avoid misuse.State<T> to another remember call—this creates unnecessary nested observability.State or use snapshot state collections (mutableStateListOf, mutableStateMapOf).rememberSaveable/SavedStateHandle (Android); save IDs and rehydrate instead.derivedStateOf, causing unnecessary recompositions.value + callbacks.references/compose-state-guidance.md for decision trees, tables, and code examples.development
Scala auto-derivation with Kindlings for Circe and PureConfig. Use when replacing circe-generic/circe-generic-extras or PureConfig generic derivation with Kindlings while keeping normal Circe JSON APIs and PureConfig loading/writing APIs.
development
Simplifies code for clarity without changing behavior. Use when code is working but overly complex, deeply nested, duplicated, or unclear.
development
Helps agents design and review Kotlin library APIs for Java consumers. Use when building Kotlin code intended for Java callers, shaping JVM signatures with @JvmName, @JvmOverloads, @JvmStatic, @JvmField, @Throws, @JvmRecord, nullability, records, and backward/binary compatibility rules.
tools
JSpecify nullness annotations for Java APIs and tooling. Use when adopting or migrating JSpecify annotations, designing null-safe Java signatures, fixing generic bounds and type-use placement, or interpreting Kotlin interop, annotation-processor, and tool-conformance behavior.