agy-superpowers 5.0.8 → 5.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/template/agent/rules/superpowers.md +54 -0
- package/template/agent/skills/frontend-developer/SKILL.md +39 -0
- package/template/agent/skills/frontend-developer/references/react-nextjs.md +343 -0
- package/template/agent/skills/frontend-developer/references/react-rules/_sections.md +46 -0
- package/template/agent/skills/frontend-developer/references/react-rules/_template.md +28 -0
- package/template/agent/skills/frontend-developer/references/react-rules/advanced-event-handler-refs.md +55 -0
- package/template/agent/skills/frontend-developer/references/react-rules/advanced-init-once.md +42 -0
- package/template/agent/skills/frontend-developer/references/react-rules/advanced-use-latest.md +39 -0
- package/template/agent/skills/frontend-developer/references/react-rules/async-api-routes.md +38 -0
- package/template/agent/skills/frontend-developer/references/react-rules/async-defer-await.md +80 -0
- package/template/agent/skills/frontend-developer/references/react-rules/async-dependencies.md +51 -0
- package/template/agent/skills/frontend-developer/references/react-rules/async-parallel.md +28 -0
- package/template/agent/skills/frontend-developer/references/react-rules/async-suspense-boundaries.md +99 -0
- package/template/agent/skills/frontend-developer/references/react-rules/bundle-barrel-imports.md +59 -0
- package/template/agent/skills/frontend-developer/references/react-rules/bundle-conditional.md +31 -0
- package/template/agent/skills/frontend-developer/references/react-rules/bundle-defer-third-party.md +49 -0
- package/template/agent/skills/frontend-developer/references/react-rules/bundle-dynamic-imports.md +35 -0
- package/template/agent/skills/frontend-developer/references/react-rules/bundle-preload.md +50 -0
- package/template/agent/skills/frontend-developer/references/react-rules/client-event-listeners.md +74 -0
- package/template/agent/skills/frontend-developer/references/react-rules/client-localstorage-schema.md +71 -0
- package/template/agent/skills/frontend-developer/references/react-rules/client-passive-event-listeners.md +48 -0
- package/template/agent/skills/frontend-developer/references/react-rules/client-swr-dedup.md +56 -0
- package/template/agent/skills/frontend-developer/references/react-rules/js-batch-dom-css.md +107 -0
- package/template/agent/skills/frontend-developer/references/react-rules/js-cache-function-results.md +80 -0
- package/template/agent/skills/frontend-developer/references/react-rules/js-cache-property-access.md +28 -0
- package/template/agent/skills/frontend-developer/references/react-rules/js-cache-storage.md +70 -0
- package/template/agent/skills/frontend-developer/references/react-rules/js-combine-iterations.md +32 -0
- package/template/agent/skills/frontend-developer/references/react-rules/js-early-exit.md +50 -0
- package/template/agent/skills/frontend-developer/references/react-rules/js-flatmap-filter.md +60 -0
- package/template/agent/skills/frontend-developer/references/react-rules/js-hoist-regexp.md +45 -0
- package/template/agent/skills/frontend-developer/references/react-rules/js-index-maps.md +37 -0
- package/template/agent/skills/frontend-developer/references/react-rules/js-length-check-first.md +49 -0
- package/template/agent/skills/frontend-developer/references/react-rules/js-min-max-loop.md +82 -0
- package/template/agent/skills/frontend-developer/references/react-rules/js-set-map-lookups.md +24 -0
- package/template/agent/skills/frontend-developer/references/react-rules/js-tosorted-immutable.md +57 -0
- package/template/agent/skills/frontend-developer/references/react-rules/rendering-activity.md +26 -0
- package/template/agent/skills/frontend-developer/references/react-rules/rendering-animate-svg-wrapper.md +47 -0
- package/template/agent/skills/frontend-developer/references/react-rules/rendering-conditional-render.md +40 -0
- package/template/agent/skills/frontend-developer/references/react-rules/rendering-content-visibility.md +38 -0
- package/template/agent/skills/frontend-developer/references/react-rules/rendering-hoist-jsx.md +46 -0
- package/template/agent/skills/frontend-developer/references/react-rules/rendering-hydration-no-flicker.md +82 -0
- package/template/agent/skills/frontend-developer/references/react-rules/rendering-hydration-suppress-warning.md +30 -0
- package/template/agent/skills/frontend-developer/references/react-rules/rendering-resource-hints.md +85 -0
- package/template/agent/skills/frontend-developer/references/react-rules/rendering-script-defer-async.md +68 -0
- package/template/agent/skills/frontend-developer/references/react-rules/rendering-svg-precision.md +28 -0
- package/template/agent/skills/frontend-developer/references/react-rules/rendering-usetransition-loading.md +75 -0
- package/template/agent/skills/frontend-developer/references/react-rules/rerender-defer-reads.md +39 -0
- package/template/agent/skills/frontend-developer/references/react-rules/rerender-dependencies.md +45 -0
- package/template/agent/skills/frontend-developer/references/react-rules/rerender-derived-state-no-effect.md +40 -0
- package/template/agent/skills/frontend-developer/references/react-rules/rerender-derived-state.md +29 -0
- package/template/agent/skills/frontend-developer/references/react-rules/rerender-functional-setstate.md +74 -0
- package/template/agent/skills/frontend-developer/references/react-rules/rerender-lazy-state-init.md +58 -0
- package/template/agent/skills/frontend-developer/references/react-rules/rerender-memo-with-default-value.md +38 -0
- package/template/agent/skills/frontend-developer/references/react-rules/rerender-memo.md +44 -0
- package/template/agent/skills/frontend-developer/references/react-rules/rerender-move-effect-to-event.md +45 -0
- package/template/agent/skills/frontend-developer/references/react-rules/rerender-no-inline-components.md +82 -0
- package/template/agent/skills/frontend-developer/references/react-rules/rerender-simple-expression-in-memo.md +35 -0
- package/template/agent/skills/frontend-developer/references/react-rules/rerender-split-combined-hooks.md +64 -0
- package/template/agent/skills/frontend-developer/references/react-rules/rerender-transitions.md +40 -0
- package/template/agent/skills/frontend-developer/references/react-rules/rerender-use-deferred-value.md +59 -0
- package/template/agent/skills/frontend-developer/references/react-rules/rerender-use-ref-transient-values.md +73 -0
- package/template/agent/skills/frontend-developer/references/react-rules/server-after-nonblocking.md +73 -0
- package/template/agent/skills/frontend-developer/references/react-rules/server-auth-actions.md +96 -0
- package/template/agent/skills/frontend-developer/references/react-rules/server-cache-lru.md +41 -0
- package/template/agent/skills/frontend-developer/references/react-rules/server-cache-react.md +76 -0
- package/template/agent/skills/frontend-developer/references/react-rules/server-dedup-props.md +65 -0
- package/template/agent/skills/frontend-developer/references/react-rules/server-hoist-static-io.md +142 -0
- package/template/agent/skills/frontend-developer/references/react-rules/server-parallel-fetching.md +83 -0
- package/template/agent/skills/frontend-developer/references/react-rules/server-serialization.md +38 -0
- package/template/agent/skills/frontend-developer/references/svelte-sveltekit.md +220 -0
- package/template/agent/skills/frontend-developer/references/vanilla.md +275 -0
- package/template/agent/skills/frontend-developer/references/vue-nuxt.md +289 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/best-practices/_index.md +154 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/best-practices/animation-class-based-technique.md +254 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/best-practices/animation-state-driven-technique.md +291 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/best-practices/component-async.md +97 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/best-practices/component-data-flow.md +307 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/best-practices/component-fallthrough-attrs.md +174 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/best-practices/component-keep-alive.md +137 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/best-practices/component-slots.md +216 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/best-practices/component-suspense.md +228 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/best-practices/component-teleport.md +108 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/best-practices/component-transition-group.md +128 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/best-practices/component-transition.md +125 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/best-practices/composables.md +290 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/best-practices/directives.md +162 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/best-practices/perf-avoid-component-abstraction-in-lists.md +159 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/best-practices/perf-v-once-v-memo-directives.md +182 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/best-practices/perf-virtualize-large-lists.md +187 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/best-practices/plugins.md +166 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/best-practices/reactivity.md +344 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/best-practices/render-functions.md +201 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/best-practices/sfc.md +310 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/best-practices/state-management.md +135 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/best-practices/updated-hook-performance.md +187 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/router/_index.md +23 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/router/router-beforeenter-no-param-trigger.md +167 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/router/router-beforerouteenter-no-this.md +176 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/router/router-guard-async-await-pattern.md +227 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/router/router-navigation-guard-infinite-loop.md +187 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/router/router-navigation-guard-next-deprecated.md +150 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/router/router-param-change-no-lifecycle.md +181 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/router/router-simple-routing-cleanup.md +209 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/router/router-use-vue-router-for-production.md +183 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/testing/_index.md +29 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/testing/async-component-testing.md +163 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/testing/teleport-testing-complexity.md +158 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/testing/testing-async-await-flushpromises.md +175 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/testing/testing-browser-vs-node-runners.md +208 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/testing/testing-component-blackbox-approach.md +144 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/testing/testing-composables-helper-wrapper.md +238 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/testing/testing-e2e-playwright-recommended.md +242 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/testing/testing-no-snapshot-only.md +197 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/testing/testing-pinia-store-setup.md +228 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/testing/testing-suspense-async-components.md +229 -0
- package/template/agent/skills/frontend-developer/references/vue-rules/testing/testing-vitest-recommended-for-vue.md +204 -0
- package/template/agent/skills/mobile-developer/SKILL.md +52 -0
- package/template/agent/skills/mobile-developer/references/android-native.md +396 -0
- package/template/agent/skills/mobile-developer/references/android-rules/android-accessibility.md +36 -0
- package/template/agent/skills/mobile-developer/references/android-rules/android-architecture.md +52 -0
- package/template/agent/skills/mobile-developer/references/android-rules/android-coroutines.md +139 -0
- package/template/agent/skills/mobile-developer/references/android-rules/android-data-layer.md +51 -0
- package/template/agent/skills/mobile-developer/references/android-rules/android-emulator-skill.md +108 -0
- package/template/agent/skills/mobile-developer/references/android-rules/android-gradle-logic.md +126 -0
- package/template/agent/skills/mobile-developer/references/android-rules/android-retrofit.md +142 -0
- package/template/agent/skills/mobile-developer/references/android-rules/android-testing.md +102 -0
- package/template/agent/skills/mobile-developer/references/android-rules/android-viewmodel.md +43 -0
- package/template/agent/skills/mobile-developer/references/android-rules/coil-compose.md +74 -0
- package/template/agent/skills/mobile-developer/references/android-rules/compose-navigation.md +422 -0
- package/template/agent/skills/mobile-developer/references/android-rules/compose-performance-audit.md +199 -0
- package/template/agent/skills/mobile-developer/references/android-rules/compose-ui.md +49 -0
- package/template/agent/skills/mobile-developer/references/android-rules/gradle-build-performance.md +346 -0
- package/template/agent/skills/mobile-developer/references/android-rules/kotlin-concurrency-expert.md +169 -0
- package/template/agent/skills/mobile-developer/references/android-rules/rxjava-to-coroutines-migration.md +101 -0
- package/template/agent/skills/mobile-developer/references/android-rules/xml-to-compose-migration.md +338 -0
- package/template/agent/skills/mobile-developer/references/flutter-rules/dart-best-practices.md +52 -0
- package/template/agent/skills/mobile-developer/references/flutter-rules/dart-checks-migration.md +134 -0
- package/template/agent/skills/mobile-developer/references/flutter-rules/dart-cli-app-best-practices.md +123 -0
- package/template/agent/skills/mobile-developer/references/flutter-rules/dart-doc-validation.md +45 -0
- package/template/agent/skills/mobile-developer/references/flutter-rules/dart-matcher-best-practices.md +106 -0
- package/template/agent/skills/mobile-developer/references/flutter-rules/dart-modern-features.md +241 -0
- package/template/agent/skills/mobile-developer/references/flutter-rules/dart-package-maintenance.md +75 -0
- package/template/agent/skills/mobile-developer/references/flutter-rules/dart-test-fundamentals.md +124 -0
- package/template/agent/skills/mobile-developer/references/flutter.md +291 -0
- package/template/agent/skills/mobile-developer/references/ios-native.md +358 -0
- package/template/agent/skills/mobile-developer/references/ios-rules/accessibility-patterns.md +215 -0
- package/template/agent/skills/mobile-developer/references/ios-rules/animation-advanced.md +403 -0
- package/template/agent/skills/mobile-developer/references/ios-rules/animation-basics.md +284 -0
- package/template/agent/skills/mobile-developer/references/ios-rules/animation-transitions.md +326 -0
- package/template/agent/skills/mobile-developer/references/ios-rules/charts-accessibility.md +135 -0
- package/template/agent/skills/mobile-developer/references/ios-rules/charts.md +602 -0
- package/template/agent/skills/mobile-developer/references/ios-rules/image-optimization.md +203 -0
- package/template/agent/skills/mobile-developer/references/ios-rules/latest-apis.md +464 -0
- package/template/agent/skills/mobile-developer/references/ios-rules/layout-best-practices.md +266 -0
- package/template/agent/skills/mobile-developer/references/ios-rules/liquid-glass.md +416 -0
- package/template/agent/skills/mobile-developer/references/ios-rules/list-patterns.md +394 -0
- package/template/agent/skills/mobile-developer/references/ios-rules/macos-scenes.md +318 -0
- package/template/agent/skills/mobile-developer/references/ios-rules/macos-views.md +357 -0
- package/template/agent/skills/mobile-developer/references/ios-rules/macos-window-styling.md +303 -0
- package/template/agent/skills/mobile-developer/references/ios-rules/performance-patterns.md +403 -0
- package/template/agent/skills/mobile-developer/references/ios-rules/scroll-patterns.md +293 -0
- package/template/agent/skills/mobile-developer/references/ios-rules/sheet-navigation-patterns.md +363 -0
- package/template/agent/skills/mobile-developer/references/ios-rules/state-management.md +417 -0
- package/template/agent/skills/mobile-developer/references/ios-rules/view-structure.md +389 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/_sections.md +86 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/_template.md +28 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/animation-derived-value.md +53 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/animation-gesture-detector-press.md +95 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/animation-gpu-properties.md +65 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/design-system-compound-components.md +66 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/fonts-config-plugin.md +71 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/imports-design-system-folder.md +68 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/js-hoist-intl.md +61 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/list-performance-callbacks.md +44 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/list-performance-function-references.md +132 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/list-performance-images.md +53 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/list-performance-inline-objects.md +97 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/list-performance-item-expensive.md +94 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/list-performance-item-memo.md +82 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/list-performance-item-types.md +104 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/list-performance-virtualize.md +67 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/monorepo-native-deps-in-app.md +46 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/monorepo-single-dependency-versions.md +63 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/navigation-native-navigators.md +188 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/react-compiler-destructure-functions.md +50 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/react-compiler-reanimated-shared-values.md +48 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/react-state-dispatcher.md +91 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/react-state-fallback.md +56 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/react-state-minimize.md +65 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/rendering-no-falsy-and.md +74 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/rendering-text-in-text-component.md +36 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/scroll-position-no-state.md +82 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/state-ground-truth.md +80 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/ui-expo-image.md +66 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/ui-image-gallery.md +104 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/ui-measure-views.md +78 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/ui-menus.md +174 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/ui-native-modals.md +77 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/ui-pressable.md +61 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/ui-safe-area-scroll.md +65 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/ui-scrollview-content-inset.md +45 -0
- package/template/agent/skills/mobile-developer/references/react-native-rules/ui-styling.md +87 -0
- package/template/agent/skills/mobile-developer/references/react-native.md +345 -0
|
@@ -140,3 +140,55 @@ What are you building?
|
|
|
140
140
|
```
|
|
141
141
|
|
|
142
142
|
Primary CTAs belong in the **bottom 40%** of the screen.
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## Platform References
|
|
147
|
+
|
|
148
|
+
When this skill is invoked, detect the project's platform stack and read
|
|
149
|
+
the matching reference file(s) from `references/` before proceeding:
|
|
150
|
+
|
|
151
|
+
| Stack indicator | Reference file |
|
|
152
|
+
|---------------------------------------|-------------------------------|
|
|
153
|
+
| `package.json` with `react-native` | `references/react-native.md` |
|
|
154
|
+
| `pubspec.yaml` | `references/flutter.md` |
|
|
155
|
+
| `*.xcodeproj` or `Package.swift` | `references/ios-native.md` |
|
|
156
|
+
| `build.gradle.kts` or `build.gradle` | `references/android-native.md`|
|
|
157
|
+
|
|
158
|
+
If the project uses multiple stacks (e.g., React Native with native
|
|
159
|
+
modules), read ALL matching references.
|
|
160
|
+
|
|
161
|
+
If no stack indicator is found, ask the user which platform they're targeting.
|
|
162
|
+
|
|
163
|
+
### Granular Rules (React Native)
|
|
164
|
+
|
|
165
|
+
For React Native projects, `references/react-native-rules/` contains 36
|
|
166
|
+
individual rule files from [Vercel's agent-skills](https://github.com/vercel-labs/agent-skills).
|
|
167
|
+
Each rule covers one specific pattern with incorrect/correct code examples.
|
|
168
|
+
|
|
169
|
+
Read `references/react-native-rules/_sections.md` for the full index
|
|
170
|
+
organized by priority (CRITICAL → LOW). Reference individual rules
|
|
171
|
+
when working on specific areas (list performance, animation, UI patterns, etc.).
|
|
172
|
+
|
|
173
|
+
### Granular Rules (Flutter/Dart)
|
|
174
|
+
|
|
175
|
+
For Flutter projects, `references/flutter-rules/` contains 8 Dart skill
|
|
176
|
+
files from [kevmoo/dash_skills](https://github.com/kevmoo/dash_skills),
|
|
177
|
+
covering Dart language best practices, modern features, testing patterns,
|
|
178
|
+
and package maintenance.
|
|
179
|
+
|
|
180
|
+
### Granular Rules (Android)
|
|
181
|
+
|
|
182
|
+
For Android projects, `references/android-rules/` contains 17 skill
|
|
183
|
+
files from [awesome-android-agent-skills](https://github.com/new-silvermoon/awesome-android-agent-skills),
|
|
184
|
+
covering: Clean Architecture, Compose UI/Performance/Navigation,
|
|
185
|
+
ViewModel patterns, Retrofit networking, Kotlin Coroutines, Gradle
|
|
186
|
+
optimization, testing, and XML-to-Compose migration.
|
|
187
|
+
|
|
188
|
+
### Granular Rules (iOS/SwiftUI)
|
|
189
|
+
|
|
190
|
+
For iOS projects, `references/ios-rules/` contains 19 SwiftUI reference
|
|
191
|
+
files from [AvdLee/SwiftUI-Agent-Skill](https://github.com/AvdLee/SwiftUI-Agent-Skill),
|
|
192
|
+
covering: state management, view composition, performance, animations
|
|
193
|
+
(basics/advanced/transitions), navigation, Swift Charts, macOS support,
|
|
194
|
+
Liquid Glass (iOS 26+), and accessibility.
|
|
@@ -0,0 +1,396 @@
|
|
|
1
|
+
# Android Native (Kotlin / Jetpack Compose) Reference
|
|
2
|
+
|
|
3
|
+
> **Philosophy:** Material Design, Kotlin-first, Compose-first.
|
|
4
|
+
> Lifecycle-aware, configuration-change-safe, backwards-compatible.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Project Setup & Detection
|
|
9
|
+
|
|
10
|
+
**Stack indicators:** `build.gradle.kts` or `build.gradle`, `AndroidManifest.xml`, `settings.gradle.kts`.
|
|
11
|
+
|
|
12
|
+
**Key config files:**
|
|
13
|
+
|
|
14
|
+
| File | Purpose |
|
|
15
|
+
|------|---------|
|
|
16
|
+
| `build.gradle.kts` (app module) | App dependencies, minSdk, targetSdk, signing |
|
|
17
|
+
| `build.gradle.kts` (project) | Plugin versions, repositories |
|
|
18
|
+
| `settings.gradle.kts` | Module declarations, version catalog |
|
|
19
|
+
| `gradle/libs.versions.toml` | Gradle Version Catalog (centralized dependency versions) |
|
|
20
|
+
| `AndroidManifest.xml` | Permissions, components, intent filters |
|
|
21
|
+
| `proguard-rules.pro` | R8/ProGuard minification rules |
|
|
22
|
+
|
|
23
|
+
**Recommended project structure (feature-based, multi-module):**
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
app/
|
|
27
|
+
src/main/
|
|
28
|
+
java/com/example/myapp/
|
|
29
|
+
MyApp.kt # Application class
|
|
30
|
+
MainActivity.kt # Single Activity
|
|
31
|
+
navigation/
|
|
32
|
+
AppNavigation.kt # NavHost setup
|
|
33
|
+
res/
|
|
34
|
+
values/themes.xml
|
|
35
|
+
feature/
|
|
36
|
+
auth/
|
|
37
|
+
src/main/java/.../auth/
|
|
38
|
+
ui/LoginScreen.kt
|
|
39
|
+
LoginViewModel.kt
|
|
40
|
+
data/AuthRepository.kt
|
|
41
|
+
home/
|
|
42
|
+
src/main/java/.../home/
|
|
43
|
+
ui/HomeScreen.kt
|
|
44
|
+
HomeViewModel.kt
|
|
45
|
+
core/
|
|
46
|
+
data/ # Shared data layer
|
|
47
|
+
ui/ # Shared Compose components
|
|
48
|
+
network/ # Retrofit setup, API definitions
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Architecture Patterns
|
|
54
|
+
|
|
55
|
+
### MVVM with ViewModel + StateFlow
|
|
56
|
+
|
|
57
|
+
```kotlin
|
|
58
|
+
class ProfileViewModel @Inject constructor(
|
|
59
|
+
private val userRepository: UserRepository,
|
|
60
|
+
) : ViewModel() {
|
|
61
|
+
|
|
62
|
+
private val _uiState = MutableStateFlow<ProfileUiState>(ProfileUiState.Loading)
|
|
63
|
+
val uiState: StateFlow<ProfileUiState> = _uiState.asStateFlow()
|
|
64
|
+
|
|
65
|
+
init { loadProfile() }
|
|
66
|
+
|
|
67
|
+
private fun loadProfile() {
|
|
68
|
+
viewModelScope.launch {
|
|
69
|
+
_uiState.value = ProfileUiState.Loading
|
|
70
|
+
userRepository.getProfile()
|
|
71
|
+
.onSuccess { _uiState.value = ProfileUiState.Success(it) }
|
|
72
|
+
.onFailure { _uiState.value = ProfileUiState.Error(it.message) }
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
sealed interface ProfileUiState {
|
|
78
|
+
data object Loading : ProfileUiState
|
|
79
|
+
data class Success(val user: User) : ProfileUiState
|
|
80
|
+
data class Error(val message: String?) : ProfileUiState
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Dependency Injection
|
|
85
|
+
|
|
86
|
+
| Framework | Use When |
|
|
87
|
+
|-----------|----------|
|
|
88
|
+
| **Hilt** (recommended) | Most apps — Google-supported, integrates with ViewModel, WorkManager |
|
|
89
|
+
| **Koin** | Lightweight, no annotation processing, multiplatform support |
|
|
90
|
+
|
|
91
|
+
```kotlin
|
|
92
|
+
// Hilt module
|
|
93
|
+
@Module
|
|
94
|
+
@InstallIn(SingletonComponent::class)
|
|
95
|
+
object NetworkModule {
|
|
96
|
+
@Provides @Singleton
|
|
97
|
+
fun provideRetrofit(): Retrofit = Retrofit.Builder()
|
|
98
|
+
.baseUrl("https://api.example.com/")
|
|
99
|
+
.addConverterFactory(MoshiConverterFactory.create())
|
|
100
|
+
.build()
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// ViewModel injection
|
|
104
|
+
@HiltViewModel
|
|
105
|
+
class HomeViewModel @Inject constructor(
|
|
106
|
+
private val repository: ItemRepository,
|
|
107
|
+
) : ViewModel()
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Navigation
|
|
111
|
+
|
|
112
|
+
**Navigation Compose** — type-safe with Kotlin serialization:
|
|
113
|
+
|
|
114
|
+
```kotlin
|
|
115
|
+
@Serializable data class Profile(val id: String)
|
|
116
|
+
|
|
117
|
+
NavHost(navController, startDestination = Home) {
|
|
118
|
+
composable<Home> { HomeScreen(onNavigate = { navController.navigate(Profile(it)) }) }
|
|
119
|
+
composable<Profile> { backStackEntry ->
|
|
120
|
+
val profile: Profile = backStackEntry.toRoute()
|
|
121
|
+
ProfileScreen(id = profile.id)
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
- Use **single-Activity** architecture with Compose Navigation
|
|
127
|
+
- Use `NavBackStackEntry.toRoute()` for type-safe argument extraction
|
|
128
|
+
- Handle deep links via `deepLinks` parameter in `composable()`
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## Performance Optimization
|
|
133
|
+
|
|
134
|
+
### Critical Thresholds
|
|
135
|
+
|
|
136
|
+
| Metric | Target | Investigate |
|
|
137
|
+
|--------|--------|-------------|
|
|
138
|
+
| Cold start | < 1s | > 2s |
|
|
139
|
+
| Frame rendering | 16ms (60fps) | > 32ms |
|
|
140
|
+
| APK/AAB size | < 20MB | > 50MB |
|
|
141
|
+
| Memory (foreground) | < 150MB | > 300MB |
|
|
142
|
+
|
|
143
|
+
### Compose Performance
|
|
144
|
+
|
|
145
|
+
1. **Stability matters** — Compose skips recomposition for stable parameters. Unstable types (lists, lambdas) prevent skipping.
|
|
146
|
+
|
|
147
|
+
```kotlin
|
|
148
|
+
// ❌ Bad: List<Item> is unstable, recomposes every time
|
|
149
|
+
@Composable fun ItemList(items: List<Item>) { ... }
|
|
150
|
+
|
|
151
|
+
// ✅ Good: ImmutableList is stable, skips recomposition when data unchanged
|
|
152
|
+
@Composable fun ItemList(items: ImmutableList<Item>) { ... }
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
2. **`@Stable` and `@Immutable` annotations** — tell Compose your types are stable.
|
|
156
|
+
|
|
157
|
+
```kotlin
|
|
158
|
+
@Immutable
|
|
159
|
+
data class UserProfile(val id: String, val name: String, val avatarUrl: String)
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
3. **`LazyColumn` with stable keys** — always provide unique keys for correct recomposition and animation.
|
|
163
|
+
|
|
164
|
+
```kotlin
|
|
165
|
+
LazyColumn {
|
|
166
|
+
items(items, key = { it.id }) { item ->
|
|
167
|
+
ItemRow(item = item)
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
4. **`remember` wisely** — use `remember` for expensive computations, not simple derivations. Don't use `remember` with unstable keys.
|
|
173
|
+
|
|
174
|
+
5. **Baseline Profiles** — pre-compile hot paths at install time, reducing cold start time by 30-50%.
|
|
175
|
+
|
|
176
|
+
```kotlin
|
|
177
|
+
// benchmark/src/main/java/BaselineProfileGenerator.kt
|
|
178
|
+
@RunWith(AndroidJUnit4::class)
|
|
179
|
+
class BaselineProfileGenerator {
|
|
180
|
+
@get:Rule val rule = BaselineProfileRule()
|
|
181
|
+
|
|
182
|
+
@Test
|
|
183
|
+
fun generate() {
|
|
184
|
+
rule.collect("com.example.myapp") {
|
|
185
|
+
pressHome()
|
|
186
|
+
startActivityAndWait()
|
|
187
|
+
// Navigate through critical flows
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
6. **R8 minification** — always enable for release builds. Removes unused code and obfuscates.
|
|
194
|
+
|
|
195
|
+
7. **StrictMode** — enable in debug to catch disk/network on main thread:
|
|
196
|
+
|
|
197
|
+
```kotlin
|
|
198
|
+
if (BuildConfig.DEBUG) {
|
|
199
|
+
StrictMode.setThreadPolicy(StrictMode.ThreadPolicy.Builder()
|
|
200
|
+
.detectAll().penaltyLog().build())
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## Common Libraries Ecosystem
|
|
207
|
+
|
|
208
|
+
| Category | Recommended | Alternative |
|
|
209
|
+
|----------|-------------|-------------|
|
|
210
|
+
| **Networking** | `Retrofit` + `OkHttp` | `Ktor` |
|
|
211
|
+
| **JSON** | `Moshi` / `Kotlin Serialization` | `Gson` (legacy) |
|
|
212
|
+
| **Database** | `Room` | `SQLDelight` |
|
|
213
|
+
| **Preferences** | `DataStore` | `SharedPreferences` (legacy) |
|
|
214
|
+
| **Secure Storage** | `EncryptedSharedPreferences` | `Tink` |
|
|
215
|
+
| **Images** | `Coil` (Compose-native) | `Glide` |
|
|
216
|
+
| **DI** | `Hilt` | `Koin` |
|
|
217
|
+
| **UI** | Material 3 (`material3`) | — |
|
|
218
|
+
| **Async** | Kotlin `Flow` + `Coroutines` | RxJava (legacy) |
|
|
219
|
+
| **Paging** | `Paging 3` | — |
|
|
220
|
+
| **Work** | `WorkManager` | — |
|
|
221
|
+
| **Testing** | `JUnit 5` + `MockK` | `Mockito-Kotlin` |
|
|
222
|
+
| **Compose Testing** | `compose-test` | — |
|
|
223
|
+
| **Analytics** | Firebase Analytics | Amplitude |
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
## Anti-Patterns & Gotchas
|
|
228
|
+
|
|
229
|
+
| ❌ Don't | Why | ✅ Do Instead |
|
|
230
|
+
|----------|-----|---------------|
|
|
231
|
+
| Unstable lambdas in Compose | Prevents recomposition skipping | Extract to ViewModel, hoist to caller, or use `remember` |
|
|
232
|
+
| `MutableList`/`List` parameters | Unstable in Compose, always recomposes | `ImmutableList` from `kotlinx.collections.immutable` |
|
|
233
|
+
| `remember { mutableStateOf() }` for ViewModel state | ViewModel outlives Compose, wrong lifecycle | `StateFlow` in ViewModel, `collectAsStateWithLifecycle` in UI |
|
|
234
|
+
| Blocking main thread | ANR (Application Not Responding) | Coroutines with `Dispatchers.IO` |
|
|
235
|
+
| Missing ProGuard rules | Crashes in release (reflection-based libs) | Add keep rules for Retrofit, Moshi, Room models |
|
|
236
|
+
| Hardcoded dp/sp values everywhere | Inconsistent across screens | Design tokens / theme values |
|
|
237
|
+
| `GlobalScope.launch` | Lifecycle leak, no cancellation | `viewModelScope`, `lifecycleScope`, or custom scope |
|
|
238
|
+
| `SharedPreferences` for complex data | Race conditions, no type safety | `DataStore` with Proto or Preferences |
|
|
239
|
+
| Multiple Activities for navigation | Complex backstack, state loss | Single Activity + Compose Navigation |
|
|
240
|
+
| `@Preview` without sample data | Previews are useless | Use `@PreviewParameter` with sample providers |
|
|
241
|
+
|
|
242
|
+
### Compose-Specific Pitfalls
|
|
243
|
+
|
|
244
|
+
- **`derivedStateOf`** — use for expensive computations that depend on state. Don't use for simple reads.
|
|
245
|
+
- **`LaunchedEffect` vs `SideEffect`** — `LaunchedEffect` for suspend functions (runs once per key), `SideEffect` for every recomposition.
|
|
246
|
+
- **`rememberSaveable`** — survives configuration changes and process death. Use for user input, scroll position.
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
|
|
250
|
+
## Testing
|
|
251
|
+
|
|
252
|
+
| Layer | Tool | Purpose |
|
|
253
|
+
|-------|------|---------|
|
|
254
|
+
| **Unit** | JUnit 5 + MockK | ViewModel, Repository, UseCase |
|
|
255
|
+
| **Compose UI** | `createComposeRule()` | Component rendering and interaction |
|
|
256
|
+
| **Integration** | Espresso (+ Compose) | Full screen flows |
|
|
257
|
+
| **Robolectric** | JVM-based Android tests | Fast feedback, no emulator needed |
|
|
258
|
+
| **Screenshot** | Compose Preview Screenshot Testing | Visual regression |
|
|
259
|
+
|
|
260
|
+
**Testing Compose:**
|
|
261
|
+
|
|
262
|
+
```kotlin
|
|
263
|
+
@get:Rule val composeTestRule = createComposeRule()
|
|
264
|
+
|
|
265
|
+
@Test
|
|
266
|
+
fun showsLoginButton() {
|
|
267
|
+
composeTestRule.setContent { LoginScreen() }
|
|
268
|
+
composeTestRule.onNodeWithText("Log In").assertIsDisplayed()
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
@Test
|
|
272
|
+
fun submitForm() {
|
|
273
|
+
composeTestRule.setContent { LoginScreen() }
|
|
274
|
+
composeTestRule.onNodeWithTag("email_input").performTextInput("test@example.com")
|
|
275
|
+
composeTestRule.onNodeWithText("Log In").performClick()
|
|
276
|
+
composeTestRule.onNodeWithText("Welcome").assertIsDisplayed()
|
|
277
|
+
}
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
**ViewModel testing:**
|
|
281
|
+
|
|
282
|
+
```kotlin
|
|
283
|
+
@Test
|
|
284
|
+
fun loadProfile_success() = runTest {
|
|
285
|
+
val repo = mockk<UserRepository> {
|
|
286
|
+
coEvery { getProfile() } returns Result.success(testUser)
|
|
287
|
+
}
|
|
288
|
+
val vm = ProfileViewModel(repo)
|
|
289
|
+
vm.uiState.test {
|
|
290
|
+
assertThat(awaitItem()).isEqualTo(ProfileUiState.Loading)
|
|
291
|
+
assertThat(awaitItem()).isEqualTo(ProfileUiState.Success(testUser))
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
---
|
|
297
|
+
|
|
298
|
+
## Deployment & Distribution
|
|
299
|
+
|
|
300
|
+
### Build Commands
|
|
301
|
+
|
|
302
|
+
```bash
|
|
303
|
+
# Debug build
|
|
304
|
+
./gradlew assembleDebug
|
|
305
|
+
|
|
306
|
+
# Release APK
|
|
307
|
+
./gradlew assembleRelease
|
|
308
|
+
|
|
309
|
+
# Release AAB (Play Store required format)
|
|
310
|
+
./gradlew bundleRelease
|
|
311
|
+
|
|
312
|
+
# Run tests
|
|
313
|
+
./gradlew test # Unit tests
|
|
314
|
+
./gradlew connectedAndroidTest # Instrumented tests
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
### Distribution Channels
|
|
318
|
+
|
|
319
|
+
| Channel | Use When |
|
|
320
|
+
|---------|----------|
|
|
321
|
+
| **Google Play Internal Testing** | Fast internal feedback (up to 100 testers) |
|
|
322
|
+
| **Google Play Closed Testing** | Beta testing with larger groups |
|
|
323
|
+
| **Google Play Production** | Public release (staged rollout recommended) |
|
|
324
|
+
| **Firebase App Distribution** | Ad hoc testing, no Play Store needed |
|
|
325
|
+
|
|
326
|
+
### Signing Configuration
|
|
327
|
+
|
|
328
|
+
```kotlin
|
|
329
|
+
// build.gradle.kts
|
|
330
|
+
android {
|
|
331
|
+
signingConfigs {
|
|
332
|
+
create("release") {
|
|
333
|
+
storeFile = file(System.getenv("KEYSTORE_PATH"))
|
|
334
|
+
storePassword = System.getenv("KEYSTORE_PASSWORD")
|
|
335
|
+
keyAlias = System.getenv("KEY_ALIAS")
|
|
336
|
+
keyPassword = System.getenv("KEY_PASSWORD")
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
buildTypes {
|
|
340
|
+
release {
|
|
341
|
+
signingConfig = signingConfigs.getByName("release")
|
|
342
|
+
isMinifyEnabled = true
|
|
343
|
+
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
### App Size Optimization
|
|
350
|
+
- Enable R8 minification (`isMinifyEnabled = true`)
|
|
351
|
+
- Use Android App Bundle (`.aab`) — Google Play delivers optimized APK per device
|
|
352
|
+
- Remove unused resources with `shrinkResources = true`
|
|
353
|
+
- Use WebP for images (30% smaller than PNG)
|
|
354
|
+
- Split APKs by ABI if distributing outside Play Store
|
|
355
|
+
|
|
356
|
+
---
|
|
357
|
+
|
|
358
|
+
## Quick Reference — Granular Rules
|
|
359
|
+
|
|
360
|
+
Individual skill files in `android-rules/` with detailed patterns, code
|
|
361
|
+
examples, and audit workflows for Android/Kotlin/Compose development.
|
|
362
|
+
|
|
363
|
+
> Source: [awesome-android-agent-skills](https://github.com/new-silvermoon/awesome-android-agent-skills)
|
|
364
|
+
|
|
365
|
+
### Architecture & Core
|
|
366
|
+
|
|
367
|
+
- [android-architecture.md](android-rules/android-architecture.md) — Clean Architecture, modularization, Hilt DI
|
|
368
|
+
- [android-viewmodel.md](android-rules/android-viewmodel.md) — ViewModel + StateFlow/SharedFlow patterns
|
|
369
|
+
- [android-data-layer.md](android-rules/android-data-layer.md) — Repository pattern, offline-first sync
|
|
370
|
+
- [kotlin-concurrency-expert.md](android-rules/kotlin-concurrency-expert.md) — Coroutines triage & structured concurrency
|
|
371
|
+
- [android-coroutines.md](android-rules/android-coroutines.md) — Coroutines patterns
|
|
372
|
+
|
|
373
|
+
### Compose UI & Performance
|
|
374
|
+
|
|
375
|
+
- [compose-ui.md](android-rules/compose-ui.md) — Stateless composables, state hoisting, theming
|
|
376
|
+
- [compose-performance-audit.md](android-rules/compose-performance-audit.md) — Recomposition storms, unstable keys audit
|
|
377
|
+
- [compose-navigation.md](android-rules/compose-navigation.md) — Type-safe navigation, deep links, nested graphs
|
|
378
|
+
- [coil-compose.md](android-rules/coil-compose.md) — Coil image loading in Compose
|
|
379
|
+
|
|
380
|
+
### Networking & Data
|
|
381
|
+
|
|
382
|
+
- [android-retrofit.md](android-rules/android-retrofit.md) — Retrofit, OkHttp, serialization, interceptors
|
|
383
|
+
- [android-accessibility.md](android-rules/android-accessibility.md) — Content descriptions, touch targets, contrast
|
|
384
|
+
|
|
385
|
+
### Testing & Build
|
|
386
|
+
|
|
387
|
+
- [android-testing.md](android-rules/android-testing.md) — Unit, Hilt, screenshot testing (Roborazzi)
|
|
388
|
+
- [android-gradle-logic.md](android-rules/android-gradle-logic.md) — Convention plugins, version catalogs
|
|
389
|
+
- [gradle-build-performance.md](android-rules/gradle-build-performance.md) — Build time optimization (12 patterns)
|
|
390
|
+
- [android-emulator-skill.md](android-rules/android-emulator-skill.md) — ADB, emulator automation
|
|
391
|
+
|
|
392
|
+
### Migration
|
|
393
|
+
|
|
394
|
+
- [xml-to-compose-migration.md](android-rules/xml-to-compose-migration.md) — XML to Compose mapping tables
|
|
395
|
+
- [rxjava-to-coroutines-migration.md](android-rules/rxjava-to-coroutines-migration.md) — RxJava to Coroutines/Flow
|
|
396
|
+
|
package/template/agent/skills/mobile-developer/references/android-rules/android-accessibility.md
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: android-accessibility
|
|
3
|
+
description: Expert checklist and prompts for auditing and fixing Android accessibility issues, especially in Jetpack Compose.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Android Accessibility Checklist
|
|
7
|
+
|
|
8
|
+
## Instructions
|
|
9
|
+
|
|
10
|
+
Analyze the provided component or screen for the following accessibility aspects.
|
|
11
|
+
|
|
12
|
+
### 1. Content Descriptions
|
|
13
|
+
* **Check**: Do `Image` and `Icon` composables have a meaningful `contentDescription`?
|
|
14
|
+
* **Decorative**: If an image is purely decorative, use `contentDescription = null`.
|
|
15
|
+
* **Actionable**: If an element is clickable, the description should describe the *action* (e.g., "Play music"), not the icon (e.g., "Triangle").
|
|
16
|
+
|
|
17
|
+
### 2. Touch Target Size
|
|
18
|
+
* **Standard**: Minimum **48x48dp** for all interactive elements.
|
|
19
|
+
* **Fix**: Use `MinTouchTargetSize` or wrap in `Box` with appropriate padding if the visual icon is smaller.
|
|
20
|
+
|
|
21
|
+
### 3. Color Contrast
|
|
22
|
+
* **Standard**: WCAG AA requires **4.5:1** for normal text and **3.0:1** for large text/icons.
|
|
23
|
+
* **Tool**: Verify colors against backgrounds using contrast logic.
|
|
24
|
+
|
|
25
|
+
### 4. Focus & Semantics
|
|
26
|
+
* **Focus Order**: Ensure keyboard/screen-reader focus moves logically (e.g., Top-Start to Bottom-End).
|
|
27
|
+
* **Grouping**: Use `Modifier.semantics(mergeDescendants = true)` for complex items (like a row with text and icon) so they are announced as a single item.
|
|
28
|
+
* **State descriptions**: Use `stateDescription` to describe custom states (e.g., "Selected", "Checked") if standard semantics aren't enough.
|
|
29
|
+
|
|
30
|
+
### 5. Headings
|
|
31
|
+
* **Traversal**: Mark title texts with `Modifier.semantics { heading() }` to allow screen reader users to jump between sections.
|
|
32
|
+
|
|
33
|
+
## Example Prompts for Agent Usage
|
|
34
|
+
* "Analyze the content description of this Image. Is it appropriate?"
|
|
35
|
+
* "Check if the touch target size of this button is at least 48dp."
|
|
36
|
+
* "Does this custom toggle button report its 'Checked' state to TalkBack?"
|
package/template/agent/skills/mobile-developer/references/android-rules/android-architecture.md
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: android-architecture
|
|
3
|
+
description: Expert guidance on setting up and maintaining a modern Android application architecture using Clean Architecture and Hilt. Use this when asked about project structure, module setup, or dependency injection.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Android Modern Architecture & Modularization
|
|
7
|
+
|
|
8
|
+
## Instructions
|
|
9
|
+
|
|
10
|
+
When designing or refactoring an Android application, adhere to the **Guide to App Architecture** and **Clean Architecture** principles.
|
|
11
|
+
|
|
12
|
+
### 1. High-Level Layers
|
|
13
|
+
Structure the application into three primary layers. Dependencies must strictly flow **inwards** (or downwards) to the core logic.
|
|
14
|
+
|
|
15
|
+
* **UI Layer (Presentation)**:
|
|
16
|
+
* **Responsibility**: Displaying data and handling user interactions.
|
|
17
|
+
* **Components**: Activities, Fragments, Composables, ViewModels.
|
|
18
|
+
* **Dependencies**: Depends on the Domain Layer (or Data Layer if simple). **Never** depends on the Data Layer implementation details directly.
|
|
19
|
+
* **Domain Layer (Business Logic) [Optional but Recommended]**:
|
|
20
|
+
* **Responsibility**: Encapsulating complex business rules and reuse.
|
|
21
|
+
* **Components**: Use Cases (e.g., `GetLatestNewsUseCase`), Domain Models (pure Kotlin data classes).
|
|
22
|
+
* **Pure Kotlin**: Must NOT contain any Android framework dependencies (no `android.*` imports).
|
|
23
|
+
* **Dependencies**: Depends on Repository Interfaces.
|
|
24
|
+
* **Data Layer**:
|
|
25
|
+
* **Responsibility**: Managing application data (fetching, caching, saving).
|
|
26
|
+
* **Components**: Repositories (implementations), Data Sources (Retrofit APIs, Room DAOs).
|
|
27
|
+
* **Dependencies**: Depends only on external sources and libraries.
|
|
28
|
+
|
|
29
|
+
### 2. Dependency Injection with Hilt
|
|
30
|
+
Use **Hilt** for all dependency injection.
|
|
31
|
+
|
|
32
|
+
* **@HiltAndroidApp**: Annotate the `Application` class.
|
|
33
|
+
* **@AndroidEntryPoint**: Annotate Activities and Fragments.
|
|
34
|
+
* **@HiltViewModel**: Annotate ViewModels; use standard `constructor` injection.
|
|
35
|
+
* **Modules**:
|
|
36
|
+
* Use `@Module` and `@InstallIn(SingletonComponent::class)` for app-wide singletons (e.g., Network, Database).
|
|
37
|
+
* Use `@Binds` in an abstract class to bind interface implementations (cleaner than `@Provides`).
|
|
38
|
+
|
|
39
|
+
### 3. Modularization Strategy
|
|
40
|
+
For production apps, use a multi-module strategy to improve build times and separation of concerns.
|
|
41
|
+
|
|
42
|
+
* **:app**: The main entry point, connects features.
|
|
43
|
+
* **:core:model**: Shared domain models (Pure Kotlin).
|
|
44
|
+
* **:core:data**: Repositories, Data Sources, Database, Network.
|
|
45
|
+
* **:core:domain**: Use Cases and Repository Interfaces.
|
|
46
|
+
* **:core:ui**: Shared Composables, Theme, Resources.
|
|
47
|
+
* **:feature:[name]**: Standalone feature modules containing their own UI and ViewModels. Depends on `:core:domain` and `:core:ui`.
|
|
48
|
+
|
|
49
|
+
### 4. Checklist for implementation
|
|
50
|
+
- [ ] Ensure `Domain` layer has no Android dependencies.
|
|
51
|
+
- [ ] Repositories should default to main-safe suspend functions (use `Dispatchers.IO` internally if needed).
|
|
52
|
+
- [ ] ViewModels should interact with the UI layer via `StateFlow` (see `android-viewmodel` skill).
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: android-coroutines
|
|
3
|
+
description: Authoritative rules and patterns for production-quality Kotlin Coroutines onto Android. Covers structured concurrency, lifecycle integration, and reactive streams.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Android Coroutines Expert Skill
|
|
7
|
+
|
|
8
|
+
This skill provides authoritative rules and patterns for writing production-quality Kotlin Coroutines code on Android. It enforces structured concurrency, lifecycle safety, and modern best practices (2025 standards).
|
|
9
|
+
|
|
10
|
+
## Responsibilities
|
|
11
|
+
|
|
12
|
+
* **Asynchronous Logic**: Implementing suspend functions, Dispatcher management, and parallel execution.
|
|
13
|
+
* **Reactive Streams**: Implementing `Flow`, `StateFlow`, `SharedFlow`, and `callbackFlow`.
|
|
14
|
+
* **Lifecycle Integration**: Managing scopes (`viewModelScope`, `lifecycleScope`) and safe collection (`repeatOnLifecycle`).
|
|
15
|
+
* **Error Handling**: Implementing `CoroutineExceptionHandler`, `SupervisorJob`, and proper `try-catch` hierarchies.
|
|
16
|
+
* **Cancellability**: Ensuring long-running operations are cooperative using `ensureActive()`.
|
|
17
|
+
* **Testing**: Setting up `TestDispatcher` and `runTest`.
|
|
18
|
+
|
|
19
|
+
## Applicability
|
|
20
|
+
|
|
21
|
+
Activate this skill when the user asks to:
|
|
22
|
+
* "Fetch data from an API/Database."
|
|
23
|
+
* "Perform background processing."
|
|
24
|
+
* "Fix a memory leak" related to threads/tasks.
|
|
25
|
+
* "Convert a listener/callback to Coroutines."
|
|
26
|
+
* "Implement a ViewModel."
|
|
27
|
+
* "Handle UI state updates."
|
|
28
|
+
|
|
29
|
+
## Critical Rules & Constraints
|
|
30
|
+
|
|
31
|
+
### 1. Dispatcher Injection (Testability)
|
|
32
|
+
* **NEVER** hardcode Dispatchers (e.g., `Dispatchers.IO`, `Dispatchers.Default`) inside classes.
|
|
33
|
+
* **ALWAYS** inject a `CoroutineDispatcher` via the constructor.
|
|
34
|
+
* **DEFAULT** to `Dispatchers.IO` in the constructor argument for convenience, but allow it to be overridden.
|
|
35
|
+
|
|
36
|
+
```kotlin
|
|
37
|
+
// CORRECT
|
|
38
|
+
class UserRepository(
|
|
39
|
+
private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO
|
|
40
|
+
) { ... }
|
|
41
|
+
|
|
42
|
+
// INCORRECT
|
|
43
|
+
class UserRepository {
|
|
44
|
+
fun getData() = withContext(Dispatchers.IO) { ... }
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### 2. Main-Safety
|
|
49
|
+
* All suspend functions defined in the Data or Domain layer must be **main-safe**.
|
|
50
|
+
* **One-shot calls** should be exposed as `suspend` functions.
|
|
51
|
+
* **Data changes** should be exposed as `Flow`.
|
|
52
|
+
* The caller (ViewModel) should be able to call them from `Dispatchers.Main` without blocking the UI.
|
|
53
|
+
* Use `withContext(dispatcher)` inside the repository implementation to move execution to the background.
|
|
54
|
+
|
|
55
|
+
### 3. Lifecycle-Aware Collection
|
|
56
|
+
* **NEVER** collect a flow directly in `lifecycleScope.launch` or `launchWhenStarted` (deprecated/unsafe).
|
|
57
|
+
* **ALWAYS** use `repeatOnLifecycle(Lifecycle.State.STARTED)` for collecting flows in Activities or Fragments.
|
|
58
|
+
|
|
59
|
+
```kotlin
|
|
60
|
+
// CORRECT
|
|
61
|
+
viewLifecycleOwner.lifecycleScope.launch {
|
|
62
|
+
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
|
|
63
|
+
viewModel.uiState.collect { ... }
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### 4. ViewModel Scope Usage
|
|
69
|
+
* Use `viewModelScope` for initiating coroutines in ViewModels.
|
|
70
|
+
* Do not expose suspend functions from the ViewModel to the View. The ViewModel should expose `StateFlow` or `SharedFlow` that the View observes.
|
|
71
|
+
|
|
72
|
+
### 5. Mutable State Encapsulation
|
|
73
|
+
* **NEVER** expose `MutableStateFlow` or `MutableSharedFlow` publicly.
|
|
74
|
+
* Expose them as read-only `StateFlow` or `Flow` using `.asStateFlow()` or upcasting.
|
|
75
|
+
|
|
76
|
+
### 6. GlobalScope Prohibition
|
|
77
|
+
* **NEVER** use `GlobalScope`. It breaks structured concurrency and leads to leaks.
|
|
78
|
+
* If a task must survive the current scope, use an injected `applicationScope` (a custom scope tied to the Application lifecycle).
|
|
79
|
+
|
|
80
|
+
### 7. Exception Handling
|
|
81
|
+
* **NEVER** catch `CancellationException` in a generic `catch (e: Exception)` block without rethrowing it.
|
|
82
|
+
* Use `runCatching` only if you explicitly rethrow `CancellationException`.
|
|
83
|
+
* Use `CoroutineExceptionHandler` only for top-level coroutines (inside `launch`). It has no effect inside `async` or child coroutines.
|
|
84
|
+
|
|
85
|
+
### 8. Cancellability
|
|
86
|
+
* Coroutines feature **cooperative cancellation**. They don't stop immediately unless they check for cancellation.
|
|
87
|
+
* **ALWAYS** call `ensureActive()` or `yield()` in tight loops (e.g., processing a large list, reading files) to check for cancellation.
|
|
88
|
+
* Standard functions like `delay()` and `withContext()` are already cancellable.
|
|
89
|
+
|
|
90
|
+
### 9. Callback Conversion
|
|
91
|
+
* Use `callbackFlow` to convert callback-based APIs to Flow.
|
|
92
|
+
* **ALWAYS** use `awaitClose` at the end of the `callbackFlow` block to unregister listeners.
|
|
93
|
+
|
|
94
|
+
## Code Patterns
|
|
95
|
+
|
|
96
|
+
### Repository Pattern with Flow
|
|
97
|
+
|
|
98
|
+
```kotlin
|
|
99
|
+
class NewsRepository(
|
|
100
|
+
private val remoteDataSource: NewsRemoteDataSource,
|
|
101
|
+
private val externalScope: CoroutineScope, // For app-wide events
|
|
102
|
+
private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO
|
|
103
|
+
) {
|
|
104
|
+
val newsUpdates: Flow<List<News>> = flow {
|
|
105
|
+
val news = remoteDataSource.fetchLatestNews()
|
|
106
|
+
emit(news)
|
|
107
|
+
}.flowOn(ioDispatcher) // Upstream executes on IO
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Parallel Execution
|
|
112
|
+
|
|
113
|
+
```kotlin
|
|
114
|
+
suspend fun loadDashboardData() = coroutineScope {
|
|
115
|
+
val userDeferred = async { userRepo.getUser() }
|
|
116
|
+
val feedDeferred = async { feedRepo.getFeed() }
|
|
117
|
+
|
|
118
|
+
// Wait for both
|
|
119
|
+
DashboardData(
|
|
120
|
+
user = userDeferred.await(),
|
|
121
|
+
feed = feedDeferred.await()
|
|
122
|
+
)
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Testing with runTest
|
|
127
|
+
|
|
128
|
+
```kotlin
|
|
129
|
+
@Test
|
|
130
|
+
fun testViewModel() = runTest {
|
|
131
|
+
val testDispatcher = StandardTestDispatcher(testScheduler)
|
|
132
|
+
val viewModel = MyViewModel(testDispatcher)
|
|
133
|
+
|
|
134
|
+
viewModel.loadData()
|
|
135
|
+
advanceUntilIdle() // Process coroutines
|
|
136
|
+
|
|
137
|
+
assertEquals(expectedState, viewModel.uiState.value)
|
|
138
|
+
}
|
|
139
|
+
```
|