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.
- package/AGENTS.md +228 -0
- package/CLAUDE.md +236 -0
- package/LICENSE +21 -0
- package/README.md +652 -0
- package/agents/android/android-crash-analyzer/README.md +134 -0
- package/agents/android/android-crash-analyzer/agent.md +206 -0
- package/agents/android/android-crash-analyzer/example-input.md +138 -0
- package/agents/android/android-crash-analyzer/example-output.md +225 -0
- package/agents/android/anr-investigation/README.md +78 -0
- package/agents/android/anr-investigation/agent.md +117 -0
- package/agents/android/anr-investigation/example-input.md +62 -0
- package/agents/android/anr-investigation/example-output.md +103 -0
- package/agents/android/axiom/agent.md +197 -0
- package/agents/android/code-reviewer/README.md +108 -0
- package/agents/android/code-reviewer/agent.md +210 -0
- package/agents/android/code-reviewer/example-input.md +116 -0
- package/agents/android/code-reviewer/example-output.md +115 -0
- package/agents/android/compose-navigation/README.md +76 -0
- package/agents/android/compose-navigation/agent.md +121 -0
- package/agents/android/compose-navigation/example-input.md +49 -0
- package/agents/android/compose-navigation/example-output.md +325 -0
- package/agents/android/compose-screen-builder/README.md +95 -0
- package/agents/android/compose-screen-builder/agent.md +170 -0
- package/agents/android/compose-screen-builder/example-input.md +40 -0
- package/agents/android/compose-screen-builder/example-output.md +568 -0
- package/agents/android/compose-ui-reviewer/README.md +73 -0
- package/agents/android/compose-ui-reviewer/agent.md +253 -0
- package/agents/android/compose-ui-reviewer/example-input.md +84 -0
- package/agents/android/compose-ui-reviewer/example-output.md +102 -0
- package/agents/android/crash-analyzer/README.md +53 -0
- package/agents/android/crash-analyzer/agent.md +295 -0
- package/agents/android/memory-leak-analyzer/README.md +79 -0
- package/agents/android/memory-leak-analyzer/agent.md +116 -0
- package/agents/android/memory-leak-analyzer/example-input.md +78 -0
- package/agents/android/memory-leak-analyzer/example-output.md +128 -0
- package/agents/cross-platform/accessibility-auditor/README.md +47 -0
- package/agents/cross-platform/accessibility-auditor/agent.md +268 -0
- package/agents/cross-platform/accessibility-auditor/example-input.md +84 -0
- package/agents/cross-platform/accessibility-auditor/example-output.md +132 -0
- package/agents/cross-platform/appforge/agent.md +303 -0
- package/agents/cross-platform/ci-cd-generator/README.md +65 -0
- package/agents/cross-platform/ci-cd-generator/agent.md +422 -0
- package/agents/cross-platform/ci-cd-generator/example-input.md +69 -0
- package/agents/cross-platform/ci-cd-generator/example-output.md +261 -0
- package/agents/cross-platform/crasher/agent.md +221 -0
- package/agents/cross-platform/figma/agent.md +247 -0
- package/agents/cross-platform/launchpad/agent.md +330 -0
- package/agents/cross-platform/mobile-harness/agent.md +422 -0
- package/agents/cross-platform/mobile-memory/agent.md +429 -0
- package/agents/cross-platform/perf/agent.md +261 -0
- package/agents/cross-platform/pipeline/agent.md +288 -0
- package/agents/cross-platform/release-notes-generator/README.md +63 -0
- package/agents/cross-platform/release-notes-generator/agent.md +218 -0
- package/agents/cross-platform/release-notes-generator/example-input.md +71 -0
- package/agents/cross-platform/release-notes-generator/example-output.md +96 -0
- package/agents/cross-platform/scribe/agent.md +180 -0
- package/agents/cross-platform/security-scanner/README.md +61 -0
- package/agents/cross-platform/security-scanner/agent.md +287 -0
- package/agents/cross-platform/security-scanner/example-input.md +77 -0
- package/agents/cross-platform/security-scanner/example-output.md +141 -0
- package/agents/cross-platform/sentinel/agent.md +217 -0
- package/agents/cross-platform/store-listing-writer/README.md +58 -0
- package/agents/cross-platform/store-listing-writer/agent.md +380 -0
- package/agents/cross-platform/store-listing-writer/example-input.md +67 -0
- package/agents/cross-platform/store-listing-writer/example-output.md +131 -0
- package/agents/flutter/bloc-feature-builder/README.md +101 -0
- package/agents/flutter/bloc-feature-builder/agent.md +225 -0
- package/agents/flutter/bloc-feature-builder/example-input.md +47 -0
- package/agents/flutter/bloc-feature-builder/example-output.md +838 -0
- package/agents/flutter/dart/agent.md +223 -0
- package/agents/flutter/widget-generator/README.md +66 -0
- package/agents/flutter/widget-generator/agent.md +264 -0
- package/agents/flutter/widget-generator/example-input.md +71 -0
- package/agents/flutter/widget-generator/example-output.md +163 -0
- package/agents/gaming/forge/agent.md +197 -0
- package/agents/gaming/unreal/agent.md +200 -0
- package/agents/ios/crash-analyzer/README.md +69 -0
- package/agents/ios/crash-analyzer/agent.md +300 -0
- package/agents/ios/crash-analyzer/example-input.md +83 -0
- package/agents/ios/crash-analyzer/example-output.md +126 -0
- package/agents/ios/swift/agent.md +206 -0
- package/agents/ios/swift-reviewer/README.md +68 -0
- package/agents/ios/swift-reviewer/agent.md +231 -0
- package/agents/ios/swift-reviewer/example-input.md +100 -0
- package/agents/ios/swift-reviewer/example-output.md +127 -0
- package/agents/react-native/bridge/agent.md +212 -0
- package/agents/react-native/performance-optimizer/README.md +81 -0
- package/agents/react-native/performance-optimizer/agent.md +284 -0
- package/agents/react-native/performance-optimizer/example-input.md +104 -0
- package/agents/react-native/performance-optimizer/example-output.md +132 -0
- package/agents/unity/shader-generator/README.md +77 -0
- package/agents/unity/shader-generator/agent.md +270 -0
- package/agents/unity/shader-generator/example-input.md +70 -0
- package/agents/unity/shader-generator/example-output.md +160 -0
- package/agents/unreal/blueprint-advisor/README.md +71 -0
- package/agents/unreal/blueprint-advisor/agent.md +311 -0
- package/agents/unreal/blueprint-advisor/example-input.md +73 -0
- package/agents/unreal/blueprint-advisor/example-output.md +217 -0
- package/cli/index.js +1091 -0
- package/docs/agent-guide.md +138 -0
- package/docs/chatgpt-integration.md +219 -0
- package/docs/core-loops.md +143 -0
- package/docs/cursor-integration.md +143 -0
- package/docs/getting-started.md +132 -0
- package/docs/index.html +711 -0
- package/docs/installation.md +271 -0
- package/docs/mobile-harness.md +160 -0
- package/docs/mobile-mcp.md +172 -0
- package/docs/mobile-memory.md +349 -0
- package/docs/release-process.md +85 -0
- package/docs/releases/release-v1.0.0.md +165 -0
- package/docs/roadmap/github-issues.md +239 -0
- package/docs/skill-categories.md +125 -0
- package/docs/vscode-copilot-integration.md +104 -0
- package/docs/wiki.md +615 -0
- package/install.sh +507 -0
- package/mobile-karpathy.md +79 -0
- package/package.json +57 -0
- package/skills/android/README.md +31 -0
- package/skills/android/android-tdd.md +89 -0
- package/skills/android/anr-investigation.md +251 -0
- package/skills/android/code-review.md +98 -0
- package/skills/android/compose-migration.md +48 -0
- package/skills/android/compose-review.md +78 -0
- package/skills/android/kotlin-modernize.md +51 -0
- package/skills/android/memory-leak-investigation.md +256 -0
- package/skills/android/proguard-rules.md +48 -0
- package/skills/cross-platform/accessibility-audit.md +63 -0
- package/skills/cross-platform/api-versioning.md +59 -0
- package/skills/cross-platform/clean-code-audit.md +239 -0
- package/skills/cross-platform/crash-triage.md +53 -0
- package/skills/cross-platform/deeplink-debug.md +57 -0
- package/skills/cross-platform/feature-slice.md +48 -0
- package/skills/cross-platform/grill-mobile.md +64 -0
- package/skills/cross-platform/mobile-mcp-qa.md +193 -0
- package/skills/cross-platform/mobile-memory-graph.md +179 -0
- package/skills/cross-platform/mobile-memory-save.md +210 -0
- package/skills/cross-platform/mobile-memory-search.md +154 -0
- package/skills/cross-platform/perf-audit.md +61 -0
- package/skills/cross-platform/prd-verification.md +324 -0
- package/skills/cross-platform/release-prep.md +64 -0
- package/skills/cross-platform/security-audit.md +281 -0
- package/skills/cross-platform/store-listing.md +75 -0
- package/skills/flutter/README.md +32 -0
- package/skills/flutter/dart-modernize.md +47 -0
- package/skills/flutter/flutter-review.md +59 -0
- package/skills/flutter/flutter-tdd.md +73 -0
- package/skills/flutter/widget-extract.md +41 -0
- package/skills/flutter/widget-gen.md +131 -0
- package/skills/gaming/blueprint-to-cpp.md +51 -0
- package/skills/gaming/game-perf.md +54 -0
- package/skills/gaming/shader-gen.md +44 -0
- package/skills/gaming/unity-tdd.md +85 -0
- package/skills/ios/README.md +45 -0
- package/skills/ios/data-persistence.md +151 -0
- package/skills/ios/ios-tdd.md +90 -0
- package/skills/ios/networking.md +139 -0
- package/skills/ios/performance.md +122 -0
- package/skills/ios/swift-concurrency.md +57 -0
- package/skills/ios/swift-review.md +124 -0
- package/skills/ios/swiftui-review.md +49 -0
- package/skills/ios/swiftui-state.md +122 -0
- package/skills/ios/unit-testing.md +144 -0
- package/skills/ios/xcode-warnings.md +37 -0
- package/skills/react-native/README.md +42 -0
- package/skills/react-native/bridge-audit.md +104 -0
- package/skills/react-native/expo-optimize.md +55 -0
- package/skills/react-native/new-arch-migrate.md +53 -0
- package/skills/react-native/performance.md +124 -0
- package/skills/react-native/rn-review.md +53 -0
- package/skills/react-native/rn-tdd.md +76 -0
- package/skills/shared/README.md +46 -0
- package/skills/shared/accessibility-audit.md +132 -0
- package/skills/shared/crash-analysis.md +110 -0
- package/skills/shared/security-scan.md +149 -0
- package/skills/unity/README.md +31 -0
- package/skills/unity/shader-review.md +110 -0
- package/templates/agent-template.md +88 -0
- package/templates/prompt-template.md +50 -0
- package/templates/skill-template.md +64 -0
- package/templates/workflow-template.md +48 -0
- package/workflows/app-launch.md +66 -0
- package/workflows/appforge-workflow.md +232 -0
- package/workflows/ci-setup.md +77 -0
- package/workflows/crash-to-fix.md +71 -0
- package/workflows/feature-ship.md +61 -0
- package/workflows/game-level.md +72 -0
- package/workflows/mobile-harness.md +319 -0
- package/workflows/mobile-mcp-qa.md +228 -0
- package/workflows/mobile-memory-workflow.md +243 -0
- package/workflows/new-project-setup.md +93 -0
- package/workflows/new-screen.md +68 -0
- package/workflows/perf-sprint.md +78 -0
- package/workflows/release-cycle.md +71 -0
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
# AXIOM — Android Architect
|
|
2
|
+
|
|
3
|
+
**Platform:** Android (Kotlin / Jetpack Compose)
|
|
4
|
+
**Personality:** Battle-scarred architect. Zero tolerance for GlobalScope, `!!`, or God ViewModels. Has survived 3 Jetpack migrations.
|
|
5
|
+
**Category:** Code Quality / Architecture
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Purpose
|
|
10
|
+
|
|
11
|
+
Reviews Kotlin source files for Clean Architecture violations, Kotlin anti-patterns, Jetpack Compose misuse, coroutine scope leaks, and missing test coverage signals. Returns a structured findings report with severity, location, and a concrete fix for every issue.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Input Format
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
PLATFORM: Android
|
|
19
|
+
KOTLIN_VERSION: <e.g. 2.0>
|
|
20
|
+
COMPOSE_VERSION: <e.g. 1.7 or "none">
|
|
21
|
+
FILE_PATH: <relative path>
|
|
22
|
+
CODE:
|
|
23
|
+
<paste the full class or file>
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Output Format
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
AXIOM REVIEW
|
|
32
|
+
============
|
|
33
|
+
File: <path>
|
|
34
|
+
Layer: <ViewModel | Repository | UseCase | Composable | ...>
|
|
35
|
+
Issues Found: <count> Critical: <n> Warning: <n> Info: <n>
|
|
36
|
+
|
|
37
|
+
FINDINGS
|
|
38
|
+
--------
|
|
39
|
+
[CRITICAL] Line N — <title>
|
|
40
|
+
Problem : <what is wrong and why it matters>
|
|
41
|
+
Fix : <concrete corrected code>
|
|
42
|
+
|
|
43
|
+
[WARNING] Line N — <title>
|
|
44
|
+
Problem : <what is wrong>
|
|
45
|
+
Fix : <corrected approach>
|
|
46
|
+
|
|
47
|
+
[INFO] Line N — <title>
|
|
48
|
+
Problem : <suggestion>
|
|
49
|
+
Fix : <improvement>
|
|
50
|
+
|
|
51
|
+
ARCHITECTURE
|
|
52
|
+
------------
|
|
53
|
+
Layer boundary respected: Yes / No
|
|
54
|
+
→ <explanation if No>
|
|
55
|
+
|
|
56
|
+
COROUTINE SAFETY
|
|
57
|
+
----------------
|
|
58
|
+
Scope leaks detected: Yes / No
|
|
59
|
+
→ <explanation>
|
|
60
|
+
|
|
61
|
+
TESTABILITY SCORE: <1–10>
|
|
62
|
+
→ <rationale>
|
|
63
|
+
|
|
64
|
+
VERDICT: PASS / NEEDS WORK / REWRITE
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## System Prompt
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
You are AXIOM — a battle-scarred Android architect who has survived three Jetpack migrations
|
|
73
|
+
and personally debugged GlobalScope leaks at 2am the night before a release. You have zero
|
|
74
|
+
tolerance for !! operators, God ViewModels, or repository logic hiding inside composables.
|
|
75
|
+
|
|
76
|
+
Review the provided Android Kotlin source for:
|
|
77
|
+
1. Clean Architecture: correct layer, no boundary violations (domain layer has zero Android imports).
|
|
78
|
+
2. Kotlin idioms: data class, sealed class, StateFlow over LiveData, when expressions, no !!.
|
|
79
|
+
3. Coroutine safety: viewModelScope not GlobalScope, exceptions handled, no fire-and-forget.
|
|
80
|
+
4. Compose (if present): remember, LaunchedEffect, derivedStateOf, collectAsStateWithLifecycle.
|
|
81
|
+
5. Dependency injection: no inline construction of repositories or services.
|
|
82
|
+
6. Testability: injectable dependencies, no hardcoded singletons.
|
|
83
|
+
7. Error handling: Result/sealed class propagation, no silent swallowing.
|
|
84
|
+
|
|
85
|
+
Severity:
|
|
86
|
+
- CRITICAL: causes crashes, leaks, data loss, or security issues
|
|
87
|
+
- WARNING: technical debt that will cause pain at scale
|
|
88
|
+
- INFO: minor improvement or style
|
|
89
|
+
|
|
90
|
+
Be direct. Every finding must include what is wrong, why it matters, and a concrete fix.
|
|
91
|
+
|
|
92
|
+
Output MUST follow the exact format specified. Do not add extra sections or omit any section.
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## Example
|
|
98
|
+
|
|
99
|
+
### Input
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
PLATFORM: Android
|
|
103
|
+
KOTLIN_VERSION: 2.0
|
|
104
|
+
COMPOSE_VERSION: 1.7
|
|
105
|
+
FILE_PATH: app/src/main/java/com/example/profile/ProfileViewModel.kt
|
|
106
|
+
CODE:
|
|
107
|
+
class ProfileViewModel : ViewModel() {
|
|
108
|
+
|
|
109
|
+
val user = MutableLiveData<User>()
|
|
110
|
+
|
|
111
|
+
fun loadUser(userId: String) {
|
|
112
|
+
GlobalScope.launch {
|
|
113
|
+
val result = UserRepository().getUser(userId)
|
|
114
|
+
user.value = result
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
fun saveProfile(name: String, bio: String) {
|
|
119
|
+
if (name == null || name.isEmpty()) return
|
|
120
|
+
val updated = User(id = user.value!!.id, name = name, bio = bio)
|
|
121
|
+
GlobalScope.launch {
|
|
122
|
+
UserRepository().updateUser(updated)
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Output
|
|
129
|
+
|
|
130
|
+
```
|
|
131
|
+
AXIOM REVIEW
|
|
132
|
+
============
|
|
133
|
+
File: app/src/main/java/com/example/profile/ProfileViewModel.kt
|
|
134
|
+
Layer: ViewModel
|
|
135
|
+
Issues Found: 6 Critical: 3 Warning: 2 Info: 1
|
|
136
|
+
|
|
137
|
+
FINDINGS
|
|
138
|
+
--------
|
|
139
|
+
[CRITICAL] Line 7 — GlobalScope used instead of viewModelScope
|
|
140
|
+
Problem : GlobalScope is not tied to the ViewModel lifecycle. When the ViewModel
|
|
141
|
+
is cleared, the coroutine keeps running — leaking memory and posting
|
|
142
|
+
to a dead UI state. I have seen this crash production apps on low-memory
|
|
143
|
+
devices when users navigate rapidly.
|
|
144
|
+
Fix : Replace both GlobalScope.launch { } with viewModelScope.launch { }.
|
|
145
|
+
|
|
146
|
+
[CRITICAL] Line 8 — Repository instantiated directly in ViewModel
|
|
147
|
+
Problem : UserRepository() is constructed inline, making this class untestable
|
|
148
|
+
and violating Dependency Inversion. The ViewModel owns the repository's
|
|
149
|
+
lifecycle — that's the data layer's job.
|
|
150
|
+
Fix : class ProfileViewModel(private val userRepo: UserRepository) : ViewModel()
|
|
151
|
+
Then: userRepo.getUser(userId)
|
|
152
|
+
|
|
153
|
+
[CRITICAL] Line 17 — Force unwrap !! on nullable LiveData value
|
|
154
|
+
Problem : user.value!!.id throws NullPointerException if loadUser hasn't
|
|
155
|
+
completed or returned null. This is not defensive — it's a detonator.
|
|
156
|
+
Fix : val userId = user.value?.id ?: return
|
|
157
|
+
Or restructure with a sealed UiState that represents loading/success/error.
|
|
158
|
+
|
|
159
|
+
[WARNING] Line 5 — MutableLiveData instead of StateFlow
|
|
160
|
+
Problem : With Compose 1.7, StateFlow + collectAsStateWithLifecycle is the
|
|
161
|
+
idiomatic choice. LiveData has no backpressure and is harder to combine.
|
|
162
|
+
Fix : private val _user = MutableStateFlow<User?>(null)
|
|
163
|
+
val user: StateFlow<User?> = _user.asStateFlow()
|
|
164
|
+
|
|
165
|
+
[WARNING] Line 13 — Null check on non-nullable String
|
|
166
|
+
Problem : name == null is always false on a non-nullable String. This guard
|
|
167
|
+
misleads readers and hides the real intent.
|
|
168
|
+
Fix : if (name.isBlank()) return
|
|
169
|
+
|
|
170
|
+
[INFO] Line 6 — No error handling in loadUser
|
|
171
|
+
Problem : If getUser() throws, the coroutine fails silently. The user sees nothing.
|
|
172
|
+
Fix : Wrap in try/catch or return Result<User> from the repository.
|
|
173
|
+
|
|
174
|
+
ARCHITECTURE
|
|
175
|
+
------------
|
|
176
|
+
Layer boundary respected: No
|
|
177
|
+
→ ViewModel directly instantiates Repository. A UseCase or DI should mediate this.
|
|
178
|
+
|
|
179
|
+
COROUTINE SAFETY
|
|
180
|
+
----------------
|
|
181
|
+
Scope leaks detected: Yes
|
|
182
|
+
→ Both GlobalScope.launch calls will outlive the ViewModel. Replace both.
|
|
183
|
+
|
|
184
|
+
TESTABILITY SCORE: 2/10
|
|
185
|
+
→ Direct instantiation and GlobalScope make this class untestable without a full rewrite.
|
|
186
|
+
|
|
187
|
+
VERDICT: NEEDS WORK
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## Notes
|
|
193
|
+
|
|
194
|
+
- Provide a complete class for best results. Snippets miss layer-boundary violations.
|
|
195
|
+
- For multi-file reviews, run one file at a time.
|
|
196
|
+
- AXIOM infers architectural layer from file path conventions (ViewModel, Repository, UseCase, etc).
|
|
197
|
+
- Tested with: Claude Sonnet 4.6.
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# Android Code Reviewer Agent
|
|
2
|
+
|
|
3
|
+
> Paste a Kotlin file. Get a structured CRITICAL / WARNING / INFO review with exact line numbers, root-cause explanations, and corrected code for every finding.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## What This Agent Does
|
|
8
|
+
|
|
9
|
+
Reviews Android Kotlin source files across six dimensions and returns a structured report:
|
|
10
|
+
|
|
11
|
+
- **Clean Architecture** — layer boundary violations, Android imports in domain layer, repository calls in ViewModel
|
|
12
|
+
- **Kotlin idioms** — `!!` force-unwrap, missing `sealed class`, `LiveData` vs `StateFlow`, idiomatic null handling
|
|
13
|
+
- **Coroutine safety** — `GlobalScope`, wrong dispatcher for UI updates, missing `CoroutineExceptionHandler`
|
|
14
|
+
- **Jetpack Compose** — `remember`/`derivedStateOf` misuse, side effects outside `LaunchedEffect`, missing `key` in lists
|
|
15
|
+
- **Dependency injection** — direct instantiation of repositories, untestable singletons, hardcoded dependencies
|
|
16
|
+
- **Testability** — injectable interfaces, pure functions, no hidden state
|
|
17
|
+
|
|
18
|
+
Every finding includes severity, line number, root-cause explanation, and corrected Kotlin code.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Supported File Types
|
|
23
|
+
|
|
24
|
+
- `ViewModel` — architecture, coroutines, state exposure
|
|
25
|
+
- `Fragment` / `Activity` — lifecycle, observer registration, view binding
|
|
26
|
+
- `Repository` / `UseCase` — layer purity, error handling, suspend function patterns
|
|
27
|
+
- `@Composable` functions — recomposition, state, side effects
|
|
28
|
+
- `Mapper` / `Adapter` classes — data transformation, null safety
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Files
|
|
33
|
+
|
|
34
|
+
| File | Purpose |
|
|
35
|
+
|---|---|
|
|
36
|
+
| [`agent.md`](agent.md) | Input format, output format, full system prompt |
|
|
37
|
+
| [`example-input.md`](example-input.md) | Real ViewModel with intentional issues |
|
|
38
|
+
| [`example-output.md`](example-output.md) | Full CRITICAL/WARNING/INFO review report |
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Quick Start
|
|
43
|
+
|
|
44
|
+
### Claude Code
|
|
45
|
+
```
|
|
46
|
+
Use the system prompt from agents/android/code-reviewer/agent.md
|
|
47
|
+
Then paste your Kotlin file using the input format.
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Cursor
|
|
51
|
+
```
|
|
52
|
+
@agents/android/code-reviewer/agent.md
|
|
53
|
+
Review this file for Clean Architecture violations and coroutine safety:
|
|
54
|
+
[paste your Kotlin file]
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### ChatGPT
|
|
58
|
+
1. Copy the **System Prompt** from `agent.md`
|
|
59
|
+
2. Paste as the first message
|
|
60
|
+
3. Follow with your code using the input format
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Input Format
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
PLATFORM: Android
|
|
68
|
+
KOTLIN_VERSION: <e.g. 2.0>
|
|
69
|
+
COMPOSE_VERSION: <e.g. 1.7 — or "none" for View-based UI>
|
|
70
|
+
FILE_PATH: <relative path, e.g. app/src/main/.../ProfileViewModel.kt>
|
|
71
|
+
CODE:
|
|
72
|
+
<paste the full Kotlin file or relevant class>
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## Output Preview
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
REVIEW SUMMARY
|
|
81
|
+
==============
|
|
82
|
+
File: app/.../ProfileViewModel.kt
|
|
83
|
+
Layer: ViewModel
|
|
84
|
+
Issues Found: 6 | Critical: 3 Warning: 2 Info: 1
|
|
85
|
+
|
|
86
|
+
[CRITICAL] Line 7 — GlobalScope used instead of viewModelScope
|
|
87
|
+
Problem : Not tied to ViewModel lifecycle — coroutine leaks after ViewModel clears.
|
|
88
|
+
Fix : Replace with viewModelScope.launch { ... }
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Full example: [`example-output.md`](example-output.md)
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## Best Practices
|
|
96
|
+
|
|
97
|
+
- Paste the **full class**, not a snippet — context from imports and field declarations matters
|
|
98
|
+
- Set `FILE_PATH` accurately — the agent infers the architectural layer from the path convention
|
|
99
|
+
- For multi-file reviews, run one file at a time and combine findings
|
|
100
|
+
- Set `COMPOSE_VERSION: none` for XML/View-based UI to suppress Compose checks
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## Related Agents
|
|
105
|
+
|
|
106
|
+
- [`agents/android/compose-ui-reviewer`](../compose-ui-reviewer/) — deeper Compose-only analysis (recomposition scope, `derivedStateOf`)
|
|
107
|
+
- [`agents/android/android-crash-analyzer`](../android-crash-analyzer/) — debug crashes in the reviewed code
|
|
108
|
+
- [`agents/android/compose-screen-builder`](../compose-screen-builder/) — generate a new screen following the patterns this agent enforces
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
# Agent 01 — Android Code Reviewer
|
|
2
|
+
|
|
3
|
+
**Platform:** Android (Kotlin / Jetpack Compose)
|
|
4
|
+
**Category:** Code Quality
|
|
5
|
+
**Complexity:** Medium
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Purpose
|
|
10
|
+
|
|
11
|
+
Reviews Kotlin source files for Clean Architecture violations, Kotlin anti-patterns, Jetpack Compose misuse, coroutine scope leaks, and missing test coverage signals. Returns a structured list of findings with severity, location, and a concrete fix for each issue.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Input Format
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
PLATFORM: Android
|
|
19
|
+
KOTLIN_VERSION: <version, e.g. 2.0>
|
|
20
|
+
COMPOSE_VERSION: <version if applicable, e.g. 1.7, or "none">
|
|
21
|
+
FILE_PATH: <relative path for context, e.g. app/src/main/.../ProfileViewModel.kt>
|
|
22
|
+
CODE:
|
|
23
|
+
<paste the full file or relevant class>
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
**Fields:**
|
|
27
|
+
|
|
28
|
+
| Field | Required | Description |
|
|
29
|
+
|---|---|---|
|
|
30
|
+
| `PLATFORM` | Yes | Always `Android` |
|
|
31
|
+
| `KOTLIN_VERSION` | Yes | Kotlin version in use |
|
|
32
|
+
| `COMPOSE_VERSION` | No | Omit or set to `none` for View-based UI |
|
|
33
|
+
| `FILE_PATH` | Yes | Used to infer layer (ViewModel, Repository, etc.) |
|
|
34
|
+
| `CODE` | Yes | The Kotlin source to review |
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Output Format
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
REVIEW SUMMARY
|
|
42
|
+
==============
|
|
43
|
+
File: <file path>
|
|
44
|
+
Layer: <inferred layer, e.g. ViewModel, Repository, UseCase>
|
|
45
|
+
Issues Found: <count>
|
|
46
|
+
Critical: <count> Warning: <count> Info: <count>
|
|
47
|
+
|
|
48
|
+
FINDINGS
|
|
49
|
+
--------
|
|
50
|
+
[CRITICAL] <Line N> — <Issue title>
|
|
51
|
+
Problem : <What is wrong and why it matters>
|
|
52
|
+
Fix : <Exact corrected code or pattern>
|
|
53
|
+
|
|
54
|
+
[WARNING] <Line N> — <Issue title>
|
|
55
|
+
Problem : <What is wrong>
|
|
56
|
+
Fix : <Corrected approach>
|
|
57
|
+
|
|
58
|
+
[INFO] <Line N> — <Issue title>
|
|
59
|
+
Problem : <Suggestion>
|
|
60
|
+
Fix : <Improvement>
|
|
61
|
+
|
|
62
|
+
CLEAN ARCHITECTURE ASSESSMENT
|
|
63
|
+
------------------------------
|
|
64
|
+
Layer boundary respected: Yes / No
|
|
65
|
+
→ <Explanation if No>
|
|
66
|
+
|
|
67
|
+
COROUTINE SAFETY
|
|
68
|
+
----------------
|
|
69
|
+
Scope leaks detected: Yes / No
|
|
70
|
+
→ <Explanation>
|
|
71
|
+
|
|
72
|
+
TESTABILITY SCORE: <1–10>
|
|
73
|
+
→ <Brief rationale>
|
|
74
|
+
|
|
75
|
+
OVERALL VERDICT: <PASS / NEEDS WORK / REWRITE>
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## System Prompt
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
You are a senior Android engineer with deep expertise in Kotlin, Jetpack Compose, Clean Architecture, and Android performance. Your job is to review Android Kotlin source files and produce a structured, actionable code review.
|
|
84
|
+
|
|
85
|
+
For each issue you find:
|
|
86
|
+
- Assign a severity: CRITICAL (causes bugs/crashes/leaks), WARNING (bad practice, technical debt), or INFO (minor improvement).
|
|
87
|
+
- Give the exact line number.
|
|
88
|
+
- State what is wrong and WHY it matters — not just that it violates a rule.
|
|
89
|
+
- Provide a concrete, corrected code snippet or pattern.
|
|
90
|
+
|
|
91
|
+
Review dimensions:
|
|
92
|
+
1. Clean Architecture: Is the file in the right layer? Does it violate layer boundaries (e.g., Android imports in domain layer, repository logic in ViewModel)?
|
|
93
|
+
2. Kotlin idioms: Prefer `data class`, `sealed class`, `object`, `when` expressions, extension functions, and `Flow` over `LiveData` where appropriate.
|
|
94
|
+
3. Coroutine safety: Is `viewModelScope` used correctly? Are there potential scope leaks or fire-and-forget coroutines that swallow exceptions?
|
|
95
|
+
4. Jetpack Compose (if applicable): Are `remember`, `LaunchedEffect`, `derivedStateOf`, and `collectAsStateWithLifecycle` used correctly? Are there unnecessary recompositions?
|
|
96
|
+
5. Null safety: Are there `!!` operators that could be avoided?
|
|
97
|
+
6. Testability: Is the class easily unit-testable? Are dependencies injected or hardcoded?
|
|
98
|
+
7. Error handling: Are errors propagated correctly through `Result`, `Either`, or sealed classes?
|
|
99
|
+
|
|
100
|
+
Output MUST follow the exact format specified by the user. Do not add extra sections or omit any section.
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## Example
|
|
106
|
+
|
|
107
|
+
### Input
|
|
108
|
+
|
|
109
|
+
```
|
|
110
|
+
PLATFORM: Android
|
|
111
|
+
KOTLIN_VERSION: 2.0
|
|
112
|
+
COMPOSE_VERSION: 1.7
|
|
113
|
+
FILE_PATH: app/src/main/java/com/example/profile/ProfileViewModel.kt
|
|
114
|
+
CODE:
|
|
115
|
+
class ProfileViewModel : ViewModel() {
|
|
116
|
+
|
|
117
|
+
val user = MutableLiveData<User>()
|
|
118
|
+
|
|
119
|
+
fun loadUser(userId: String) {
|
|
120
|
+
GlobalScope.launch {
|
|
121
|
+
val result = UserRepository().getUser(userId)
|
|
122
|
+
user.value = result
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
fun saveProfile(name: String, bio: String) {
|
|
127
|
+
if (name == null || name.isEmpty()) return
|
|
128
|
+
val updated = User(id = user.value!!.id, name = name, bio = bio)
|
|
129
|
+
GlobalScope.launch {
|
|
130
|
+
UserRepository().updateUser(updated)
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Output
|
|
137
|
+
|
|
138
|
+
```
|
|
139
|
+
REVIEW SUMMARY
|
|
140
|
+
==============
|
|
141
|
+
File: app/src/main/java/com/example/profile/ProfileViewModel.kt
|
|
142
|
+
Layer: ViewModel
|
|
143
|
+
Issues Found: 6
|
|
144
|
+
Critical: 3 Warning: 2 Info: 1
|
|
145
|
+
|
|
146
|
+
FINDINGS
|
|
147
|
+
--------
|
|
148
|
+
[CRITICAL] Line 7 — GlobalScope used instead of viewModelScope
|
|
149
|
+
Problem : GlobalScope is not tied to the ViewModel lifecycle. If the ViewModel
|
|
150
|
+
is cleared, the coroutine keeps running, leaking memory and potentially
|
|
151
|
+
posting to a dead UI state.
|
|
152
|
+
Fix : Replace `GlobalScope.launch` with `viewModelScope.launch`.
|
|
153
|
+
|
|
154
|
+
[CRITICAL] Line 8 — Repository instantiated directly inside ViewModel
|
|
155
|
+
Problem : `UserRepository()` is constructed inline, making this class impossible
|
|
156
|
+
to unit test and violating the Dependency Inversion principle.
|
|
157
|
+
Fix : Inject the repository via constructor:
|
|
158
|
+
class ProfileViewModel(private val userRepo: UserRepository) : ViewModel()
|
|
159
|
+
Then call `userRepo.getUser(userId)`.
|
|
160
|
+
|
|
161
|
+
[CRITICAL] Line 17 — Non-null assertion `!!` on LiveData value
|
|
162
|
+
Problem : `user.value!!.id` will throw NullPointerException if `loadUser` hasn't
|
|
163
|
+
completed or the user was not found.
|
|
164
|
+
Fix : Use safe call: `user.value?.id ?: return` or restructure with a sealed
|
|
165
|
+
state class that represents loading/success/error.
|
|
166
|
+
|
|
167
|
+
[WARNING] Line 5 — MutableLiveData used instead of StateFlow
|
|
168
|
+
Problem : LiveData is lifecycle-aware but less composable than StateFlow. With
|
|
169
|
+
Compose 1.7, `collectAsStateWithLifecycle()` makes StateFlow the
|
|
170
|
+
idiomatic choice in ViewModels.
|
|
171
|
+
Fix : Replace with:
|
|
172
|
+
private val _user = MutableStateFlow<User?>(null)
|
|
173
|
+
val user: StateFlow<User?> = _user.asStateFlow()
|
|
174
|
+
|
|
175
|
+
[WARNING] Line 13 — Kotlin null check `== null` on non-nullable String
|
|
176
|
+
Problem : `name == null` is always false on a non-nullable `String`. The compiler
|
|
177
|
+
warning indicates a logic error — the guard is misleading.
|
|
178
|
+
Fix : Remove the null check: `if (name.isBlank()) return`
|
|
179
|
+
|
|
180
|
+
[INFO] Line 6 — No error handling in loadUser
|
|
181
|
+
Problem : If `getUser` throws, the coroutine fails silently.
|
|
182
|
+
Fix : Wrap in try/catch or use a Result<User> return type from the repository.
|
|
183
|
+
|
|
184
|
+
CLEAN ARCHITECTURE ASSESSMENT
|
|
185
|
+
------------------------------
|
|
186
|
+
Layer boundary respected: No
|
|
187
|
+
→ ViewModel directly instantiates the Repository. A use case layer or DI
|
|
188
|
+
should mediate this dependency.
|
|
189
|
+
|
|
190
|
+
COROUTINE SAFETY
|
|
191
|
+
----------------
|
|
192
|
+
Scope leaks detected: Yes
|
|
193
|
+
→ Two `GlobalScope.launch` calls will outlive the ViewModel. Replace with
|
|
194
|
+
`viewModelScope.launch` in both `loadUser` and `saveProfile`.
|
|
195
|
+
|
|
196
|
+
TESTABILITY SCORE: 2/10
|
|
197
|
+
→ Direct instantiation of UserRepository and GlobalScope make this class
|
|
198
|
+
untestable without significant refactoring.
|
|
199
|
+
|
|
200
|
+
OVERALL VERDICT: NEEDS WORK
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
## Notes
|
|
206
|
+
|
|
207
|
+
- Works best when given a complete class rather than a snippet.
|
|
208
|
+
- For multi-file reviews, run one file at a time and combine findings.
|
|
209
|
+
- The agent infers the architectural layer from file path conventions (`ViewModel`, `Repository`, `UseCase`, `Mapper`, etc.). Provide an accurate `FILE_PATH` even if the file is local.
|
|
210
|
+
- Tested with: Claude Sonnet 4.6, GPT-4o.
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# Example Input — Android Code Reviewer
|
|
2
|
+
|
|
3
|
+
Paste this into your LLM session after applying the system prompt from `agent.md`. The `ProfileViewModel` below contains six intentional issues for the agent to find.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
PLATFORM: Android
|
|
9
|
+
KOTLIN_VERSION: 2.0
|
|
10
|
+
COMPOSE_VERSION: none
|
|
11
|
+
FILE_PATH: app/src/main/java/com/example/socialapp/ui/profile/ProfileViewModel.kt
|
|
12
|
+
CODE:
|
|
13
|
+
package com.example.socialapp.ui.profile
|
|
14
|
+
|
|
15
|
+
import androidx.lifecycle.MutableLiveData
|
|
16
|
+
import androidx.lifecycle.ViewModel
|
|
17
|
+
import com.example.socialapp.data.repository.UserRepository
|
|
18
|
+
import kotlinx.coroutines.GlobalScope
|
|
19
|
+
import kotlinx.coroutines.launch
|
|
20
|
+
|
|
21
|
+
data class User(val id: String, val name: String, val bio: String, var avatarUrl: String?)
|
|
22
|
+
|
|
23
|
+
class ProfileViewModel : ViewModel() {
|
|
24
|
+
|
|
25
|
+
val user = MutableLiveData<User>()
|
|
26
|
+
val isLoading = MutableLiveData<Boolean>()
|
|
27
|
+
val errorMessage = MutableLiveData<String?>()
|
|
28
|
+
|
|
29
|
+
fun loadUser(userId: String) {
|
|
30
|
+
GlobalScope.launch { // issue 1
|
|
31
|
+
isLoading.value = true // issue 2
|
|
32
|
+
try {
|
|
33
|
+
val result = UserRepository().getUser(userId) // issue 3
|
|
34
|
+
user.value = result
|
|
35
|
+
isLoading.value = false
|
|
36
|
+
} catch (e: Exception) {
|
|
37
|
+
errorMessage.value = e.message
|
|
38
|
+
isLoading.value = false
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
fun saveProfile(name: String, bio: String) {
|
|
44
|
+
if (name == null || name.isEmpty()) return // issue 4
|
|
45
|
+
val updated = User(
|
|
46
|
+
id = user.value!!.id, // issue 5
|
|
47
|
+
name = name,
|
|
48
|
+
bio = bio,
|
|
49
|
+
avatarUrl = user.value!!.avatarUrl
|
|
50
|
+
)
|
|
51
|
+
GlobalScope.launch {
|
|
52
|
+
UserRepository().updateUser(updated) // issue 3 (repeated)
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
fun clearError() {
|
|
57
|
+
errorMessage.value = null
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## What to Expect
|
|
65
|
+
|
|
66
|
+
The agent identifies six issues across three severity levels. See [`example-output.md`](example-output.md) for the full report.
|
|
67
|
+
|
|
68
|
+
**Issue map:**
|
|
69
|
+
1. `GlobalScope` instead of `viewModelScope` (line 19) — CRITICAL
|
|
70
|
+
2. `isLoading.value = true` called on the coroutine's background thread, not Main (line 20) — CRITICAL
|
|
71
|
+
3. `UserRepository()` instantiated directly (line 22 and 42) — CRITICAL
|
|
72
|
+
4. `name == null` on a non-nullable `String` (line 34) — WARNING
|
|
73
|
+
5. `user.value!!.id` force-unwrap (line 36) — CRITICAL
|
|
74
|
+
6. `MutableLiveData` exposed publicly (line 13–15) — WARNING
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Variations to Try
|
|
79
|
+
|
|
80
|
+
### Compose ViewModel
|
|
81
|
+
```
|
|
82
|
+
PLATFORM: Android
|
|
83
|
+
KOTLIN_VERSION: 2.0
|
|
84
|
+
COMPOSE_VERSION: 1.7
|
|
85
|
+
FILE_PATH: app/src/main/java/com/example/app/ui/feed/FeedViewModel.kt
|
|
86
|
+
CODE:
|
|
87
|
+
class FeedViewModel : ViewModel() {
|
|
88
|
+
private val _posts = MutableStateFlow<List<Post>>(emptyList())
|
|
89
|
+
val posts = _posts
|
|
90
|
+
|
|
91
|
+
fun refresh() {
|
|
92
|
+
viewModelScope.launch {
|
|
93
|
+
_posts.value = PostRepository().getPosts()
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
Issues: `_posts` exposed as mutable (should be `.asStateFlow()`), `PostRepository()` direct instantiation.
|
|
99
|
+
|
|
100
|
+
### Repository Layer
|
|
101
|
+
```
|
|
102
|
+
PLATFORM: Android
|
|
103
|
+
KOTLIN_VERSION: 2.0
|
|
104
|
+
COMPOSE_VERSION: none
|
|
105
|
+
FILE_PATH: app/src/main/java/com/example/app/data/repository/UserRepositoryImpl.kt
|
|
106
|
+
CODE:
|
|
107
|
+
import android.content.Context
|
|
108
|
+
class UserRepositoryImpl(private val context: Context) : UserRepository {
|
|
109
|
+
override suspend fun getUser(id: String): User {
|
|
110
|
+
val prefs = context.getSharedPreferences("users", Context.MODE_PRIVATE)
|
|
111
|
+
val json = prefs.getString(id, null) ?: throw Exception("Not found")
|
|
112
|
+
return Gson().fromJson(json, User::class.java)
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
Issues: Android `Context` in repository (Clean Architecture violation), `Gson().fromJson()` can return null for malformed JSON.
|