Use when writing acceptance criteria for a task - express each as an observable Given/When/Then that QA can execute, including negative cases
日本語の概要は準備中です。原文の説明を表示しています。
Use when building native Android with Jetpack Compose - stateless composables, state hoisting, ViewModel-owned state, edge-to-edge, predictive back, adaptive layout, atomic components, and Material theming over hardcoded values
インストール方法を見るインストールする前に、エージェントに与えられる指示の中身を確認できます。
Native Android (Jetpack Compose) is chosen when a task needs deep Android integration or the app is already native (see native-vs-flutter-decision). Same discipline as Flutter/SwiftUI: small stateless composables, state hoisted out, reusable atomic components.
Core principle: Composables are stateless functions of state. State is hoisted to a ViewModel; composables emit events upward.
onXxx) — it does not own app state. The screen-level composable connects a ViewModel to the stateless UI.ViewModel owns state and logic, exposed as StateFlow/UiState; the composable collects it with collectAsStateWithLifecycle(). Networking/business rules live in the ViewModel + repository, never in the composable.Loading | Data | Empty | Error — when over it renders every branch. No happy-path-only screens.MaterialTheme.colorScheme / typography / a spacing tokens object (MaterialTheme.spacing, see mobile-design-system-foundation) — never scattered Color(0xFF...) and magic dp. Support dark theme + dynamic color.remember/derivedStateOf to avoid recomputation; hoist remembered state only when it's genuinely local (scroll, text field).@Preview reusable composables in their key states, and across the matrix (see below).enableEdgeToEdge() before setContent in the activity — the opt-out is gone at targetSdk 35+.Scaffold: use its innerPadding and Modifier.consumeWindowInsets(innerPadding) on the content so a nested scrollable doesn't double-apply it.Modifier.imePadding() once, at the container that should move with the keyboard — applying it a second time further down the tree produces extra empty space.android:windowSoftInputMode="adjustResize" in the manifest for screens with text input.NavigationSuiteScaffold does not automatically propagate its padding to the content slot — apply insets explicitly inside it, don't assume it's handled.onBackPressed() / OnBackPressedCallback without isEnabled toggling is not called the same way once predictive back is the default — use BackHandler (simple) or PredictiveBackHandler (custom transition) in Compose, or Navigation 3's built-in handling.currentWindowAdaptiveInfo().windowSizeClass to branch layout by available width/height — never by Configuration.orientation or a hardcoded device check.NavigationSuiteScaffold switches a bottom nav bar to a nav rail automatically at the window-size-class breakpoint — prefer it over hand-rolling the switch.GridCells.Adaptive(minWidth) for grids that should reflow by available width.PROPERTY_COMPAT_ALLOW_RESTRICTED_RESIZABILITY) and Android 17/API 37 (no opt-out) ignore screenOrientation/resizeableActivity restrictions on screens ≥600dp — design every screen to work in both orientations and at tablet width; don't rely on an orientation lock to avoid building the wider layout.@PreviewScreenSizes, @PreviewFontScale, @PreviewLightDark, or a custom multi-preview with Devices.PHONE/Devices.TABLET — see mobile-visual-self-review for the full size/text-scale/dark matrix.DeviceConfigurationOverride(ForcedSize(...) then FontScale(...) then DarkMode(...)) for instrumented matrix tests.rule.enableAccessibilityChecks() on an API 34+ device/emulator before UI-mutating test actions (inconclusive on Robolectric — say so if that's all you ran); see mobile-accessibility.contentDescription on every Image/Icon that carries meaning; null explicitly for a purely decorative one.Modifier.semantics(mergeDescendants = true) on a composite row so a screen reader announces it once.Modifier.size/minimumInteractiveComponentSize().// ViewModel owns state + logic (unit-testable, no Compose)
class TaskListViewModel(private val repo: TaskRepository) : ViewModel() {
private val _state = MutableStateFlow<UiState<List<Task>>>(UiState.Loading)
val state: StateFlow<UiState<List<Task>>> = _state
fun load() = viewModelScope.launch {
_state.value = UiState.Loading
_state.value = try {
val items = repo.list()
if (items.isEmpty()) UiState.Empty else UiState.Data(items)
} catch (e: CancellationException) {
throw e // never swallow cancellation
} catch (e: Exception) {
UiState.Error(e)
}
}
}
// stateless composable renders state, emits events
@Composable
fun TaskListScreen(state: UiState<List<Task>>, onRetry: () -> Unit) = when (state) {
is UiState.Loading -> AppSpinner()
is UiState.Error -> AppErrorView(message = state.cause.message, onRetry = onRetry)
is UiState.Data -> TaskList(tasks = state.value)
is UiState.Empty -> EmptyView()
}
The fix from the previous version: runCatching { } wrapped around a suspend call inside viewModelScope.launch catches CancellationException along with real errors, which breaks structured concurrency (a cancelled screen keeps "loading" instead of stopping) — use try/catch and rethrow CancellationException explicitly. The Empty branch is now actually emitted when the list comes back empty, not just declared and never reached.
ViewModel with a fake/mockk repository and a test dispatcher — no Compose.createComposeRule) assert visible behavior and clicks. Test-first.MaterialTheme + tokens.collectAsStateWithLifecycle (leaks/waste).Empty declared but never emitted.runCatching around a suspend call, swallowing CancellationException.@Composable that imports a repository or Retrofit service.Color(0xFF...)/magic dp outside the theme.when.enableEdgeToEdge() missing from a new or recently targetSdk-bumped activity.まだレビューはありません。使ってみた感想をお寄せください。
概要と使いどころ
Use when writing acceptance criteria for a task - express each as an observable Given/When/Then that QA can execute, including negative cases
日本語の概要は準備中です。原文の説明を表示しています。
Use when the diff adds or changes an endpoint, resolver, RPC, job or query that takes an object id, a role check, a request binding or a tenant filter - BOLA/IDOR, function-level authorization, mass assignment and tenant scoping
日本語の概要は準備中です。原文の説明を表示しています。
Use on every UI change - semantic HTML, labels for controls, keyboard-navigable dialogs/menus, visible focus, and never color as the only signal
日本語の概要は準備中です。原文の説明を表示しています。
Use when a task changes any screen, form, dialog, menu or control - Lighthouse/axe scan of the changed screens, a keyboard walk, and the thresholds that fail a task
日本語の概要は準備中です。原文の説明を表示しています。
How to work a task returned with review, QA or UAT findings. Use when a task is in need_revision or PR review comments are in your context.
日本語の概要は準備中です。原文の説明を表示しています。
Use when deciding whether a request needs an analiz task before implementation - the conditions that require the architect's analysis versus going straight to implementation
日本語の概要は準備中です。原文の説明を表示しています。