// Android PR Code Review skill. Performs a comprehensive code review on the current Git repository's PR or specified code changes. Covers all review dimensions including architecture, Kotlin code quality, Android platform best practices, performance, security, and testability — along with a standardized output format. Can also be used as a standalone reference for Android review standards.
Android PR Code Review skill. Performs a comprehensive code review on the current Git repository's PR or specified code changes. Covers all review dimensions including architecture, Kotlin code quality, Android platform best practices, performance, security, and testability — along with a standardized output format. Can also be used as a standalone reference for Android review standards.
triggers
["/android-code-review","review this MR","do a code review"]
Android Code Review
Usage
/android-code-review # Review diff between current branch and develop
/android-code-review --branch feature/login # Review a specific branch
/android-code-review --base develop # Use a different base branch (default: develop)
/android-code-review --file path/to/File.kt # Review a single file
/android-code-review --focus security # Focus on a specific dimension (security/performance/arch)
/android-code-review --severity major # Only show issues at or above the specified severity
/android-code-review --output ./review.md # Save report to a file
Arguments
Argument
Description
Example
--branch <name>
Specify the branch to review
--branch feature/payment
--base <branch>
Base branch for comparison (default: develop)
--base main
--file <path>
Review a single file
--file app/src/.../LoginViewModel.kt
--focus <dimension>
Focus on a specific review dimension
--focus performance
--severity <level>
Only show issues at or above this level
--severity major
--output <path>
Save the report to a file
--output ./review.md
Execution Steps
Step 1 — Fetch Code Changes
Retrieve the code to review based on the provided arguments:
# Default: current branch vs develop (or --base value if specified)
git log${BASE:-develop}...HEAD --oneline
git diff ${BASE:-develop}...HEAD --stat
git diff ${BASE:-develop}...HEAD
# If --branch is specified
git diff ${BASE:-develop}...<branch-name>
# If --file is specified, read the file directly
Note: this reviews committed changes only. Uncommitted staged/unstaged changes are not included. Use --base to change the base branch (default: develop).
Step 2 — Analyze
Using the dimensions and checklists defined below, analyze each changed file for:
Architecture & design correctness
Kotlin code quality
Android platform best practices
Performance issues
Security vulnerabilities
Testability
Readability & coding standards
For large PRs (> 500 lines), prioritize core business logic files.
String resource check: Scan the diff for any changes to *strings*.xml or res/values/*.xml files. Collect every newly added <string name="..."> entry (diff lines starting with a single + but not+++ diff header lines). Lines starting with - are removals and must be excluded. Record the string key and the file it appears in — this list will be used in the 🌐 New Strings — Weblate Sync Required section of the report.
Step 3 — Generate Review Report
Output the report following the Standard Output Format defined below.
Step 4 — Save Report (Optional)
If --output <path> was specified, use the Write tool to save the full report markdown to that path.
Notes
If git commands are unavailable, prompt the user to paste the code directly
Always deliver feedback in a constructive and respectful tone
Tech Stack Conventions
Language: Kotlin (no new Java files)
Min SDK: API 24 (Android 8.0)
Target SDK: API 36
Architecture: MVVM + Clean Architecture
UI Framework: Jetpack Compose (new screens), View system (legacy screens)
DI: Hilt
Async: Kotlin Coroutines + Flow
Local Storage: Room, DataStore, SQLCipher (encrypted DB)
Image Loading: Coil
Unit Testing: JUnit5 + MockK + Turbine
UI Testing: Compose Testing
Build: Convention plugins (build-logic/convention/), Version Catalogs (gradle/catalogs/)
Review Dimensions & Checklists
ViewModel files: When reviewing *ViewModel.kt files, also apply the conventions in viewmodel-conventions.md.
UseCase files: When reviewing *UseCase.kt files, also apply the conventions in usecase-conventions.md.
Mapper files: When reviewing *Mapper.kt files, also apply the conventions in mapper-conventions.md.
Compose: unnecessary recompositions avoided (remember, derivedStateOf used correctly)
Lists use LazyColumn (never full lists inside ScrollView)
Images loaded with explicit size constraints (prevent OOM)
No database or network calls on the main thread
ViewModel does not cache unnecessarily large datasets in memory
Common Issues:
// ❌ Expensive operation runs on every recomposition@ComposablefunUserList(users: List<User>) {
val sortedUsers = users.sortedBy { it.name }
}
// ✅ Cache with remember, keyed on input@ComposablefunUserList(users: List<User>) {
val sortedUsers = remember(users) { users.sortedBy { it.name } }
}
6. Security
Checklist:
Sensitive data (tokens, passwords) not stored in plaintext SharedPreferences
No sensitive data logged (e.g., Log.d("token", token))
User inputs are validated and sanitized
Sensitive operations require authentication
Database encrypted with SQLCipher
Sensitive fields in entities/mappers encrypted using EncryptData before persistence
No API keys or secrets committed to the repository
Common Issues:
// ❌ Token stored in plaintext
sharedPreferences.edit().putString("token", authToken).apply()
// ✅ Use EncryptedSharedPreferencesval encryptedPrefs = EncryptedSharedPreferences.create(
context, "secure_prefs",
MasterKey.Builder(context).setKeyScheme(MasterKey.KeyScheme.AES256_GCM).build(),
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)
encryptedPrefs.edit().putString("token", authToken).apply()
// ❌ Logging sensitive data
Log.d("Auth", "User token: $token")
// ✅ Debug-only and redactedif (BuildConfig.DEBUG) Log.d("Auth", "Token received successfully")
// ❌ Sensitive field stored unencrypted in Room entity@EntitydataclassBackupEntity(val backupId: String)
// ✅ Encrypt sensitive fields using EncryptData before persistingsuspendoperatorfuninvoke(backup: Backup): BackupEntity? {
return BackupEntity(
encryptedBackupId = encryptData(backup.backupId.toString()) ?: returnnull
)
}
7. Testability
ViewModel tests: When reviewing ViewModel test files (*ViewModelTest.kt), also apply the conventions in viewmodel-test-conventions.md.
UseCase tests: When reviewing UseCase test files (*UseCaseTest.kt), also apply the conventions in usecase-test-conventions.md.
Mapper tests: When reviewing Mapper test files (*MapperTest.kt), also apply the conventions in mapper-test-conventions.md.
Checklist:
ViewModel, UseCase and Repository implementation business logics have corresponding unit tests
Test method naming: Follow the patterns below (see Test Method Naming)
New logic has corresponding tests — no missing tests for new behavior
Compose View has UI tests
ViewModels can be tested without Android framework dependencies
Test coverage meets team requirements (recommended ≥ 80% for core logic)
Test class annotated with @ExtendWith(CoroutineMainDispatcherExtension::class) and @TestInstance(TestInstance.Lifecycle.PER_CLASS)
Flow emissions tested using Turbine (underTest.state.test { ... })
Test Method Naming
Format: Use one of the following patterns for test method names:
`test that <method> <action>` — e.g. `test that init does not call loginToFolderUseCase`()
`test that <method> <action> when <cause>` — e.g. `test that init emits Loaded when login succeeds`()
Common Issues:
// ❌ Test name does not follow "test that" patterns — inconsistent with project convention@Testfun `loading state is shown`() { ... }
// ✅ Use "test that <method> <action>" or "test that <method> <action> when <cause>"@Testfun `test that init emits Loaded when login succeeds`() { ... }
@Testfun `test that init does not call loginToFolderUseCase`() { ... }
8. Code Style & Formatting
Checklist:
Use explicit imports at the top of the file — never inline fully qualified class names in code
No hardcoded strings (should be in shared_strings.xml)
Naming and comments are clear; intent is obvious (no unclear naming or comments)
No leftover debug code or TODOs in production code
Extra or unused code after implementation switch — When the change refactors or replaces an approach, check for leftover files, types, or dependencies that are no longer used and suggest removing or slimming them
Readability, naming conventions, small optimizations
No
Suggestion
🔵
Optional improvement, not required in this PR
No
Standard Output Format
All review reports must strictly follow this format:
# PR Code Review Report## Summary-**Branch**: userid/JiraID-branch → develop
-**Files Changed**: X
-**Review Date**: YYYY-MM-DD HH:mm
-**Overall**: [One-sentence overall assessment]
## 🌐 New Strings — Weblate Sync Required> ⚠️ New string keys were detected in this PR. Please ensure they are added to Weblate before merging.> `string_key_one`, `string_key_two`
[Omit this section entirely if no new strings were detected in the diff.]
## Issue Overview
| Severity | Count |
|----------|-------|
| 🔴 Critical | X |
| 🟠 Major | X |
| 🟡 Minor | X |
| 🔵 Suggestion | X |
---
## Detailed Findings### `path/to/FileName.kt`#### 🔴 [Critical] Issue Title**Location**: Line XX
**Problem**: Clear description of what the issue is and why it's risky.
**Suggestion**:
```kotlin
// ❌ Current code
...
// ✅ Suggested fix
...
```#### 🟡 [Minor] Issue Title**Location**: Line XX
**Problem**: ...
**Suggestion**: ...
---
## Highlights 👍> Good practices worth acknowledging (at least one per review)-`FileName.kt`: ...
## Conclusion> [Approved ✅ / Request Changes 🔄 / Needs Discussion 💬]>
> Brief explanation of the conclusion, and a list of blocking issues that must be fixed before merge (if any).
Review Mindset & Etiquette
Critique the code, not the person — say "this function" not "you wrote"
Explain the why — every issue should include a reason, not just "this is wrong"
Always provide a solution — point out problems and suggest concrete fixes
Acknowledge the good — find at least one thing done well in every review
Distinguish must-fix from nice-to-have — Minor and Suggestion items are not blocking