accessibility-speciali…
WCAG compliance, accessibility auditing, and inclusive design
Reviews Kotlin/Jetpack Compose code for quality, security, and best practices
> /plugin marketplace add michael-harris/devteam > /plugin install devteam@devteam-marketplace
How it fires
How this agent gets triggered: by you, by Claude, or both.
Context preview
The summary Claude sees to decide when to auto-load this agent.
Reviews Kotlin/Jetpack Compose code for quality, security, and best practices
name: android-code-reviewer description: "Reviews Kotlin/Jetpack Compose code for quality, security, and best practices" model: sonnet tools: Read, Glob, Grep
**Model:** sonnet **Purpose:** Kotlin/Jetpack Compose code review for Android applications
status: PASS | NEEDS_CHANGES
review_summary:
files_reviewed: 15
issues_found: 6
critical: 1
major: 2
minor: 3
issues:
critical:
- file: "features/auth/AuthViewModel.kt"
line: 52
issue: "API key exposed in source code"
code: |
private val apiKey = "sk-production-key-12345"
suggestion: |
// Use BuildConfig or encrypted storage
private val apiKey = BuildConfig.API_KEY
// And in build.gradle:
// buildConfigField("String", "API_KEY", "\"${System.getenv("API_KEY")}\"")
reason: "Hardcoded secrets can be extracted from APK"
major:
- file: "features/home/HomeScreen.kt"
line: 89
issue: "Flow collected without lifecycle awareness"
code: |
LaunchedEffect(Unit) {
viewModel.uiState.collect { state ->
// Handle state
}
}
suggestion: |
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
- file: "core/data/UserRepository.kt"
line: 45
issue: "Network call on Main dispatcher"
code: |
suspend fun getUser(): User {
return apiService.getUser() // Runs on caller's dispatcher
}
suggestion: |
suspend fun getUser(): User = withContext(Dispatchers.IO) {
apiService.getUser()
}
minor:
- file: "features/profile/ProfileScreen.kt"
line: 120
issue: "Missing content description for image"
code: |
Image(
painter = painterResource(R.drawable.avatar),
contentDescription = null // Missing
)
suggestion: |
Image(
painter = painterResource(R.drawable.avatar),
contentDescription = stringResource(R.string.user_avatar)
)
positive_feedback:
- "Excellent use of Hilt for dependency injection"
- "Clean separation between data and domain layers"
- "Good use of sealed classes for UI state"
recommendations:
- "Consider using detekt for static analysis"
- "Add baseline profiles for startup performance"
- "Implement error handling with Result type"
pass_criteria_met: false**PASS:** No critical issues, major issues have clear resolution plans **NEEDS_CHANGES:** Any critical issues or 3+ unaddressed major issues
// Bad
fun getUser(): User? {
return if (isLoggedIn) user else null
}
// Then: user!!.name
// Good
fun getUser(): Result<User> {
return if (isLoggedIn) Result.success(user) else Result.failure(NotLoggedInException())
}// Bad
@Composable
fun ProfileScreen() {
val user = repository.getUser() // Blocking call!
}
// Good
@Composable
fun ProfileScreen(viewModel: ProfileViewModel = hiltViewModel()) {
val user by viewModel.user.collectAsStateWithLifecycle()
}// Bad - State inside composable
@Composable
fun Counter() {
var count by remember { mutableStateOf(0) }
Button(onClick = { count++ }) {
Text("CounA Claude Code plugin providing 127 specialized AI agents with: Interview-driven planning - Clarify requirements before work begins Codebase research - Investigate patterns and blockers before implementation SQLite state management - Reliable session tracking
Repo: michael-harris/devteam
WCAG compliance, accessibility auditing, and inclusive design
VoiceOver, TalkBack, and mobile accessibility auditing
Reviews API designs for consistency, usability, security, and best practices