Loading...
Loading...
Writes and reviews composables for Compose and CMP: the Route/Screen/leaf split, state-read placement and stability, loading/empty/error UX states, LazyColumn lists and grids, animation choice, accessibility and semantics, design-system tokens, CMP Res resources, Coil images, and keyboard/focus. Use when touching @Composable code, recomposition, stability, LazyColumn, animation, shimmer or skeleton, accessibility, theme, colors, Res.string, Coil, focus, or keyboard. Do NOT use for MVI, error tiers, or module graph (compose-architecture), ViewModel or data work (compose-feature, compose-data), Gradle or module work (compose-project), or expect/actual splits (compose-platform).
npx skill4agent add meet-miyani/compose-skill compose-uiremember@Immutablecompose-architecturecompose-architecturegradle/libs.versions.toml| Task | Use instead |
|---|---|
| Route first: decide the task path and files to read | the |
| Add, change or review a screen, destination or slice | the |
| Repositories, Ktor, Room, DataStore, Paging, offline-first | the |
| the |
| New project or module, convention plugins, version catalog, CI, guards | the |
| Navigation 3 API mechanics (scenes, decorators, deep-link recipes) | the android/skills |
Compiler-report internals beyond the loop in | the skydoves |
Iron law: read depth decides cost. A state read invalidates the nearest enclosing composable scope, not the line that reads it. When a screen re-executes too often, move the read down to the leaf that renders it, never wrap the scope in. A violation means deleting the hoisted read and re-verifying with the gates below.remember
compose-architectureexisting-projects.mdonActiononActionScaffoldStateUiStateUiStateInstantupdateState===equalskotlin.collections.*@ImmutableLoadState.ErrorThrowableAppErrorcompose-architecturecontentTypeconsumeWindowInsetscommonMainjava.*android.*LocalContextRDispatchers.Defaultjava.time.InstantLocalContextkotlin.time.InstantResDispatchers.IONotesTabletScreenisTablet<Dest>Screen<Dest>LayoutNotesExpandedLayout*TabletScreenux-states.md| Situation | Fix |
|---|---|
Domain model from a module without the Compose compiler sits in | Declare its package in the stability configuration file (rule 4) |
Class is genuinely immutable ( | |
| An M-11 trigger fires (derived values, merged sources, UI-only fields, hidden fields) | UI-specific wrapper class |
| Anything else, including "make it skippable" on a mutable class | Stop. No annotation, no wrapper |
| Thought | Reality |
|---|---|
"I'll read the clock at the top and pass | No. Rule 2: passing the value moves the cost up. Pass the |
| "I'll tick a formatted countdown string from the ViewModel; simpler." | No. Rules 2–3: the string invalidates every collector each second. Carry the |
"I'll wrap it in | No. Rule 2 (iron law): |
"Adding | No. Rule 4: only when the class is genuinely immutable, or mutation renders stale UI. |
| "Every feature needs a UiModel for consistency." | No. Rule 4: consistency means the same rule, not the same files. Name the M-11 trigger or hold the domain model. |
"I'll pass the whole | No. Keys carry identity; detail re-fetches by identity (see the |
| "This refresh can show a full-screen spinner; it is only a second." | No. Rule 7: refresh keeps content with an indicator. Skeletons are cold-load only. |
| "Index keys are fine; the list never reorders today." | No. Rule 8: keys come from domain identity, plus |
| "I'll hardcode this color; the tokens do not have it." | No. Rule 5: tokens only in feature code. Name the missing token as an open gap. |
| "I'll copy this component; the condition was specific to that screen." | No. Rule 6: copy the gate with the component. |
| "I'll put this string inline; translation comes later." | No. Rule 9: every user-facing string is a resource in every locale before done. |
"I'll use | No. Rule 11: |
"I'll default this dispatcher to | Rule 11: inject it and default to |
"The user named | No. Rule 12: decline device names first; build one |
"I'll keep | No. Rule 12: name the value after the layout ( |
rg -n "ViewModel|koinViewModel|collectAsState" --glob '*Screen.kt' --glob '*Sheet.kt'*Route.ktrememberSaveableUiStateLaunchedEffectcompose-architectureUiStateUiStateUiModel@Immutablevalperformance-diagnostics.mdrg -n "Color\(0x" --glob '*.kt' <feature-root>check-hardcoded-colors.shitems(item(keycontentTypecheck-locale-parity.shrg -n "isTablet|isPhone|(Tablet|Phone|Mobile|Desktop|Web)(Screen|Layout)\b" --glob '*.kt' <feature-root>ResRModifier.Node