mobile-ai-agents 1.0.23

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.
Files changed (194) hide show
  1. package/AGENTS.md +228 -0
  2. package/CLAUDE.md +236 -0
  3. package/LICENSE +21 -0
  4. package/README.md +652 -0
  5. package/agents/android/android-crash-analyzer/README.md +134 -0
  6. package/agents/android/android-crash-analyzer/agent.md +206 -0
  7. package/agents/android/android-crash-analyzer/example-input.md +138 -0
  8. package/agents/android/android-crash-analyzer/example-output.md +225 -0
  9. package/agents/android/anr-investigation/README.md +78 -0
  10. package/agents/android/anr-investigation/agent.md +117 -0
  11. package/agents/android/anr-investigation/example-input.md +62 -0
  12. package/agents/android/anr-investigation/example-output.md +103 -0
  13. package/agents/android/axiom/agent.md +197 -0
  14. package/agents/android/code-reviewer/README.md +108 -0
  15. package/agents/android/code-reviewer/agent.md +210 -0
  16. package/agents/android/code-reviewer/example-input.md +116 -0
  17. package/agents/android/code-reviewer/example-output.md +115 -0
  18. package/agents/android/compose-navigation/README.md +76 -0
  19. package/agents/android/compose-navigation/agent.md +121 -0
  20. package/agents/android/compose-navigation/example-input.md +49 -0
  21. package/agents/android/compose-navigation/example-output.md +325 -0
  22. package/agents/android/compose-screen-builder/README.md +95 -0
  23. package/agents/android/compose-screen-builder/agent.md +170 -0
  24. package/agents/android/compose-screen-builder/example-input.md +40 -0
  25. package/agents/android/compose-screen-builder/example-output.md +568 -0
  26. package/agents/android/compose-ui-reviewer/README.md +73 -0
  27. package/agents/android/compose-ui-reviewer/agent.md +253 -0
  28. package/agents/android/compose-ui-reviewer/example-input.md +84 -0
  29. package/agents/android/compose-ui-reviewer/example-output.md +102 -0
  30. package/agents/android/crash-analyzer/README.md +53 -0
  31. package/agents/android/crash-analyzer/agent.md +295 -0
  32. package/agents/android/memory-leak-analyzer/README.md +79 -0
  33. package/agents/android/memory-leak-analyzer/agent.md +116 -0
  34. package/agents/android/memory-leak-analyzer/example-input.md +78 -0
  35. package/agents/android/memory-leak-analyzer/example-output.md +128 -0
  36. package/agents/cross-platform/accessibility-auditor/README.md +47 -0
  37. package/agents/cross-platform/accessibility-auditor/agent.md +268 -0
  38. package/agents/cross-platform/accessibility-auditor/example-input.md +84 -0
  39. package/agents/cross-platform/accessibility-auditor/example-output.md +132 -0
  40. package/agents/cross-platform/appforge/agent.md +303 -0
  41. package/agents/cross-platform/ci-cd-generator/README.md +65 -0
  42. package/agents/cross-platform/ci-cd-generator/agent.md +422 -0
  43. package/agents/cross-platform/ci-cd-generator/example-input.md +69 -0
  44. package/agents/cross-platform/ci-cd-generator/example-output.md +261 -0
  45. package/agents/cross-platform/crasher/agent.md +221 -0
  46. package/agents/cross-platform/figma/agent.md +247 -0
  47. package/agents/cross-platform/launchpad/agent.md +330 -0
  48. package/agents/cross-platform/mobile-harness/agent.md +422 -0
  49. package/agents/cross-platform/mobile-memory/agent.md +429 -0
  50. package/agents/cross-platform/perf/agent.md +261 -0
  51. package/agents/cross-platform/pipeline/agent.md +288 -0
  52. package/agents/cross-platform/release-notes-generator/README.md +63 -0
  53. package/agents/cross-platform/release-notes-generator/agent.md +218 -0
  54. package/agents/cross-platform/release-notes-generator/example-input.md +71 -0
  55. package/agents/cross-platform/release-notes-generator/example-output.md +96 -0
  56. package/agents/cross-platform/scribe/agent.md +180 -0
  57. package/agents/cross-platform/security-scanner/README.md +61 -0
  58. package/agents/cross-platform/security-scanner/agent.md +287 -0
  59. package/agents/cross-platform/security-scanner/example-input.md +77 -0
  60. package/agents/cross-platform/security-scanner/example-output.md +141 -0
  61. package/agents/cross-platform/sentinel/agent.md +217 -0
  62. package/agents/cross-platform/store-listing-writer/README.md +58 -0
  63. package/agents/cross-platform/store-listing-writer/agent.md +380 -0
  64. package/agents/cross-platform/store-listing-writer/example-input.md +67 -0
  65. package/agents/cross-platform/store-listing-writer/example-output.md +131 -0
  66. package/agents/flutter/bloc-feature-builder/README.md +101 -0
  67. package/agents/flutter/bloc-feature-builder/agent.md +225 -0
  68. package/agents/flutter/bloc-feature-builder/example-input.md +47 -0
  69. package/agents/flutter/bloc-feature-builder/example-output.md +838 -0
  70. package/agents/flutter/dart/agent.md +223 -0
  71. package/agents/flutter/widget-generator/README.md +66 -0
  72. package/agents/flutter/widget-generator/agent.md +264 -0
  73. package/agents/flutter/widget-generator/example-input.md +71 -0
  74. package/agents/flutter/widget-generator/example-output.md +163 -0
  75. package/agents/gaming/forge/agent.md +197 -0
  76. package/agents/gaming/unreal/agent.md +200 -0
  77. package/agents/ios/crash-analyzer/README.md +69 -0
  78. package/agents/ios/crash-analyzer/agent.md +300 -0
  79. package/agents/ios/crash-analyzer/example-input.md +83 -0
  80. package/agents/ios/crash-analyzer/example-output.md +126 -0
  81. package/agents/ios/swift/agent.md +206 -0
  82. package/agents/ios/swift-reviewer/README.md +68 -0
  83. package/agents/ios/swift-reviewer/agent.md +231 -0
  84. package/agents/ios/swift-reviewer/example-input.md +100 -0
  85. package/agents/ios/swift-reviewer/example-output.md +127 -0
  86. package/agents/react-native/bridge/agent.md +212 -0
  87. package/agents/react-native/performance-optimizer/README.md +81 -0
  88. package/agents/react-native/performance-optimizer/agent.md +284 -0
  89. package/agents/react-native/performance-optimizer/example-input.md +104 -0
  90. package/agents/react-native/performance-optimizer/example-output.md +132 -0
  91. package/agents/unity/shader-generator/README.md +77 -0
  92. package/agents/unity/shader-generator/agent.md +270 -0
  93. package/agents/unity/shader-generator/example-input.md +70 -0
  94. package/agents/unity/shader-generator/example-output.md +160 -0
  95. package/agents/unreal/blueprint-advisor/README.md +71 -0
  96. package/agents/unreal/blueprint-advisor/agent.md +311 -0
  97. package/agents/unreal/blueprint-advisor/example-input.md +73 -0
  98. package/agents/unreal/blueprint-advisor/example-output.md +217 -0
  99. package/cli/index.js +1091 -0
  100. package/docs/agent-guide.md +138 -0
  101. package/docs/chatgpt-integration.md +219 -0
  102. package/docs/core-loops.md +143 -0
  103. package/docs/cursor-integration.md +143 -0
  104. package/docs/getting-started.md +132 -0
  105. package/docs/index.html +711 -0
  106. package/docs/installation.md +271 -0
  107. package/docs/mobile-harness.md +160 -0
  108. package/docs/mobile-mcp.md +172 -0
  109. package/docs/mobile-memory.md +349 -0
  110. package/docs/release-process.md +85 -0
  111. package/docs/releases/release-v1.0.0.md +165 -0
  112. package/docs/roadmap/github-issues.md +239 -0
  113. package/docs/skill-categories.md +125 -0
  114. package/docs/vscode-copilot-integration.md +104 -0
  115. package/docs/wiki.md +615 -0
  116. package/install.sh +507 -0
  117. package/mobile-karpathy.md +79 -0
  118. package/package.json +57 -0
  119. package/skills/android/README.md +31 -0
  120. package/skills/android/android-tdd.md +89 -0
  121. package/skills/android/anr-investigation.md +251 -0
  122. package/skills/android/code-review.md +98 -0
  123. package/skills/android/compose-migration.md +48 -0
  124. package/skills/android/compose-review.md +78 -0
  125. package/skills/android/kotlin-modernize.md +51 -0
  126. package/skills/android/memory-leak-investigation.md +256 -0
  127. package/skills/android/proguard-rules.md +48 -0
  128. package/skills/cross-platform/accessibility-audit.md +63 -0
  129. package/skills/cross-platform/api-versioning.md +59 -0
  130. package/skills/cross-platform/clean-code-audit.md +239 -0
  131. package/skills/cross-platform/crash-triage.md +53 -0
  132. package/skills/cross-platform/deeplink-debug.md +57 -0
  133. package/skills/cross-platform/feature-slice.md +48 -0
  134. package/skills/cross-platform/grill-mobile.md +64 -0
  135. package/skills/cross-platform/mobile-mcp-qa.md +193 -0
  136. package/skills/cross-platform/mobile-memory-graph.md +179 -0
  137. package/skills/cross-platform/mobile-memory-save.md +210 -0
  138. package/skills/cross-platform/mobile-memory-search.md +154 -0
  139. package/skills/cross-platform/perf-audit.md +61 -0
  140. package/skills/cross-platform/prd-verification.md +324 -0
  141. package/skills/cross-platform/release-prep.md +64 -0
  142. package/skills/cross-platform/security-audit.md +281 -0
  143. package/skills/cross-platform/store-listing.md +75 -0
  144. package/skills/flutter/README.md +32 -0
  145. package/skills/flutter/dart-modernize.md +47 -0
  146. package/skills/flutter/flutter-review.md +59 -0
  147. package/skills/flutter/flutter-tdd.md +73 -0
  148. package/skills/flutter/widget-extract.md +41 -0
  149. package/skills/flutter/widget-gen.md +131 -0
  150. package/skills/gaming/blueprint-to-cpp.md +51 -0
  151. package/skills/gaming/game-perf.md +54 -0
  152. package/skills/gaming/shader-gen.md +44 -0
  153. package/skills/gaming/unity-tdd.md +85 -0
  154. package/skills/ios/README.md +45 -0
  155. package/skills/ios/data-persistence.md +151 -0
  156. package/skills/ios/ios-tdd.md +90 -0
  157. package/skills/ios/networking.md +139 -0
  158. package/skills/ios/performance.md +122 -0
  159. package/skills/ios/swift-concurrency.md +57 -0
  160. package/skills/ios/swift-review.md +124 -0
  161. package/skills/ios/swiftui-review.md +49 -0
  162. package/skills/ios/swiftui-state.md +122 -0
  163. package/skills/ios/unit-testing.md +144 -0
  164. package/skills/ios/xcode-warnings.md +37 -0
  165. package/skills/react-native/README.md +42 -0
  166. package/skills/react-native/bridge-audit.md +104 -0
  167. package/skills/react-native/expo-optimize.md +55 -0
  168. package/skills/react-native/new-arch-migrate.md +53 -0
  169. package/skills/react-native/performance.md +124 -0
  170. package/skills/react-native/rn-review.md +53 -0
  171. package/skills/react-native/rn-tdd.md +76 -0
  172. package/skills/shared/README.md +46 -0
  173. package/skills/shared/accessibility-audit.md +132 -0
  174. package/skills/shared/crash-analysis.md +110 -0
  175. package/skills/shared/security-scan.md +149 -0
  176. package/skills/unity/README.md +31 -0
  177. package/skills/unity/shader-review.md +110 -0
  178. package/templates/agent-template.md +88 -0
  179. package/templates/prompt-template.md +50 -0
  180. package/templates/skill-template.md +64 -0
  181. package/templates/workflow-template.md +48 -0
  182. package/workflows/app-launch.md +66 -0
  183. package/workflows/appforge-workflow.md +232 -0
  184. package/workflows/ci-setup.md +77 -0
  185. package/workflows/crash-to-fix.md +71 -0
  186. package/workflows/feature-ship.md +61 -0
  187. package/workflows/game-level.md +72 -0
  188. package/workflows/mobile-harness.md +319 -0
  189. package/workflows/mobile-mcp-qa.md +228 -0
  190. package/workflows/mobile-memory-workflow.md +243 -0
  191. package/workflows/new-project-setup.md +93 -0
  192. package/workflows/new-screen.md +68 -0
  193. package/workflows/perf-sprint.md +78 -0
  194. package/workflows/release-cycle.md +71 -0
