A Claude skill designed for working with Compose Multiplatform, based on my own experience using the Claude Code and CMP combination.
SaferSkills independently audited greenfish-cpm-skill (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Every screen follows this structure under ui/<feature>/:
*State — immutable data class; initializes with empty/default values, never hardcoded sample data*Intent — sealed class for user actions*ViewModel — holds StateFlow<*State>, processes intents; annotated @KoinViewModel*View — Composable that observes state and dispatches intentsOne function (or class) per file. No exceptions.
Use annotation-based Koin: @Module, @KoinViewModel, component scanning on the root package. No manual module { } blocks or factory/single wiring unless annotations are unavailable. KSP generates type-safe builders at compile time.
Never wrap a theme root in Surface just to set content color. Use CompositionLocalProvider:
CompositionLocalProvider(LocalContentColor provides colorScheme.onSurface) {
content()
}Surface adds an implicit background layer. Use it only when you explicitly want a background drawn. CompositionLocalProvider is the right primitive for propagating color context.
Do not repeat what the surrounding package or class already says. In package navigation.animation, a function called navAnimationColors() is redundant — animationColors() is enough. Before naming a symbol, check what the enclosing scope already implies; only add a qualifier if the name would be genuinely ambiguous without it.
All animation constants (durations, spring stiffness, press scales) go in a single *Animation object. All extended color tokens go in a single *Colors object. Never inline magic numbers in UI code — if a value is used once, it still belongs in the token object.
M3 state layer opacity: 8% hover, 12% press. Active nav items: lerp(containerColor, onContainerColor, stateAlpha). Inactive: onSurface.copy(alpha = stateAlpha).
State classes and ViewModels initialize with empty collections and default values. Hardcoded sample or demo data belongs in test helpers or @Preview parameters only — never inline in production State or ViewModel files. The app is a working product, not a prototype.
Every numeric constant used in layout, animation, or color logic must be named. No Modifier.padding(12.dp) without a token; no alpha = 0.08f without a constant. Name it where it lives conceptually (animation object, color object, shape object).
RowScaffold so window insets are handled automaticallycurrentWindowAdaptiveInfo() has no commonMain alternative yet; suppress deprecation where neededLock phones (smallestScreenWidthDp < 600) to portrait in Activity.onCreate(). Tablets and foldables rotate freely.
Surface as a theme wrapper for content color propagationState or ViewModel~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.