Audit Android Jetpack Compose repositories for performance, state management, side effects, and composable API quality. Scans source code, scores each category from 0-10, writes a strict markdown report, and summarizes the most important fixes. Use when reviewing a Compose codebase, rating repository quality, inspecting recomposition/state issues, or running a Compose audit.
73
92%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
This skill audits Android Jetpack Compose repositories with a strict, evidence-based report.
Rubric version: v1 — current as of 2026-04-13. Compose track: Kotlin 2.0.20+ / Compose Compiler 1.5.4+ (Strong Skipping Mode default).
It is intentionally focused on four categories:
This skill does not score design or Material 3 compliance in v1. If the audit surfaces likely design-system problems, recommend a follow-up audit with the material-3 skill (reference implementation: https://github.com/hamen/material-3-skill).
Owned and deliberate scope choices — call out the limitation in the report rather than silently producing thin coverage:
material-3 skill.semantics, content descriptions, touch-target sizing) — flag obvious gaps as a note, do not score.expect/actual, target-specific code paths).If the user explicitly asks for any of these, narrow the scope and state it in the report.
Use this skill when the user asks to:
Typical trigger phrases:
Produce both:
COMPOSE-AUDIT-REPORT.mdreferences/canonical-sources.md. The report template requires a References: line per finding.0-3 scores for repeated or systemic problems, not isolated mistakes.9-10 unless the repo is consistently strong across the category.Identify the target path:
[repo path or module path]), use it.Before mapping modules, confirm Compose is actually present (fast-fail):
androidx.compose in any build.gradle* or libs.versions.tomlsetContent { or @Composable under src/If neither shows up, stop and report that the target is out of scope. Do not run a full module map first.
If Compose is present only in samples/, demos/, or test sources (no production usage), narrow the scope to those directories, set confidence to Low, and state in the report that the audit is over sample code rather than production paths. Do not score production-quality categories against demo code.
Before scoring, identify:
Look for:
@Composable functionsViewModel usageremember, rememberSaveable, mutableStateOfcollectAsStateWithLifecycle, collectAsStateLaunchedEffect, DisposableEffect, SideEffect, rememberUpdatedState, produceStateLazyColumn, LazyRow, items, itemsIndexedIf the repo is large, audit by category or by module. If subagents are available, parallelize category scans by spawning Explore-type subagents (no write tools) and merge the findings.
Do not ask the user to edit build.gradle or run commands themselves. The skill runs the build with a bundled Gradle init script that injects reportsDestination / metricsDestination into every Compose module without modifying any file in the target repo. Before scoring, attempt this:
Locate the init script shipped with the skill: scripts/compose-reports.init.gradle. The absolute path is the skill's install location — in most installs that's ~/.claude/skills/jetpack-compose-audit/scripts/compose-reports.init.gradle. If you cannot resolve the path, fall back to writing the script to <target>/.compose-audit-reports.init.gradle and delete it after the run.
Check for a Gradle wrapper in the target: test -x <target>/gradlew. If missing, skip to the fallback in step 6.
Pick a compile target. Prefer the cheapest task that still triggers Kotlin compilation for a Compose module:
rg -l 'com\.android\.application' -g '*.gradle*':<app-module>:compileReleaseKotlinAndroid, :<app-module>:compileReleaseKotlin, assembleRelease, assembleDebugcom.android.library), use that module instead.Run the build. Inform the user the build is starting (it may take several minutes).
cd <target> && ./gradlew <task> \
--init-script <path-to>/compose-reports.init.gradle \
--no-daemon --quietUse a 600-second timeout. If the task fails, try the next fallback task in step 3 once. Do not loop indefinitely.
Collect the reports.
find <target> -path '*/build/compose_audit/*' \
\( -name '*-classes.txt' -o -name '*-composables.txt' -o -name '*-composables.csv' -o -name '*-module.json' \)From these files, extract:
unstable class in *-classes.txt) used as composable parameters*-composables.txt or *-composables.csv where isLambda == "0")*-module.json, AND compute the named-only skippability from *-composables.csv (by filtering out rows where isLambda == "1" and calculating sum(skippable) / sum(restartable)). Cite both in the Performance section, noting that zero-argument lambdas can artificially anchor the module-wide metric.Fallback if the build fails or Gradle is unavailable. Proceed with source-inferred stability findings, but:
Compiler diagnostics used: no in the report's Notes And Limits and explain the failure reason briefly (wrapper missing, compile error, timeout)Stability deductions from step 5 are measured evidence and should be weighted normally. Fallback deductions from step 6 are inferred and must be flagged as such in the report.
Use the scoring rubric in references/scoring.md and the heuristics in references/search-playbook.md.
Focus on:
Focus on:
remember vs rememberSaveableFocus on:
Focus on reusable internal components, not every leaf screen.
Check:
modifier presence and placementMutableState<T> or State<T> parameters in reusable APIs where a better shape existsBefore deducting points:
app/build/compose_audit/app_release-classes.txt:42) as evidence. Only fall back to source-inferred stability claims if Step 4 failed, and label them as such.Assign each category a 0-10 score and a status:
0-3: fail4-6: needs work7-8: solid9-10: excellentUse the weights in references/scoring.md to compute the overall score.
Measured ceilings are mandatory, not suggestive. When Step 4 produced compiler reports, the Performance rubric in references/scoring.md defines a ceiling based on skippable% and unstable-param count. After arriving at a qualitative Performance score, you MUST apply the ceiling and lower the score if it exceeds the cap. Show the math in the report:
Performance ceiling check:
skippable% = 186/273 = 68.1% → falls in 50-70% band → cap at 4
qualitative score: 7
applied score: 4 (ceiling lowered from 7)Do not round skippable% up into a higher band. 68.1% is not ≥70%. If a qualitative score lands at or below the ceiling, no adjustment is needed — but the check itself must appear in the report so the reader can audit it.
If a category genuinely has too little auditable surface area, mark it N/A, explain why, and renormalize the remaining weights.
Use references/report-template.md.
The report must include:
material-3 if design issues are suspectedWrite the report to:
COMPOSE-AUDIT-REPORT.md inside the audited target (the path the user passed), not the current working directory.If COMPOSE-AUDIT-REPORT.md already exists at that path, do not overwrite it silently. Either confirm overwrite with the user, or write to COMPOSE-AUDIT-REPORT-<YYYY-MM-DD>.md alongside it.
In chat, produce a summary that mirrors the report's Prioritized Fixes section — not a generic recap. The developer should be able to act on the summary alone without opening the report file.
Include:
COMPOSE-AUDIT-REPORT*.md at the same path, if present)skippable%, count of unstable shared types, any module that failed to buildkey = { it.id } to items(...) in feed/FeedList.kt:42")references/canonical-sources.mdFeedItem, should move skippable% from 79% → ~90%")material-3 audit is worth running nextThe top-three fixes in the chat summary MUST be the same items as the report's Prioritized Fixes list (same file paths, same doc links). Do not add generic advice in chat that isn't in the written report.
For medium or large repositories:
LaunchedEffect(Unit) or LaunchedEffect(true) on its own — the "run once" pattern is idiomatic. Only flag it when the body captures a value that may change without rememberUpdatedState.collectAsStateWithLifecycle, lifecycle-runtime-compose). Note the platform constraint as a tradeoff instead.references/scoring.md — per-rule rubric with inline citationsreferences/search-playbook.md — search patterns and red-flag heuristicsreferences/report-template.md — required structure for COMPOSE-AUDIT-REPORT.mdreferences/canonical-sources.md — the official URLs every deduction must citereferences/diagnostics.md — copy-pasteable Gradle/code snippets for Compose Compiler reports, stability config, baseline profiles, and R8 checksscripts/compose-reports.init.gradle — Gradle init script the skill injects via --init-script in Step 4 to generate compiler reports automaticallye68a71e
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.