home / skills / hoangnguyen0403 / agent-skills-standard / compose

This skill helps you implement high-performance Jetpack Compose UI with proper state hoisting, theming, and lifecycle-safe patterns for fluid apps.

npx playbooks add skill hoangnguyen0403/agent-skills-standard --skill compose

Review the files below or copy the command above to add this skill to your agents.

Files (2)
SKILL.md
1.3 KB
---
name: Android Jetpack Compose
description: Standards for high-performance Declarative UI and State Hoisting.
metadata:
  labels: [android, compose, ui]
  triggers:
    files: ['**/*.kt']
    keywords: ['@Composable', 'Modifier', 'Column', 'Row']
---

# Jetpack Compose Expert

## **Priority: P0 (CRITICAL)**

**You are an Android UI Performance Expert.** Prioritize frame stability and state management.

## Implementation Guidelines

- **State Hoisting**: `Screen` (Stateful) -> `Content` (Stateless).
- **Events**: Pass lambdas down (`onItemClick: (Id) -> Unit`).
- **Dependencies**: NEVER pass ViewModel to stateless composables.
- **Theming**: Use `MaterialTheme.colorScheme`, no hardcoded hex.

## Performance Checklist (Mandatory)

- [ ] **Recomposition**: Are params `@Stable` or `@Immutable`?
- [ ] **Lists**: Is `key` used in `LazyColumn` items?
- [ ] **Modifiers**: Are they reused or static where possible?
- [ ] **Side Effects**: `LaunchedEffect` used correctly? (No limits).
- [ ] **Derived State**: `derivedStateOf` for frequent updates?

## Anti-Patterns

- **No Side Effects**: Use `LaunchedEffect`, not composition body.
- **No VM Deep Pass**: Hoist state; pass only data/callbacks.
- **No Heavy Comp**: Move complex calc to ViewModel or `remember`.

## References

- [Optimization Patterns](references/implementation.md)

Overview

This skill captures standards and best practices for building high-performance UIs with Android Jetpack Compose. It focuses on frame stability, correct state hoisting, and avoiding common performance anti-patterns. The guidance helps agents produce composables that are efficient, testable, and maintainable.

How this skill works

The skill inspects component boundaries, state flow, and event propagation to ensure stateful and stateless separation (Screen → Content). It checks that composables receive only data and callbacks rather than ViewModels, verifies use of derivedStateOf and LaunchedEffect for side effects, and enforces theming and modifier reuse. It also validates performance checklist items like stable/immutable params, Lazy list keys, and reused modifiers.

When to use it

  • When designing new Compose screens to ensure proper state hoisting and event handling.
  • When reviewing or refactoring Compose code for performance regressions or janky frames.
  • When enforcing UI theming consistency and avoiding hardcoded colors.
  • When optimizing Recycler-like lists (LazyColumn/LazyRow) for smooth scrolling.
  • When migrating business logic out of composition into ViewModel or remembered state.

Best practices

  • Hoist state: keep Screen composables stateful and Content composables stateless; pass data and lambdas down.
  • Never pass ViewModel into stateless composables; pass only data and event callbacks.
  • Mark parameters @Stable or @Immutable when appropriate and use derivedStateOf for frequent calculations.
  • Use LaunchedEffect for side effects and remember to scope heavy calculations outside composition (ViewModel or remember).
  • Reuse Modifiers where possible and provide explicit keys for Lazy lists to avoid unnecessary recomposition.
  • Use MaterialTheme.colorScheme for colors; avoid hardcoded hex values.

Example use cases

  • Code review automation that flags composables which accept ViewModel instances or perform heavy computation in composition.
  • Refactor tasks that split a monolithic screen into a stateful Screen and multiple stateless Content composables.
  • Performance audits that verify LazyColumn items include stable keys and derivedStateOf is used for dynamic UI metrics.
  • Linting rules that ensure theming via MaterialTheme.colorScheme and check for reuse of Modifier instances.

FAQ

Why must ViewModels not be passed into stateless composables?

Passing ViewModels couples UI implementation to lifecycle-aware components and encourages pulling logic into composition. Pass plain data and callbacks so composables remain reusable and testable.

When should I use derivedStateOf?

Use derivedStateOf for expensive or frequently updated derived values so they only recompute when their inputs change, reducing unnecessary recompositions.