[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-1342":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":9,"language":10,"languages":9,"totalLinesOfCode":9,"stars":11,"forks":12,"watchers":13,"openIssues":14,"contributorsCount":15,"subscribersCount":15,"size":15,"stars1d":16,"stars7d":17,"stars30d":18,"stars90d":15,"forks30d":15,"starsTrendScore":19,"compositeScore":20,"rankGlobal":9,"rankLanguage":9,"license":9,"archived":21,"fork":21,"defaultBranch":22,"hasWiki":23,"hasPages":21,"topics":24,"createdAt":9,"pushedAt":9,"updatedAt":25,"readmeContent":26,"aiSummary":27,"trendingCount":15,"starSnapshotCount":15,"syncStatus":28,"lastSyncTime":29,"discoverSource":30},1342,"compose_skill","hamen\u002Fcompose_skill","hamen","A strict, evidence-based audit skill for Android Jetpack Compose repositories.",null,"Shell",305,20,243,1,0,21,26,51,63,79.07,false,"main",true,[],"2026-06-12 04:00:08","# Jetpack Compose Audit Skill\n\n**Version 2.0.1 · released 2026-04-29** — Sharper \"no IO in composition\" rule with concrete class enumeration, the `remember`-is-not-a-fix framing, and the Coil\u002FGlide carve-out. `compose-agent` bumped to `1.1.2` for the matching authoring-mode update.\n\n> Find out where your Compose app is burning frames, by how much, and what to change to win them back — measured against real compiler data, not vibes.\n\nA strict, evidence-based audit for Android Jetpack Compose repositories. Point it at a repo, let it run the build once, and get back a 0-100 score, a 0-10 score per category, an actionable top-three fix list, and a full Markdown report with every deduction cited against an official `developer.android.com` page.\n\nBuilt for Claude Code, Cursor, and any agent that loads the Anthropic skill format.\n\n---\n\n## What's new\n\n### 2.0.1 — 2026-04-29\n\n**Sharpened — \"no IO in composition\" rule, with concrete class enumeration.**\n\nBoth skills now name the IO categories that must never appear in a composable body — serialization (`Json.decodeFromString`, `Gson`, `Moshi`, `ObjectMapper`, XML\u002FProtobuf\u002FCSV), network (`HttpClient`, `OkHttp`, `Retrofit`, `URL`, `Socket`), database (`DriverManager`, `Connection`, `prepareStatement`, `executeQuery`), file\u002Fdirectory IO (`File(...)`, `Files.*`, `FileInputStream`, `BufferedReader`), and subprocess (`ProcessBuilder`, `Runtime.exec`). The accepted carve-out is image loading via threading-aware loaders (Coil's `AsyncImage` \u002F `rememberAsyncImagePainter`, Glide's Compose API) — they manage the threading contract correctly.\n\nThe framing is now blunt: **`remember` is not a fix.** A `remember(key) { expensiveWork() }` still runs `expensiveWork()` on the composition thread on first composition and again on every key change, which is a frame hitch on screen entry. The only correct fix for non-trivial work is moving it to the presenter \u002F state holder \u002F ViewModel.\n\nWhat changed:\n\n- **`compose-agent\u002Freferences\u002Fperformance.md`**: rewrote the \"Expensive Work In Composition\" section. Added the explicit IO list with the Coil\u002FGlide carve-out, the \"`remember` is not the fix\" warning, the \"O(1) is not a free pass\" note (object init, lock acquisition, side-effectful constructors), grep-friendly enumeration of O(N) string ops and inline-`Regex` constructions, and a \"safe in composition\" list so the agent does not over-flag cheap reads.\n- **`compose-agent\u002Freferences\u002Feffects.md`**: added one Anti-Patterns bullet pointing at the new performance.md section so an agent reviewing effects encounters the rule.\n- **`jetpack-compose-audit\u002Freferences\u002Fscoring.md`**: tightened the Performance \"deduct for\" line to name the work types and explicitly reject `remember` as a fix; added the IO-in-composition deduction to Side Effects with the canonical class list and a Coil\u002FGlide reward in the same category.\n- **`jetpack-compose-audit\u002Freferences\u002Fsearch-playbook.md`**: added grep patterns for inline `Regex(...)` \u002F `.toRegex()` \u002F `.matches()`, O(N) string ops (`split`, `lines`, `replace`, `format`, etc.), O(N) collection aggregates (`count {}`, `joinToString`, `flatMap`, `sumOf`, `fold`), and a per-category list of forbidden-IO class names so the agent has actionable leads.\n- **Versions.** `jetpack-compose-audit` → `2.0.1`. `compose-agent` → `1.1.2`. No install-URL change. No breaking change to scoring categories, weights, or report format.\n\nFor older releases see the [full Changelog](#changelog) at the bottom of this README.\n\n---\n\n## What you get\n\nRun the skill on a Compose repo and you walk away with:\n\n- **`COMPOSE-AUDIT-REPORT.md`** written at the target root — per-category scoring, evidence file paths, line numbers, and prioritized fixes.\n- **A chat summary** that mirrors the report's top three fixes — same file paths, same doc links, same predicted impact. Act on the chat alone if you're short on time.\n- **Measured stability numbers** from the Compose Compiler — module-wide `skippable%`, named-only `skippable%`, the unstable-class list, and the per-module Strong Skipping state inferred from compiler version plus explicit flags.\n- **A score you can defend.** Every deduction carries an official Android Developers URL. No \"trust me\" findings.\n\n---\n\n## What the audit looks at\n\nFour categories, weighted for an app repo. Each scored `0-10`; overall on `0-100`.\n\n| Category | Weight | What it covers |\n|----------|--------|----------------|\n| **Performance** | 35% | Work in composition, lazy-list keys, state-read timing, stability, Strong Skipping, backwards writes, **animation phase correctness**, baseline profiles |\n| **State management** | 25% | Hoisting, single source of truth, `rememberSaveable`, lifecycle-aware collection, observable collections, ViewModel placement, type-safe navigation |\n| **Side effects** | 20% | Effect API choice, keys, stale captures, cleanup, composition-time work, **animation driving via `LaunchedEffect`** |\n| **Composable API quality** | 20% | Modifier conventions, parameter order, slot APIs, `CompositionLocal` usage, `Modifier.Node`, **`animationSpec` exposure**, `@Preview` coverage, hardcoded strings \u002F magic numbers |\n\nScore bands: `0-3` fail · `4-6` needs work · `7-8` solid · `9-10` excellent.\n\n---\n\n## What it catches (and what fixing it buys you)\n\nConcrete smells the rubric targets, with realistic wins:\n\n| Smell | Expected gain after fix |\n|-------|-------------------------|\n| Unstable or repeatedly recreated params (`List`, domain models, `ArrayList`-backed state, `listOf(...)`, fresh UI models) | On older compiler tracks, can lift named-only `skippable%` and the Performance ceiling. Under Strong Skipping, usually removes instance-recreation churn or expensive `equals()` work that was still forcing re-runs despite high skippability. |\n| Lazy-list `items(...)` without stable `key =` | Fewer reallocated compositions on reorder, smoother scroll, fewer `IllegalArgumentException: Key already used` crashes |\n| Rapidly-changing state read high in the tree | Recompositions collapse from \"per frame, whole screen\" to \"per frame, single modifier\" |\n| Animated `.value` piped into `Modifier.offset(x.dp)` \u002F `Modifier.alpha(a)` | Moving to `Modifier.graphicsLayer { ... }` \u002F `Modifier.offset { ... }` defers per-frame reads to layout\u002Fdraw — same animation, fraction of the recomposition cost |\n| `Animatable(...)` created in a composable body without `remember` | Animation no longer resets on every recomposition; velocity and target survive |\n| `rememberCoroutineScope().launch { animatable.animateTo(...) }` for target-driven animation | Replace with `LaunchedEffect(target)` — restart semantics follow the target automatically, while `rememberCoroutineScope()` stays available for event-driven animation |\n| `rememberInfiniteTransition` hosted on something that stays composed offscreen | Scoping it to visible content avoids needless offscreen animation work and lets it stop when the host actually leaves composition |\n| `collectAsState()` on Android UI flows | Swap to `collectAsStateWithLifecycle()` — no collection when UI is paused |\n| `mutableStateOf\u003CInt>` \u002F `\u003CLong>` \u002F `\u003CFloat>` in hot paths | Remove autoboxing, fewer allocations |\n| Hardcoded strings and magic numbers in reusable components | i18n + dark-mode + accessibility ready; testable |\n| `rememberSaveable` inside a `LazyListScope` item factory | No more `TransactionTooLargeException` when the list grows |\n| `Scaffold { innerPadding -> ... }` content that ignores `innerPadding` | Content stops drawing behind the `TopAppBar` \u002F system bars |\n\nThe report lists every occurrence with file path and line number, not just the category.\n\n---\n\n## What makes it different\n\n**Measured, not inferred.** The skill ships `scripts\u002Fcompose-reports.init.gradle` and injects it into your Gradle build via `--init-script` — no edits to your `build.gradle`. Every run parses real `*-classes.txt` \u002F `*-composables.txt` \u002F `*-module.json` output.\n\n**Mandatory ceilings.** A Performance score cannot exceed the cap set by the matching ceiling table. On older compiler tracks the cap is driven by `skippable%` plus unstable-param count; under Strong Skipping it is driven by named-only `skippable%`, instance-recreation churn, and `equals()` quality on unstable params. The ceiling math appears in the report so the score is auditable.\n\n**Every deduction cites an official source.** Each finding carries a `References:` line pointing at `developer.android.com` or the AndroidX component API guidelines. Audits that can't be defended with a URL don't ship.\n\n**Actionable chat summary.** The chat output mirrors the report's `Prioritized Fixes` — same file paths, same doc links, same predicted impact (\"stops rebuilding `FeedItemUiModel`, removes the Strong-Skipping cap from 8 → no cap\").\n\n---\n\n## Install\n\n### Claude Code\n\nInstall directly from the Git repository — no cloning, no symlinking:\n\n```\n\u002Fplugin add hamen\u002Fcompose_skill --subdir jetpack-compose-audit\n```\n\nClaude Code reads `jetpack-compose-audit\u002F.claude-plugin\u002Fplugin.json` and registers `SKILL.md` automatically. Updates arrive via the normal plugin update flow.\n\n### Cursor\n\nThe repo ships a `.cursor-plugin\u002Fplugin.json` manifest, so Cursor sees it as a valid single-skill plugin. There are two install paths today:\n\n- **Team Marketplace (orgs)**: a workspace admin can import this GitHub repository into a team marketplace. The manifest is what makes that import succeed.\n- **Manual symlink (individuals)**: use the manual install block below. Individual Cursor users do not have a `\u002Fplugin add`-style command for arbitrary Git URLs yet; symlink install remains the practical path until this skill is published to the public Cursor Marketplace.\n\n### Manual install (all harnesses)\n\nUse this on Cursor, on older Claude Code versions without `\u002Fplugin add`, or whenever you want `git pull` in this directory to update the skill in place:\n\n```bash\n# Claude Code\nmkdir -p ~\u002F.claude\u002Fskills\nln -s \"$(pwd)\u002Fjetpack-compose-audit\" ~\u002F.claude\u002Fskills\u002Fjetpack-compose-audit\n\n# Cursor\nmkdir -p ~\u002F.cursor\u002Fskills\nln -s \"$(pwd)\u002Fjetpack-compose-audit\" ~\u002F.cursor\u002Fskills\u002Fjetpack-compose-audit\n```\n\n---\n\n## Use\n\nFrom the agent prompt:\n\n```\n\u002Fjetpack-compose-audit [repo path or module path]\n```\n\nOr in natural language:\n\n```\nAudit this Compose repo.\nScore the :app module for Compose quality.\nRun a Compose performance review on core\u002Fui.\n```\n\nThe compiler-report build runs automatically and typically takes 1-5 minutes. If the build fails (no wrapper, compile error, timeout) the skill falls back to source-inferred findings, caps Performance at `7`, and flags reduced confidence — all stated explicitly in the report.\n\n---\n\n## Example output\n\n```\nOverall: 73\u002F100\n\nPerformance:  8\u002F10  capped by the SSM-on table: instance-recreation churn in feed params (qualitative 9)\nState:        6\u002F10  collectAsState without lifecycle, duplicate VM reads\nSide effects: 7\u002F10  LaunchedEffect key too broad at HomeScreen.kt:240\nAPI quality:  8\u002F10  BoxCard \u002F SearchBar follow conventions\n\nCompiler:\n  Strong Skipping: on (default)\n  ceiling table: SSM-on\n  module-wide skippable% = 186\u002F269 = 69.14%\n  named-only skippable% = 121\u002F122 = 99.18%\n  ceiling metric: named-only `skippable%` (module-wide metric anchored by zero-arg lambdas)\n  deferredUnstableClasses: 59\n  binding cap: 8 (fresh `FeedItemUiModel(...)` + `listOf(...)` rebuilt in `HomeFeedScreen`)\n\nTop 3 fixes\n1. collectAsState -> collectAsStateWithLifecycle across 6 call sites\n   feature\u002Fhome\u002FHomeScreen.kt:37, MainActivity.kt:213, ...\n   Doc: developer.android.com\u002F...\u002Fside-effects\n   Impact: fewer redundant collections, lifecycle-correct\n\n2. Stop rebuilding `FeedItemUiModel(...)` and `listOf(...)` inside `HomeFeedScreen`\n   Evidence: app\u002Fbuild\u002Fcompose_audit\u002Fapp_release-classes.txt, feature\u002Fhome\u002FHomeFeedScreen.kt:88-132\n   Doc: developer.android.com\u002F...\u002Fstability\n   Impact: removes forced re-runs under Strong Skipping, likely clears the Performance cap from 8 -> no cap\n\n3. Narrow LaunchedEffect(homeScreenState) at HomeScreen.kt:240-254\n   Doc: developer.android.com\u002F...\u002Fside-effects\n   Impact: fewer redundant ensureAuthenticated() calls\n```\n\n---\n\n## Scope\n\n**In scope (1.x).** Jetpack Compose on Android, Kotlin 2.0.20+ \u002F Compose Compiler 1.5.4+ (Strong Skipping default).\n\n**Out of scope (1.x)** — the skill will call these out as a note rather than silently produce thin coverage:\n\n- Material 3 compliance, theming, color\u002Ftypography — defer to the `material-3` skill.\n- Accessibility scoring (semantics, touch targets) — flagged as notes, not scored.\n- UI test coverage and Compose test-rule patterns.\n- Compose Multiplatform (`expect`\u002F`actual`, target-specific code paths).\n- Wear OS \u002F TV \u002F Auto \u002F Glance surfaces.\n- Build performance (incremental compilation, KSP\u002FKAPT choice).\n\n---\n\n## Layout\n\n```\njetpack-compose-audit\u002F\n  SKILL.md                       main audit skill (process, principles, output)\n  scripts\u002F\n    compose-reports.init.gradle  Gradle init script injected via --init-script\n  references\u002F\n    scoring.md                   rubric with measured ceilings and inline citations\n    search-playbook.md           grep patterns, regex, read-the-file heuristics\n    canonical-sources.md         every URL the rubric cites\n    report-template.md           required structure for COMPOSE-AUDIT-REPORT.md\n    diagnostics.md               manual-mode fallback snippets\n```\n\nA sibling skill, `compose-agent\u002F`, ships in the same repo — see [§ Sibling skill](#sibling-skill--compose-agent) for its own layout and usage.\n\n---\n\n## Philosophy\n\n- **Strict but evidence-based.** Every deduction has a file:line and an official-doc URL.\n- **Measured beats inferred.** Compiler reports are generated automatically; source-inferred stability is a fallback, not the default.\n- **Written for action.** The report's `Prioritized Fixes` section and the chat summary mirror each other, so the developer can act on the chat alone.\n- **Narrow scope on purpose.** The skill does not score design, accessibility, or build performance in v1. It says so rather than pretending otherwise.\n\n---\n\n## Sibling skill — `compose-agent`\n\nThis repo ships a second skill alongside the audit: [`compose-agent\u002F`](.\u002Fcompose-agent\u002F). Where the audit **reviews an existing repo** end-to-end and produces a score, `compose-agent` works at **file and feature scope** while you are reading, writing, or modifying Compose.\n\n- **Responds to:** \"is this right?\", \"rewrite this the modern way\", \"check this file for deprecated API\", \"find state hoisting mistakes in this feature\".\n- **Built for:** [android\u002Fskills#27](https:\u002F\u002Fgithub.com\u002Fandroid\u002Fskills\u002Fissues\u002F27) — the Android equivalent of [`swiftui-agent-skill`](https:\u002F\u002Fgithub.com\u002Ftwostraws\u002Fswiftui-agent-skill). The philosophy is the same: target the mistakes LLMs actually make in Compose, not repeat basics the model already knows.\n- **Shape:** short `SKILL.md` that routes to ten per-topic reference markdowns. You only pay the token cost for the areas your current task touches.\n\n### Install\n\nSame flow as the audit skill, pointing at the subdirectory.\n\n**Claude Code:**\n\n```\n\u002Fplugin add hamen\u002Fcompose_skill --subdir compose-agent\n```\n\n**Cursor:** import the repo as a plugin and pick `compose-agent` in the subdirectory selector.\n\n**Manual:** symlink `compose-agent\u002F` into your skills directory (`~\u002F.claude\u002Fskills\u002Fcompose-agent`, `~\u002F.cursor\u002Fskills\u002Fcompose-agent`, etc.).\n\nBoth skills can live side by side — they do not share state and do not interfere.\n\n### Use it — the two modes\n\n`compose-agent` runs in **review mode** or **authoring mode**. You do not choose; the skill picks based on your request.\n\n**Review mode** — you hand it code that already exists. It produces a file-by-file report with before\u002Fafter snippets and links to the official doc page behind each rule. Triggered by prompts like:\n\n```\nUse compose-agent to review feature\u002Fprofile\u002F.\nCheck ProfileScreen.kt with compose-agent.\ncompose-agent: find deprecated API in this module.\n```\n\n**Authoring mode** — the skill is loaded and you ask the assistant to *write* Compose. Before returning code, the assistant silently runs six checks against the rules in the skill:\n\n1. Does the composable take `modifier: Modifier = Modifier`?\n2. Is state hoisted, or is there a clear reason to own it here?\n3. If it renders a list, does it use a stable `key =`?\n4. If it launches work, is that work in a `LaunchedEffect`, `produceState`, or the ViewModel — not in the composition body?\n5. If it collects a `Flow`, is it `collectAsStateWithLifecycle()`?\n6. Is the parameter order data → `modifier` → other → content slot last?\n\nAny \"no\" without a reason → fixed before the code comes back. No extra prompt needed — loading the skill is enough.\n\n### Scoped reviews (the token-saver)\n\nThe ten reference files are deliberately loadable in isolation. Scoping a review to one area pulls only that reference into context — a focused review costs roughly a tenth of a full one.\n\n| You want… | Say |\n|---|---|\n| state correctness (hoisting, `remember`, saveable, ViewModel) | `compose-agent focus on state` |\n| side-effect choice (`LaunchedEffect`, `DisposableEffect`, `produceState`) | `compose-agent focus on effects` |\n| recomposition cost + Strong Skipping | `compose-agent focus on performance` |\n| modifier hygiene | `compose-agent focus on modifiers` |\n| Navigation 3 adoption or Nav2.8 type-safety | `compose-agent focus on navigation` |\n| `Flow` collection + lifecycle + coroutine scopes | `compose-agent focus on concurrency` |\n| Flow operator selection + `StateFlow`\u002F`SharedFlow` shape | `compose-agent focus on flows` |\n| reusable composable API shape | `compose-agent focus on component-api` |\n| deprecated \u002F soft-deprecated APIs | `compose-agent focus on api` |\n| idiomatic Kotlin \u002F Android style | `compose-agent focus on kotlin` |\n\n### What review mode gives back\n\n- **File-by-file findings.** File + line, rule name, minimal before\u002Fafter, link to `developer.android.com` or the AndroidX guidelines.\n- **Prioritized summary of up to three items**, highest impact first. Act on the chat alone if you are short on time.\n- **No nitpicks.** Clean files are not listed.\n\nAn example output block is in [`compose-agent\u002FSKILL.md`](.\u002Fcompose-agent\u002FSKILL.md) under \"Example Output\".\n\n### `compose-agent` vs `jetpack-compose-audit`\n\n| Use `compose-agent`… | Use `jetpack-compose-audit`… |\n|---|---|\n| while writing or editing a file | for a snapshot of the whole repo |\n| for doc-linked fixes on a specific concern | for a 0–100 score across four categories |\n| to make the assistant's output *be* correct Compose | to produce a `COMPOSE-AUDIT-REPORT.md` with measured evidence |\n| day to day, at file \u002F feature scope | once per release or before a review |\n\nOverlap is fine. Audit on the release candidate, `compose-agent` on every feature branch.\n\n### Layout\n\n```\ncompose-agent\u002F\n  SKILL.md                       short router — loads references on demand\n  references\u002F\n    api.md                       deprecated + soft-deprecated APIs → modern replacements\n    state.md                     hoisting, remember, rememberSaveable, ViewModel boundary\n    effects.md                   LaunchedEffect \u002F DisposableEffect \u002F produceState \u002F snapshotFlow\n    performance.md               Strong Skipping, lambda modifiers, lazy keys, typed state\n    modifiers.md                 order, lambda form, Modifier.Node vs composed { }\n    navigation.md                Navigation 3 + Nav2.8 type-safe destinations\n    concurrency.md               Flow collection + lifecycle, viewModelScope, dispatchers\n    flows.md                     StateFlow \u002F SharedFlow \u002F cold Flow, stateIn, shareIn, flatMap variants, error handling, backpressure\n    component-api.md             parameter order, slots, naming, state hoisting shape\n    kotlin.md                    Kotlin conventions + Android Kotlin style the LLM misses\n```\n\n---\n\n## Changelog\n\n### 2.0.0 — 2026-04-28\n\n**Breaking — install URL changed; repo restructured for [agentskills.io](https:\u002F\u002Fagentskills.io\u002F) compliance.**\n\nBoth skills in this repo now pass the strict [agentskills.io specification](https:\u002F\u002Fagentskills.io\u002Fspecification) validator with zero critical findings, audited against [the community validator skill](https:\u002F\u002Fgist.github.com\u002Fkingargyle\u002F37e279f27880e7a92253e5f7e7686720) raised in [android\u002Fskills#23](https:\u002F\u002Fgithub.com\u002Fandroid\u002Fskills\u002Fissues\u002F23). Getting there required moving the audit skill into its own `jetpack-compose-audit\u002F` subdirectory so every skill folder name matches its declared `name`, and removing a cross-skill reference that traversed `..` between the two skills. The cost is a one-time install URL update for existing users.\n\n**Required action for existing installs.**\n\n```\n# Old (no longer works)\n\u002Fplugin add hamen\u002Fcompose_skill\n\n# New\n\u002Fplugin add hamen\u002Fcompose_skill --subdir jetpack-compose-audit\n```\n\nAnyone running `\u002Fplugin update` against the old install will not pick up changes after `1.5.1`. Reinstall once with `--subdir jetpack-compose-audit` and updates resume normally.\n\n- **Repo restructure.** `SKILL.md`, `references\u002F`, `scripts\u002F`, `.claude-plugin\u002F`, and `.cursor-plugin\u002F` all moved from the repo root into `jetpack-compose-audit\u002F`. Git tracked the moves as renames, so blame and history are preserved. No skill content changed.\n- **Cross-skill reference inlined.** `jetpack-compose-audit\u002Freferences\u002Fsearch-playbook.md` previously linked into `compose-agent\u002Freferences\u002Fflows.md` for the \"Flow operators belong outside the composable body\" rule — that pointer is replaced with the rule inlined directly. Both skills are now self-contained, with no parent-traversal references between them.\n- **Manual symlink instructions updated.** The README symlink target is now `$(pwd)\u002Fjetpack-compose-audit` instead of `$(pwd)`.\n- **`compose-agent` is unchanged.** Folder, install URL (`\u002Fplugin add hamen\u002Fcompose_skill --subdir compose-agent`), and version (`1.1.1`) are all the same. No action needed for compose-agent users.\n\n**Why 2.0.0 and not 1.6.0.** The install URL change is breaking — users on the old URL silently stop receiving updates. Semver says that's a major bump, regardless of whether the rubric or report content moved. Actual audit behavior, scoring, categories, and report format are identical to `1.5.1`.\n\n### 1.5.1 — 2026-04-27\n\n**Fixed — Flow guidance consistency.**\n\nThis patch keeps the `1.5` Flow reference intact, but tightens the wording so agents do not learn two subtly different rules from adjacent sections.\n\n- **Must-deliver outcomes stay durable.** The `StateFlow` \u002F `SharedFlow` decision table no longer lists in-app purchase results as generic one-shot events. Payment, deletion, save, and similar outcomes that must not be lost are consistently described as durable UI state with an acknowledgement callback.\n- **Effect collection keys clarified.** Manual event collection now says to key `LaunchedEffect` on the changing flow identity, and to use `LaunchedEffect(Unit)` only when the flow object is intentionally stable for the call-site lifetime.\n- **Search heuristic softened.** `collectLatest` is no longer grouped with Flow-shaping operators that automatically belong in presenters. Terminal collection directly in a composable body is still a smell; collection inside a correctly keyed `LaunchedEffect(...)` for ephemeral events is explicitly acceptable.\n- **Audit command safer on Linux.** The Flow-misuse search pipeline now uses `xargs -r` so an empty composable-file list does not accidentally run the second search across the whole repo.\n\n### 1.5.0 — 2026-04-27\n\n**Added — Flow operator reference.** `compose-agent\u002Freferences\u002Fflows.md` is the missing counterpart to `concurrency.md`: lifecycle, scopes, and dispatchers stay in `concurrency.md`; operator choice and exposed Flow shape now live in `flows.md`.\n\nThis release closes the \"Flow effectively\" gap from [android\u002Fskills#27](https:\u002F\u002Fgithub.com\u002Fandroid\u002Fskills\u002Fissues\u002F27). Compose, Coroutines, and Navigation 3 were already covered by `compose-agent`; Flow operator selection was the weak spot.\n\nWhat changed:\n\n- **Flow shape decisions.** Clear guidance for `StateFlow` vs `SharedFlow` vs cold `Flow`, including when UI outcomes should be durable state instead of ephemeral events.\n- **`stateIn` \u002F `shareIn` correctness.** ViewModel state uses `stateIn(scope, started, initialValue)` with `WhileSubscribed(5_000)` as the default recommendation. `shareIn` is documented with its real API shape: `scope`, `started`, and `replay`; buffering belongs upstream via `buffer(...)` \u002F `conflate()`, not as nonexistent `shareIn` parameters.\n- **Operator selection.** Covers `flatMapLatest` \u002F `flatMapMerge` \u002F `flatMapConcat`, `combine` \u002F `merge` \u002F `zip`, `catch` \u002F `retry` \u002F `retryWhen` \u002F `onCompletion`, and backpressure via `buffer`, `conflate`, and `collectLatest`.\n- **Nonexistent APIs called out.** The reference explicitly says `kotlinx.coroutines.flow` does not ship `throttleLatest` \u002F `throttleFirst`; agents should not invent imports for them.\n- **Mutable vs read-only exposure.** Reinforces `asStateFlow()`, `asSharedFlow()`, and `receiveAsFlow()` so agents do not expose mutable primitives or call `tryEmit` on read-only `SharedFlow`.\n- **Audit wording tightened.** Scoring categories, weights, and report format are unchanged, but the state-management rubric now follows Android's UI-events guidance: model must-deliver UI outcomes as state with acknowledgement; reserve `Channel` \u002F `SharedFlow` for ephemeral signals with documented delivery semantics.\n\n**Wiring.** Added as Review Process step 8 in `compose-agent\u002FSKILL.md`, between concurrency and composable API review. The README, layout docs, scoped-review table, and both Claude\u002FCursor plugin manifests were updated for the `1.5.0` \u002F `1.1.0` release.\n\n### 1.4.1 — 2026-04-24\n\n**Fixed — `compose-agent` documentation correctness.**\n\nThis is a same-day follow-up to `1.4`. The new sibling skill shipped useful guidance, but a few reference notes were too absolute or technically wrong. `1.4.1` tightens those sections against the current official Android and Kotlin docs so the skill stops teaching bad fixes in authoring mode.\n\n- **Performance reference corrected.** `remember` semantics now match the docs: the calculation runs during the first composition, then again only when the call leaves composition or its keys change. The bogus `remember { stringResource(...) }` suggestion is gone, the nonexistent \"lambda-form padding\" recommendation is gone, and the sample state-reader lambda now compiles.\n- **Concurrency reference corrected.** `MutableStateFlow.value` is no longer described as main-thread-confined. The guidance now reflects the official thread-safe semantics and frames `.value`, `emit(...)`, and `update { ... }` by API shape rather than folklore.\n- **State reference softened.** Snapshot lists\u002Fmaps are still recommended for in-place UI mutations, but immutable list replacement via `StateFlow\u003CList\u003CT>>` \u002F `MutableState\u003CList\u003CT>>` is now called out as equally valid architecture.\n- **Navigation 3 reference corrected.** Saveable state and NavEntry-scoped `ViewModel`s are now described in terms of `NavEntryDecorator` setup, matching current `NavDisplay` defaults and the `rememberViewModelStoreNavEntryDecorator()` add-on.\n- **Custom modifier example fixed.** The zero-parameter `ModifierNodeElement` sample now uses the singleton\u002Fno-parameter pattern from the docs, and the stateful `Checkbox` convenience example now compiles.\n- **Version bumps.** The audit skill manifests now read `1.4.1`; the sibling `compose-agent` manifests now read `1.0.1`.\n\n### 1.4 — 2026-04-24\n\n**Added — `compose-agent` sibling skill.** An agent skill that helps AI coding assistants write modern Jetpack Compose.\n\nWhere `jetpack-compose-audit` scores your whole repo end-to-end, `compose-agent` works at file and feature scope while you are reading, writing, or modifying Compose. It targets the mistakes LLMs actually make. Built as a response to [android\u002Fskills#27](https:\u002F\u002Fgithub.com\u002Fandroid\u002Fskills\u002Fissues\u002F27) — the Android equivalent of [SwiftUI Pro](https:\u002F\u002Fgithub.com\u002Ftwostraws\u002Fswiftui-agent-skill).\n\n- **Short `SKILL.md` that routes to nine focused reference files** — `api`, `state`, `effects`, `performance`, `modifiers`, `navigation`, `concurrency`, `component-api`, `kotlin`. Only the reference relevant to the current task is pulled into context.\n- **Two modes, no config.** Review mode: \"check this file\" returns a file-by-file report with before\u002Fafter snippets and official doc links. Authoring mode: six silent guardrails run on every new composable before the code comes back (`modifier` param, state hoisting, lazy keys, effect placement, lifecycle-aware collection, parameter order).\n- **Scoped reviews save tokens.** `compose-agent focus on state` loads only `state.md` — roughly a tenth of a full review. Same for `effects`, `performance`, `modifiers`, `navigation`, `concurrency`, `component-api`, `api`, `kotlin`.\n- **Install side by side** with the audit skill: `\u002Fplugin add hamen\u002Fcompose_skill --subdir compose-agent`. Cursor and manual-symlink paths are documented in the new \"Sibling skill\" section of this README.\n\n**Proven on a real app.** Dogfooded against `kindle-gratis-compose` before shipping. In one review of three files it caught:\n\n- A `Random.nextInt()` called in an `@Composable` body — every recomposition picked a new placeholder URL and re-requested the image.\n- `Color.Black` text laid over a blended `colorScheme.primary` + `colorScheme.surface` background — unreadable in dark mode. Light-mode tests do not catch this.\n- A `DisposableEffect` + `LifecycleEventObserver` for an `ON_START` refresh — should be `LifecycleStartEffect` from lifecycle-runtime-compose 2.8+. Half the code, same behavior.\n- Five composables with `modifier` either missing or positioned before required data (AndroidX component guideline violation).\n- Hardcoded English strings in `contentDescription` \u002F `onClickLabel` where the rest of the file already used `stringResource`.\n\nEvery finding came with a file:line, a before\u002Fafter, and a link to the official AndroidX or `developer.android.com` page behind the rule. Top-three prioritized summary at the end.\n\n**Added — dark-mode contrast heuristic** (driven by the dogfood run above). Hard-coded foreground colors (`Color.Black`, `Color.White`, raw ARGB literals) over theme-derived backgrounds (`colorScheme.*` or blends thereof) are now flagged as a dark-mode regression risk. Documented in `compose-agent\u002Freferences\u002Fcomponent-api.md` with a \"Dark Mode Correctness\" section, grep triggers, and a fix pattern that reads color from the matching `on*` role.\n\n**Added — `LifecycleStartEffect` \u002F `LifecycleResumeEffect` guidance.** The lifecycle-runtime-compose 2.8+ APIs replace the verbose `DisposableEffect` + `LifecycleEventObserver` pattern. Covered in `compose-agent\u002Freferences\u002Feffects.md` as a first-class side-effect option and in `references\u002Fapi.md` as a soft-deprecation flag. The old idiom is pervasive in LLM-generated Compose code — exactly the kind of post-training-cutoff API the skill exists to teach.\n\n**No change to the audit skill rubric.** `jetpack-compose-audit` behavior, categories, scoring, and report format are identical to `1.3`. This release is purely additive. Run the audit once per release; run `compose-agent` every day.\n\n### 1.3 — 2026-04-22\n\n**Added — Cursor plugin support.**\n\nSame-day follow-up to `1.2`. Cursor's plugin system is structurally identical to Claude Code's (hidden manifest directory, single-skill plugins auto-discover a root-level `SKILL.md`), so shipping a sidecar manifest was essentially free — and it unblocks org admins who want to import the skill into their team marketplace via Cursor's GitHub-import flow.\n\n- **New file**: `.cursor-plugin\u002Fplugin.json` at the repo root. Same metadata as the Claude Code manifest (name, version, description, author, repository, license, keywords). The `skills` field is intentionally omitted so Cursor treats the repo as a single-skill plugin and auto-discovers `SKILL.md` at the root — matching the documented default behaviour.\n- **Install docs**: the README Install section is restructured around harnesses (Claude Code \u002F Cursor \u002F manual symlink) rather than recommended-vs-fallback. Each path is clearly labelled with what it does and does not unlock today.\n- **Not submitted to Cursor Marketplace (yet)**. The manifest is a prerequisite for submission and for team-marketplace imports, but no public Marketplace listing was created in this release. Individual Cursor users should continue with the symlink install until that changes.\n- **Version alignment**: `.claude-plugin\u002Fplugin.json` bumped to `1.3.0` to match. Both plugin manifests and `SKILL.md` now read the same version string.\n\n### 1.2 — 2026-04-22\n\n**Added — Claude Code plugin support.**\n\nThe skill now ships a `.claude-plugin\u002Fplugin.json` manifest, so Claude Code users can install it directly from the Git URL via `\u002Fplugin add hamen\u002Fcompose_skill` instead of cloning and symlinking by hand. Nothing else about the skill changed — same rubric, same categories, same report template.\n\n- **New file**: `.claude-plugin\u002Fplugin.json` at the repo root. Declares the skill name, version, repository, license, and keywords, and points Claude Code at the existing `SKILL.md` via `\"skills\": \".\u002F\"`. Purely additive — no existing files were restructured.\n- **README install section rewritten**: Claude Code plugin install is now the primary path. The previous symlink flow is kept verbatim as a **Manual install \u002F Cursor** fallback for Cursor users and for older Claude Code versions that don't yet support the plugin system.\n- **Why now**: tracks [android\u002Fskills#7](https:\u002F\u002Fgithub.com\u002Fandroid\u002Fskills\u002Fissues\u002F7) (47 👍 at time of writing) — install friction was the single biggest piece of community feedback on the Agent Skills install story. Same bottleneck applied here; same fix.\n\n### 1.1.1 — 2026-04-21\n\n**Refined — Strong Skipping-aware scoring, detection, and reporting.**\n\nThis is a corrective follow-up to `1.1`. After feedback around Strong Skipping Mode, the skill now evaluates modern Compose repos the way the compiler actually behaves on Kotlin `2.0.20+` \u002F Compose Compiler `1.5.4+`.\n\n- **Performance rubric**: split the measured-ceiling logic into explicit **SSM-off** and **SSM-on** paths. On older compiler tracks, ceilings still depend on `skippable%` and unstable shared params. Under Strong Skipping, the audit no longer blindly caps scores because a repo uses raw `List` params or misses `@Stable` on its own.\n- **What now matters under SSM**: the audit now looks for the issues that still materially defeat skipping in practice: per-recomposition param churn (`listOf(...)`, `mapOf(...)`, fresh UI models, object \u002F lambda literals in composable bodies), expensive or broken `equals()` on unstable params, and unjustified `@NonSkippableComposable` \u002F `@DontMemoize` opt-outs on hot paths.\n- **More honest compiler interpretation**: the docs now explicitly distinguish module-wide `skippable%` from **named-only `skippable%`**, because zero-argument lambdas can artificially drag down the raw module number. Reports are instructed to say which metric actually bound the ceiling.\n- **Collection guidance corrected**: `ImmutableList` \u002F `PersistentList` are no longer framed as a mandatory cargo-cult fix under Strong Skipping. They still earn credit, but for the right reasons: structural sharing, predictable equality, and lower churn when collections are reused deliberately.\n- **Search playbook**: the Strong Skipping section now tells the agent exactly how to detect explicit opt-ins \u002F opt-outs, when **not** to deduct for raw `List` params or missing `@Stable`, and what to inspect instead when SSM is active.\n- **Diagnostics**: Strong Skipping is now resolved **per module**, not assumed once for the whole repo. The diagnostics docs cover default-on, explicit opt-out, older-version opt-in, and mixed-module repos where different modules may require different ceiling tables.\n- **Report template**: added a mandatory **Performance ceiling check** block so every report records Strong Skipping status, the table applied, module-wide vs named-only `skippable%`, unstable shared-type count, the actual binding cap, and the final applied score.\n- **Chat summary guidance**: the short final summary now mirrors the same SSM-aware framing as the report. Under SSM, expected impact is described in terms of removing churn, fixing `equals()`, or clearing the binding cap rather than promising a magic `skippable%` jump.\n- **README examples and docs**: refreshed the public-facing example output to show a realistic SSM-era case: Strong Skipping on, high named-only skippability, and a score capped by recreated params rather than by the raw module-wide percentage.\n\n**Net effect:** fewer false positives on modern Compose codebases, fewer cargo-cult recommendations, and more defensible audit reports when the repo already runs with Strong Skipping enabled by default.\n\n### 1.1 — 2026-04-21\n\n**Added — animation auditing.**\n\n- **Performance**: new rules for animation phase correctness. Flags animated `.value` reads piped into state-reading modifiers (`Modifier.offset(x.dp)`, `Modifier.alpha(a)`) when lambda-form modifiers (`Modifier.graphicsLayer { ... }`, `Modifier.offset { ... }`) would defer to layout\u002Fdraw. Flags `Animatable(...)` created in a composable body without `remember { ... }` or hoisting. Flags `rememberInfiniteTransition()` hosted in composables that stay composed offscreen. Adds API-choice guidance for `Crossfade` vs `AnimatedContent`: standard fades remain fine with `Crossfade`, while custom enter\u002Fexit or size-aware swaps belong in `AnimatedContent`.\n- **Side effects**: new rules for animation driving. Flags `Animatable` animations launched from the composition body. Flags `rememberCoroutineScope().launch { animatable.animateTo(...) }` when the animation is target-driven and `LaunchedEffect(target)` is the clearer fit.\n- **Composable API quality**: new rules for reusable animated components. Encourages exposing `animationSpec: AnimationSpec\u003CT>` on shared animated APIs when callers may reasonably need timing control. Treats missing `label` parameters on tooling-visible shared animations as a light tooling-quality smell rather than a hard failure.\n- **Search playbook**: dedicated \"Animation Phase-Smell Heuristic\" section and new grep patterns for animation APIs.\n- **Canonical sources**: added the Compose Animation docs (`animation\u002Fintroduction`, `animation\u002Fvalue-based`, `animation\u002Fcustomize`) to the URL ledger every deduction must cite.\n\n### 1.0 — initial release\n\n- Four scoring categories: Performance (35%), State management (25%), Side effects (20%), Composable API quality (20%).\n- Automatic Compose Compiler reports via a bundled Gradle init script (`scripts\u002Fcompose-reports.init.gradle`).\n- Measured `skippable%` ceilings on the Performance score.\n- Every deduction cited against `developer.android.com` or the AndroidX component guidelines.\n- Mirrored chat summary and written `COMPOSE-AUDIT-REPORT.md` with prioritized fixes.\n\n---\n\n## License\n\nMIT.\n","Jetpack Compose Audit Skill 是一个针对 Android Jetpack Compose 仓库的严格、基于证据的审计工具。它能够帮助开发者识别和优化导致帧率下降的代码问题，通过一次构建运行后提供0-100的整体评分、每个类别的0-10评分、前三项可操作修复建议以及详细的Markdown报告，所有扣分项都引用了官方 `developer.android.com` 页面的内容。该工具特别适用于需要确保 Jetpack Compose 应用性能符合最佳实践标准的场景，如避免在组合过程中执行I\u002FO操作（包括网络请求、文件读写等），并强调使用`remember`并不能解决所有性能问题。此外，它还支持特定格式的自动化代理加载，便于集成到开发工作流中。",2,"2026-06-11 02:43:08","CREATED_QUERY"]