@@ -0,0 +1,115 @@
1
+ # Example Output — Android Code Reviewer
2
+
3
+ Full agent response to the input in [`example-input.md`](example-input.md).
4
+
5
+ ---
6
+
7
+ ```
8
+ REVIEW SUMMARY
9
+ ==============
10
+ File: app/src/main/java/com/example/socialapp/ui/profile/ProfileViewModel.kt
11
+ Layer: ViewModel
12
+ Issues Found: 7
13
+ Critical: 4 Warning: 2 Info: 1
14
+
15
+ FINDINGS
16
+ --------
17
+
18
+ [CRITICAL] Line 19 — GlobalScope used instead of viewModelScope
19
+ Problem : GlobalScope is not tied to the ViewModel's lifecycle. When the ViewModel
20
+ is cleared (screen navigated away, process death), the coroutine continues
21
+ running, holding references to the ViewModel's LiveData and potentially the
22
+ Fragment. This is a guaranteed scope leak.
23
+ Fix : Replace both GlobalScope.launch calls with viewModelScope.launch:
24
+ fun loadUser(userId: String) {
25
+ viewModelScope.launch {
26
+ ...
27
+ }
28
+ }
29
+
30
+ [CRITICAL] Line 20 — LiveData.value assigned from a background coroutine thread
31
+ Problem : GlobalScope.launch uses Dispatchers.Default by default. Calling
32
+ isLoading.value = true on a non-Main thread throws CalledFromWrongThreadException
33
+ in debug builds and causes silent data races in release builds.
34
+ LiveData.value can only be set from the Main thread; LiveData.postValue
35
+ is the background-safe alternative, but it introduces a delivery delay.
36
+ Fix : Either switch the coroutine to the Main dispatcher:
37
+ viewModelScope.launch(Dispatchers.Main) { isLoading.value = true; ... }
38
+ Or migrate isLoading to MutableStateFlow and update it from any thread via .value.
39
+ The cleanest solution is viewModelScope.launch, which defaults to Main.
40
+
41
+ [CRITICAL] Lines 22 & 42 — UserRepository instantiated directly inside ViewModel
42
+ Problem : new UserRepository() (or UserRepository() in Kotlin) constructs a concrete
43
+ dependency inside the ViewModel. This:
44
+ (1) makes the class impossible to unit-test without the real network/database,
45
+ (2) violates the Dependency Inversion Principle,
46
+ (3) creates a new repository instance on every function call, bypassing any
47
+ caching or connection pooling in the repository.
48
+ Fix : Inject UserRepository via the constructor. With Hilt:
49
+ @HiltViewModel
50
+ class ProfileViewModel @Inject constructor(
51
+ private val userRepository: UserRepository
52
+ ) : ViewModel() { ... }
53
+ Then use userRepository.getUser(userId) instead of UserRepository().getUser(userId).
54
+
55
+ [CRITICAL] Lines 36 & 38 — !! force-unwrap on user.value
56
+ Problem : user.value!! will throw NullPointerException if saveProfile() is called before
57
+ loadUser() completes, or if loadUser() failed with an error. The !! operator
58
+ should be treated as a code smell in production ViewModel code — it converts a
59
+ compile-time nullable into a runtime crash.
60
+ Fix : Use safe navigation and an early return:
61
+ val currentUser = user.value ?: run {
62
+ errorMessage.value = "No user loaded"
63
+ return
64
+ }
65
+ val updated = User(id = currentUser.id, name = name, bio = bio,
66
+ avatarUrl = currentUser.avatarUrl)
67
+
68
+ [WARNING] Line 34 — null check on non-nullable String (always false)
69
+ Problem : name == null is always false because name: String is non-nullable in Kotlin.
70
+ The compiler treats this as a warning. The intent was to guard against an empty
71
+ string, but the null check is dead code that misleads future readers.
72
+ Fix : Replace with:
73
+ if (name.isBlank()) return
74
+ isBlank() checks for both empty and whitespace-only strings, which is the
75
+ correct guard for a user-facing name field.
76
+
77
+ [WARNING] Lines 13–15 — MutableLiveData exposed directly as public properties
78
+ Problem : Exposing MutableLiveData publicly allows any observer to call .value = ...
79
+ from outside the ViewModel, breaking the single-source-of-truth pattern and
80
+ making state mutations untraceable.
81
+ Fix : Follow the backing property pattern:
82
+ private val _user = MutableLiveData<User>()
83
+ val user: LiveData<User> = _user
84
+
85
+ private val _isLoading = MutableLiveData<Boolean>()
86
+ val isLoading: LiveData<Boolean> = _isLoading
87
+
88
+ [INFO] Lines 13–15 — Consider migrating from LiveData to StateFlow
89
+ Problem : LiveData is lifecycle-aware but less composable than StateFlow and requires
90
+ Android framework classes (LifecycleOwner) to observe. For new ViewModels,
91
+ StateFlow + collectAsStateWithLifecycle() is the idiomatic Kotlin choice and
92
+ integrates directly with Jetpack Compose.
93
+ Fix : private val _user = MutableStateFlow<User?>(null)
94
+ val user: StateFlow<User?> = _user.asStateFlow()
95
+ In the Fragment: collect with repeatOnLifecycle(STARTED).
96
+
97
+ CLEAN ARCHITECTURE ASSESSMENT
98
+ ------------------------------
99
+ Layer boundary respected: No
100
+ → UserRepository() is instantiated directly inside ViewModel. The ViewModel should
101
+ depend on an abstraction (interface), not a concrete repository implementation.
102
+ Inject via Hilt constructor injection.
103
+
104
+ COROUTINE SAFETY
105
+ ----------------
106
+ Scope leaks detected: Yes
107
+ → Two GlobalScope.launch calls (lines 19 and 41). Both must be replaced with
108
+ viewModelScope.launch. viewModelScope is automatically cancelled in onCleared().
109
+
110
+ TESTABILITY SCORE: 1/10
111
+ → Direct UserRepository instantiation and GlobalScope make this class effectively
112
+ untestable. After applying the fixes, testability rises to ~8/10.
113
+
114
+ OVERALL VERDICT: NEEDS WORK
115
+ ```
@@ -0,0 +1,76 @@
1
+ # Android Compose Navigation Architect
2
+
3
+ > Generate or review scalable Jetpack Compose navigation with type-safe routes, nested graphs, bottom navigation, deep links, and tests.
4
+
5
+ ---
6
+
7
+ ## What It Does
8
+
9
+ - Generates Navigation Compose 2.8+ type-safe routes using `@Serializable`
10
+ - Creates root and feature-level graph-builder extensions
11
+ - Designs nested auth, onboarding, checkout, or other subflows
12
+ - Implements bottom navigation with state restoration
13
+ - Handles typed arguments through `toRoute<T>()`
14
+ - Shows `SavedStateHandle.toRoute<T>()` for ViewModels
15
+ - Defines deep-link and authentication behavior
16
+ - Reviews duplicate routes, unsafe arguments, incorrect `popUpTo`, and back-stack bugs
17
+ - Generates navigation tests
18
+
19
+ ---
20
+
21
+ ## Files
22
+
23
+ | File | Purpose |
24
+ |---|---|
25
+ | [`agent.md`](agent.md) | Input/output contract and system prompt |
26
+ | [`example-input.md`](example-input.md) | Real app navigation requirements |
27
+ | [`example-output.md`](example-output.md) | Complete generated navigation architecture |
28
+
29
+ ---
30
+
31
+ ## Quick Start
32
+
33
+ ```text
34
+ Use the agent at agents/android/compose-navigation/agent.md.
35
+
36
+ MODE: GENERATE
37
+ PACKAGE: com.example.shop
38
+ NAVIGATION_VERSION: 2.8.9
39
+ KOTLIN_VERSION: 2.0
40
+ ...
41
+ ```
42
+
43
+ Install only this agent:
44
+
45
+ ```bash
46
+ npx mobile-ai-agents add agent compose-navigation
47
+ ```
48
+
49
+ ---
50
+
51
+ ## Design Principles
52
+
53
+ - Routes are types, not strings.
54
+ - Screens expose callbacks, not `NavController`.
55
+ - Feature modules own their internal destinations.
56
+ - Route arguments contain IDs, not full objects.
57
+ - Bottom tabs preserve independent state.
58
+ - Back-stack changes are deliberate and documented.
59
+ - Deep links are validated before privileged navigation.
60
+ - Navigation behavior is covered by tests.
61
+
62
+ ---
63
+
64
+ ## Related Agents
65
+
66
+ - [`compose-screen-builder`](../compose-screen-builder/) for screen implementation
67
+ - [`compose-ui-reviewer`](../compose-ui-reviewer/) for UI quality
68
+ - [`axiom`](../axiom/) for Android architecture review
69
+
70
+ ---
71
+
72
+ ## Official References
73
+
74
+ - [Navigation with Compose](https://developer.android.com/develop/ui/compose/navigation)
75
+ - [Type safety in Kotlin DSL and Navigation Compose](https://developer.android.com/guide/navigation/design/type-safety)
76
+ - [Test Navigation](https://developer.android.com/guide/navigation/testing)
@@ -0,0 +1,121 @@
1
+ # NAVIGATOR — Android Compose Navigation Architect
2
+
3
+ **Platform:** Android (Kotlin / Jetpack Compose / Navigation Compose)
4
+ **Personality:** Back-stack cartographer. Every destination has a type and every pop has a reason.
5
+ **Category:** Architecture / Code Generation / Code Review
6
+ **Complexity:** High
7
+ **Tested With:** GPT-5.4
8
+
9
+ ---
10
+
11
+ ## Purpose
12
+
13
+ Designs or reviews scalable Jetpack Compose navigation using type-safe routes, nested feature graphs, bottom navigation, deep links, authentication gates, predictable back-stack behavior, and testable screen callbacks.
14
+
15
+ ---
16
+
17
+ ## Input Format
18
+
19
+ ```text
20
+ MODE: <GENERATE | REVIEW>
21
+ PACKAGE: <base package>
22
+ NAVIGATION_VERSION: <version, e.g. 2.8.9>
23
+ KOTLIN_VERSION: <version>
24
+ MODULES: <single app module or module list>
25
+ SCREENS:
26
+ - <screen and arguments>
27
+ FLOWS:
28
+ - <navigation flow>
29
+ BOTTOM_NAVIGATION:
30
+ - <tab destinations or "none">
31
+ DEEP_LINKS:
32
+ - <URI and destination or "none">
33
+ AUTH_RULES:
34
+ - <authentication/onboarding conditions or "none">
35
+ EXISTING_CODE:
36
+ <required in REVIEW mode; optional in GENERATE mode>
37
+ ```
38
+
39
+ ---
40
+
41
+ ## Output Format
42
+
43
+ ````
44
+ NAVIGATION ARCHITECTURE
45
+ =======================
46
+ Mode:
47
+ Verdict: PASS | NEEDS WORK | GENERATED
48
+
49
+ GRAPH
50
+ -----
51
+ <compact graph description>
52
+
53
+ FILES
54
+ -----
55
+ ## File: <path>
56
+ ```kotlin
57
+ <complete code>
58
+ ```
59
+
60
+ BACK-STACK RULES
61
+ ----------------
62
+ <rules>
63
+
64
+ DEEP-LINK RULES
65
+ ---------------
66
+ <rules>
67
+
68
+ TEST PLAN
69
+ ---------
70
+ <tests>
71
+
72
+ REVIEW FINDINGS
73
+ ---------------
74
+ <findings or "Not applicable">
75
+
76
+ DEPENDENCIES
77
+ ------------
78
+ <Gradle dependencies>
79
+ ````
80
+
81
+ ---
82
+
83
+ ## System Prompt
84
+
85
+ ```text
86
+ You are NAVIGATOR, a senior Android navigation architect specializing in Kotlin, Jetpack Compose, Navigation Compose, modularization, deep links, and back-stack correctness.
87
+
88
+ Support GENERATE and REVIEW modes.
89
+
90
+ Rules:
91
+ 1. For Navigation 2.8+, use @Serializable route objects/classes, composable<T>(), navigation<T>(), navigate(route), NavBackStackEntry.toRoute<T>(), and SavedStateHandle.toRoute<T>(). Do not generate hardcoded route strings.
92
+ 2. Pass stable identifiers only. Never pass repositories, ViewModels, mutable objects, or large domain objects as arguments.
93
+ 3. Screens receive typed callbacks such as onProductClick(id); do not pass NavController into leaf screens.
94
+ 4. Put routes and graph-builder extensions outside UI screen files. Use one feature navigation contract per module.
95
+ 5. Use nested graphs for self-contained flows such as auth, onboarding, checkout, and games.
96
+ 6. Bottom navigation must use launchSingleTop, restoreState, and popUpTo with saveState. Define reselection behavior explicitly.
97
+ 7. Authentication redirects must preserve the intended destination without putting authorization decisions in Composables.
98
+ 8. Deep links must validate hosts, paths, arguments, and authentication before privileged navigation.
99
+ 9. Explain popUpTo and inclusive choices. Prevent duplicate destinations and accidental stack clearing.
100
+ 10. Include navigation tests using TestNavHostController or an equivalent testable navigation surface.
101
+ 11. In REVIEW mode, assign CRITICAL, WARNING, or INFO and provide corrected code.
102
+ 12. If the project uses Navigation below 2.8, state the limitation and provide a migration plan before type-safe code.
103
+
104
+ Return complete compilable Kotlin for the requested scope. Do not invent screens or flows.
105
+
106
+ Output MUST follow the exact format specified. Do not add extra sections or omit any section.
107
+ ```
108
+
109
+ ---
110
+
111
+ ## Example
112
+
113
+ See [`example-input.md`](example-input.md) and [`example-output.md`](example-output.md).
114
+
115
+ ---
116
+
117
+ ## Notes
118
+
119
+ - Type-safe Navigation Compose APIs require Navigation 2.8.0 or newer and Kotlin Serialization.
120
+ - The agent targets Navigation Compose 2.x. Navigation 3 should be requested explicitly because it uses a different architecture.
121
+ - Complex payloads belong in repositories or saved state; routes carry IDs and small primitives.
@@ -0,0 +1,49 @@
1
+ # Example Input
2
+
3
+ ```text
4
+ MODE: GENERATE
5
+ PACKAGE: com.example.catalog
6
+ NAVIGATION_VERSION: 2.8.9
7
+ KOTLIN_VERSION: 2.0
8
+ MODULES:
9
+ - :app
10
+ - :feature:home
11
+ - :feature:search
12
+ - :feature:favorites
13
+ - :feature:profile
14
+ - :feature:product
15
+
16
+ SCREENS:
17
+ - Home — no arguments
18
+ - Search — optional initialQuery: String
19
+ - Favorites — no arguments
20
+ - Profile — no arguments
21
+ - Settings — no arguments
22
+ - ProductDetail — productId: String
23
+ - SignIn — optional redirectProductId: String
24
+
25
+ FLOWS:
26
+ - Home, Search, Favorites, and Profile are top-level destinations.
27
+ - Product cards open ProductDetail.
28
+ - Settings opens from Profile.
29
+ - Unauthenticated users opening ProductDetail go to SignIn, then continue to ProductDetail.
30
+ - Back from ProductDetail returns to the previous tab.
31
+
32
+ BOTTOM_NAVIGATION:
33
+ - Home
34
+ - Search
35
+ - Favorites
36
+ - Profile
37
+
38
+ DEEP_LINKS:
39
+ - https://catalog.example.com/products/{productId} -> ProductDetail
40
+
41
+ AUTH_RULES:
42
+ - Home, Search, Favorites, and Profile are public.
43
+ - ProductDetail requires authentication.
44
+ - Preserve productId through sign-in.
45
+
46
+ EXISTING_CODE:
47
+ None.
48
+ ```
49
+
@@ -0,0 +1,325 @@
1
+ # Example Output
2
+
3
+ ## Navigation Architecture
4
+
5
+ Mode: `GENERATE`
6
+ Verdict: `GENERATED`
7
+
8
+ ### Graph
9
+
10
+ ```text
11
+ AppGraph
12
+ ├── Home
13
+ ├── Search(initialQuery?)
14
+ ├── Favorites
15
+ ├── Profile
16
+ ├── Settings
17
+ ├── AuthGraph
18
+ │ └── SignIn(redirectProductId?)
19
+ └── ProductDetail(productId)
20
+ ```
21
+
22
+ Top-level tabs are direct destinations so each tab can save and restore its state. Authentication is a nested graph because sign-in is a self-contained flow. Product navigation goes through an authentication-aware coordinator callback in the app layer.
23
+
24
+ ## Files
25
+
26
+ ### File: `app/navigation/AppRoute.kt`
27
+
28
+ ```kotlin
29
+ package com.example.catalog.navigation
30
+
31
+ import kotlinx.serialization.Serializable
32
+
33
+ sealed interface AppRoute {
34
+ @Serializable
35
+ data object Home : AppRoute
36
+
37
+ @Serializable
38
+ data class Search(val initialQuery: String? = null) : AppRoute
39
+
40
+ @Serializable
41
+ data object Favorites : AppRoute
42
+
43
+ @Serializable
44
+ data object Profile : AppRoute
45
+
46
+ @Serializable
47
+ data object Settings : AppRoute
48
+
49
+ @Serializable
50
+ data class ProductDetail(val productId: String) : AppRoute
51
+
52
+ @Serializable
53
+ data object AuthGraph : AppRoute
54
+
55
+ @Serializable
56
+ data class SignIn(val redirectProductId: String? = null) : AppRoute
57
+ }
58
+ ```
59
+
60
+ ### File: `app/navigation/TopLevelDestination.kt`
61
+
62
+ ```kotlin
63
+ package com.example.catalog.navigation
64
+
65
+ import androidx.compose.material.icons.Icons
66
+ import androidx.compose.material.icons.outlined.FavoriteBorder
67
+ import androidx.compose.material.icons.outlined.Home
68
+ import androidx.compose.material.icons.outlined.Person
69
+ import androidx.compose.material.icons.outlined.Search
70
+ import androidx.compose.ui.graphics.vector.ImageVector
71
+
72
+ enum class TopLevelDestination(
73
+ val route: AppRoute,
74
+ val label: String,
75
+ val icon: ImageVector,
76
+ ) {
77
+ HOME(AppRoute.Home, "Home", Icons.Outlined.Home),
78
+ SEARCH(AppRoute.Search(), "Search", Icons.Outlined.Search),
79
+ FAVORITES(AppRoute.Favorites, "Favorites", Icons.Outlined.FavoriteBorder),
80
+ PROFILE(AppRoute.Profile, "Profile", Icons.Outlined.Person),
81
+ }
82
+ ```
83
+
84
+ ### File: `app/navigation/NavControllerExtensions.kt`
85
+
86
+ ```kotlin
87
+ package com.example.catalog.navigation
88
+
89
+ import androidx.navigation.NavGraph.Companion.findStartDestination
90
+ import androidx.navigation.NavHostController
91
+
92
+ fun NavHostController.navigateToTopLevel(
93
+ destination: TopLevelDestination,
94
+ ) {
95
+ navigate(destination.route) {
96
+ popUpTo(graph.findStartDestination().id) {
97
+ saveState = true
98
+ }
99
+ launchSingleTop = true
100
+ restoreState = true
101
+ }
102
+ }
103
+ ```
104
+
105
+ ### File: `app/navigation/AppNavHost.kt`
106
+
107
+ ```kotlin
108
+ package com.example.catalog.navigation
109
+
110
+ import androidx.compose.runtime.Composable
111
+ import androidx.navigation.NavHostController
112
+ import androidx.navigation.compose.NavHost
113
+ import androidx.navigation.compose.composable
114
+ import androidx.navigation.navigation
115
+ import androidx.navigation.toRoute
116
+ import com.example.catalog.feature.favorites.FavoritesScreen
117
+ import com.example.catalog.feature.home.HomeScreen
118
+ import com.example.catalog.feature.product.ProductDetailScreen
119
+ import com.example.catalog.feature.profile.ProfileScreen
120
+ import com.example.catalog.feature.profile.SettingsScreen
121
+ import com.example.catalog.feature.search.SearchScreen
122
+ import com.example.catalog.feature.signin.SignInScreen
123
+
124
+ @Composable
125
+ fun AppNavHost(
126
+ navController: NavHostController,
127
+ isAuthenticated: () -> Boolean,
128
+ ) {
129
+ fun openProduct(productId: String) {
130
+ val route = if (isAuthenticated()) {
131
+ AppRoute.ProductDetail(productId)
132
+ } else {
133
+ AppRoute.SignIn(redirectProductId = productId)
134
+ }
135
+ navController.navigate(route)
136
+ }
137
+
138
+ NavHost(
139
+ navController = navController,
140
+ startDestination = AppRoute.Home,
141
+ ) {
142
+ composable<AppRoute.Home> {
143
+ HomeScreen(onProductClick = ::openProduct)
144
+ }
145
+
146
+ composable<AppRoute.Search> { entry ->
147
+ val route = entry.toRoute<AppRoute.Search>()
148
+ SearchScreen(
149
+ initialQuery = route.initialQuery,
150
+ onProductClick = ::openProduct,
151
+ )
152
+ }
153
+
154
+ composable<AppRoute.Favorites> {
155
+ FavoritesScreen(onProductClick = ::openProduct)
156
+ }
157
+
158
+ composable<AppRoute.Profile> {
159
+ ProfileScreen(
160
+ onSettingsClick = {
161
+ navController.navigate(AppRoute.Settings)
162
+ },
163
+ )
164
+ }
165
+
166
+ composable<AppRoute.Settings> {
167
+ SettingsScreen(onBack = navController::navigateUp)
168
+ }
169
+
170
+ composable<AppRoute.ProductDetail>(
171
+ deepLinks = listOf(
172
+ androidx.navigation.navDeepLink<AppRoute.ProductDetail>(
173
+ basePath = "https://catalog.example.com/products",
174
+ ),
175
+ ),
176
+ ) { entry ->
177
+ val route = entry.toRoute<AppRoute.ProductDetail>()
178
+ ProductDetailScreen(
179
+ productId = route.productId,
180
+ onBack = navController::navigateUp,
181
+ )
182
+ }
183
+
184
+ navigation<AppRoute.AuthGraph>(
185
+ startDestination = AppRoute.SignIn(),
186
+ ) {
187
+ composable<AppRoute.SignIn> { entry ->
188
+ val route = entry.toRoute<AppRoute.SignIn>()
189
+ SignInScreen(
190
+ onSignedIn = {
191
+ val redirect = route.redirectProductId
192
+ if (redirect == null) {
193
+ navController.popBackStack()
194
+ } else {
195
+ navController.navigate(
196
+ AppRoute.ProductDetail(redirect),
197
+ ) {
198
+ popUpTo<AppRoute.SignIn> {
199
+ inclusive = true
200
+ }
201
+ }
202
+ }
203
+ },
204
+ onCancel = navController::navigateUp,
205
+ )
206
+ }
207
+ }
208
+ }
209
+ }
210
+ ```
211
+
212
+ ### File: `feature/product/ProductDetailViewModel.kt`
213
+
214
+ ```kotlin
215
+ package com.example.catalog.feature.product
216
+
217
+ import androidx.lifecycle.SavedStateHandle
218
+ import androidx.lifecycle.ViewModel
219
+ import androidx.navigation.toRoute
220
+ import com.example.catalog.navigation.AppRoute
221
+ import dagger.hilt.android.lifecycle.HiltViewModel
222
+ import javax.inject.Inject
223
+
224
+ @HiltViewModel
225
+ class ProductDetailViewModel @Inject constructor(
226
+ savedStateHandle: SavedStateHandle,
227
+ ) : ViewModel() {
228
+ private val route = savedStateHandle.toRoute<AppRoute.ProductDetail>()
229
+
230
+ val productId: String = route.productId
231
+ }
232
+ ```
233
+
234
+ ### File: `app/navigation/AppNavigationTest.kt`
235
+
236
+ ```kotlin
237
+ package com.example.catalog.navigation
238
+
239
+ import androidx.compose.ui.test.junit4.createComposeTestRule
240
+ import androidx.navigation.compose.ComposeNavigator
241
+ import androidx.navigation.hasRoute
242
+ import androidx.navigation.testing.TestNavHostController
243
+ import androidx.test.core.app.ApplicationProvider
244
+ import org.junit.Assert.assertTrue
245
+ import org.junit.Before
246
+ import org.junit.Rule
247
+ import org.junit.Test
248
+
249
+ class AppNavigationTest {
250
+ @get:Rule
251
+ val composeRule = createComposeTestRule()
252
+
253
+ private lateinit var navController: TestNavHostController
254
+
255
+ @Before
256
+ fun setUp() {
257
+ navController = TestNavHostController(
258
+ ApplicationProvider.getApplicationContext(),
259
+ ).apply {
260
+ navigatorProvider.addNavigator(ComposeNavigator())
261
+ }
262
+ }
263
+
264
+ @Test
265
+ fun startsOnHome() {
266
+ composeRule.setContent {
267
+ AppNavHost(
268
+ navController = navController,
269
+ isAuthenticated = { true },
270
+ )
271
+ }
272
+
273
+ assertTrue(
274
+ navController.currentBackStackEntry
275
+ ?.destination
276
+ ?.hasRoute<AppRoute.Home>() == true,
277
+ )
278
+ }
279
+ }
280
+ ```
281
+
282
+ ## Back-Stack Rules
283
+
284
+ 1. Top-level tab navigation saves and restores state.
285
+ 2. `launchSingleTop` prevents duplicate tab destinations.
286
+ 3. Product detail is pushed above the current tab, so back returns to that tab.
287
+ 4. Successful sign-in removes only `SignIn`, then opens the preserved product.
288
+ 5. Settings is pushed above Profile and uses `navigateUp()`.
289
+
290
+ ## Deep-Link Rules
291
+
292
+ 1. Accept only the HTTPS host `catalog.example.com`.
293
+ 2. Parse `productId` through the typed route.
294
+ 3. Validate that `productId` is non-blank before loading data.
295
+ 4. If unauthenticated, preserve the ID and enter `AuthGraph`.
296
+ 5. Do not trust client navigation as authorization; the backend must enforce access.
297
+
298
+ ## Test Plan
299
+
300
+ - Verify the graph starts on Home.
301
+ - Verify tapping a product opens typed `ProductDetail`.
302
+ - Verify unauthenticated product navigation opens SignIn.
303
+ - Verify successful sign-in removes SignIn and opens the intended product.
304
+ - Verify switching tabs restores scroll/state and does not duplicate tabs.
305
+ - Verify back from ProductDetail returns to the originating tab.
306
+ - Verify the HTTPS product deep link opens the correct product.
307
+ - Verify malformed or blank product IDs show a safe error state.
308
+
309
+ ## Review Findings
310
+
311
+ Not applicable.
312
+
313
+ ## Dependencies
314
+
315
+ ```kotlin
316
+ plugins {
317
+ kotlin("plugin.serialization")
318
+ }
319
+
320
+ dependencies {
321
+ implementation("androidx.navigation:navigation-compose:2.8.9")
322
+ implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3")
323
+ androidTestImplementation("androidx.navigation:navigation-testing:2.8.9")
324
+ }
325
+ ```