{"id":51544849,"url":"https://github.com/roninforge/roninforge-kotlin-compose","last_synced_at":"2026-07-09T17:01:08.247Z","repository":{"id":363762505,"uuid":"1237886575","full_name":"RoninForge/roninforge-kotlin-compose","owner":"RoninForge","description":"Cursor plugin for modern Android (Kotlin 2.x + Jetpack Compose + Material 3). Teaches StateFlow + collectAsStateWithLifecycle, Hilt, type-safe Navigation Compose, KSP, Version Catalogs, kotlin-compose plugin. Catches 20 legacy regressions LLMs still produce.","archived":false,"fork":false,"pushed_at":"2026-06-10T07:45:13.000Z","size":39,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-10T09:21:35.473Z","etag":null,"topics":["ai-dev-tools","android","anti-patterns","compose-material3","cursor","cursor-plugin","cursor-rules","developer-tools","hilt","jetpack-compose","kotlin","ksp","stateflow"],"latest_commit_sha":null,"homepage":"https://roninforge.org/#plugins","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/RoninForge.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-13T15:49:01.000Z","updated_at":"2026-06-10T07:45:18.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/RoninForge/roninforge-kotlin-compose","commit_stats":null,"previous_names":["roninforge/roninforge-kotlin-compose"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/RoninForge/roninforge-kotlin-compose","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RoninForge%2Froninforge-kotlin-compose","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RoninForge%2Froninforge-kotlin-compose/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RoninForge%2Froninforge-kotlin-compose/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RoninForge%2Froninforge-kotlin-compose/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/RoninForge","download_url":"https://codeload.github.com/RoninForge/roninforge-kotlin-compose/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RoninForge%2Froninforge-kotlin-compose/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35306717,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-09T02:00:07.329Z","response_time":57,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai-dev-tools","android","anti-patterns","compose-material3","cursor","cursor-plugin","cursor-rules","developer-tools","hilt","jetpack-compose","kotlin","ksp","stateflow"],"created_at":"2026-07-09T17:01:06.997Z","updated_at":"2026-07-09T17:01:08.234Z","avatar_url":"https://github.com/RoninForge.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# roninforge-kotlin-compose\n\n[![Validate Plugin](https://github.com/RoninForge/roninforge-kotlin-compose/actions/workflows/validate.yml/badge.svg)](https://github.com/RoninForge/roninforge-kotlin-compose/actions/workflows/validate.yml)\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)\n[![GitHub release](https://img.shields.io/github/v/release/RoninForge/roninforge-kotlin-compose)](https://github.com/RoninForge/roninforge-kotlin-compose/releases)\n\nCursor plugin for modern Android development with Kotlin 2.x and Jetpack Compose. Teaches the AI to write stateless Screen + stateful Route composables, StateFlow + `collectAsStateWithLifecycle`, Hilt + `hiltViewModel()`, type-safe Navigation Compose, KSP, Version Catalogs, and Material 3. Catches 20 legacy regressions LLMs still produce.\n\n## The Problem\n\nLLMs trained on Android-View-system + Kotlin 1.x patterns ship code that does not match modern Compose. They produce:\n\n- `findViewById\u003c...\u003e(R.id.x)` and `setContentView(R.layout.x)` in projects meant to be Compose-based\n- `GlobalScope.launch { }` (leaks across the process)\n- `LiveData` + `observeAsState` instead of `StateFlow` + `collectAsStateWithLifecycle`\n- Public `MutableStateFlow` exposed from the ViewModel\n- Force-unwrap `!!` everywhere\n- Lowercase composable names (`@Composable fun userCard()`)\n- `LazyColumn { items(list) { ... } }` without a `key` argument\n- `LaunchedEffect(true)` / `LaunchedEffect(Unit)` as a catch-all\n- `androidx.compose.material.*` (Material 2) imports in a Material 3 project\n- `Modifier.padding(...).clickable { }` (dead zone around the button)\n- `kotlinCompilerExtensionVersion` in `composeOptions` (removed in Kotlin 2.0+)\n- `kapt` annotation processor instead of KSP\n- ViewModel drilled through composition instead of `hiltViewModel()` at the screen root\n- `remember { mutableStateOf() }` outside a `@Composable` function\n- `runBlocking { }` on the main thread\n- Side effects in composition body without `LaunchedEffect` / `DisposableEffect` / `SideEffect`\n- Java-style `getX()` / `setX()` accessors instead of Kotlin properties\n- Heavy work in the composition body (large `map` / `filter`) without `remember`\n- `Log.d` calls scattered through the codebase\n- Hardcoded versions in module `build.gradle.kts` instead of `libs.versions.toml`\n\n## Install\n\n```bash\ngit clone https://github.com/RoninForge/roninforge-kotlin-compose.git ~/.cursor/plugins/local/roninforge-kotlin-compose\n```\n\nOr copy into your project:\n\n```bash\ngit clone https://github.com/RoninForge/roninforge-kotlin-compose.git\ncp -r roninforge-kotlin-compose/rules/* your-project/.cursor/rules/\ncp -r roninforge-kotlin-compose/skills/* your-project/.cursor/skills/\ncp -r roninforge-kotlin-compose/agents/* your-project/.cursor/agents/\n```\n\n## What's Included\n\n### Rules (5 files)\n\n| Rule | Scope | What it does |\n|------|-------|-------------|\n| `compose-core` | Always active | Kotlin 2.x + `kotlin-compose` plugin, Material 3, state hoisting, StateFlow + `collectAsStateWithLifecycle`, Hilt, type-safe Navigation Compose, KSP, Version Catalogs, BOM |\n| `compose-anti-patterns` | Always active | 20 regressions: findViewById, setContentView, GlobalScope, LiveData, public MutableState, `!!`, lowercase composables, LazyColumn without key, LaunchedEffect(true), Material 2, modifier order, kotlinCompilerExtensionVersion, kapt, runBlocking, side effects in composition |\n| `compose-architecture` | `**/*.kt` | Feature modularization, repository + data source, sealed UI state, ViewModel + stateIn, Ktor + Kotlin Serialization, Room with Flow + KSP, structured concurrency |\n| `compose-performance` | `**/*.kt` | Strong-skipping (Kotlin 2.x default), `@Stable` / `@Immutable`, `remember` keys, `derivedStateOf`, LazyColumn `key` + `contentType`, deferred reads |\n| `compose-testing` | Agent-requested | `createComposeRule`, semantic matchers, ViewModel tests with `runTest` + Turbine, fake repositories, Hilt tests, Paparazzi screenshots |\n\n### Skills (4 commands)\n\n| Skill | Command | What it does |\n|-------|---------|-------------|\n| New screen | `/compose-new-screen` | Scaffold stateless Screen + stateful Route + ViewModel + sealed UI state + nav route + previews + test |\n| Migrate Views to Compose | `/compose-migrate-views-to-compose` | Per-screen migration from XML/Activity to setContent + Route + Screen, with View-to-Compose component mappings |\n| Validate | `/compose-validate` | Scan codebase for the 20 tracked anti-patterns, report by severity |\n| Modernize build | `/compose-modernize-build` | Move to Kotlin 2.x: introduce libs.versions.toml, apply kotlin-compose plugin, kapt to KSP, BOM, Material 3, target SDK 36 |\n\n### Agent (1 subagent)\n\n| Agent | What it does |\n|-------|-------------|\n| `compose-reviewer` | Reviews Kotlin/Compose code by severity: critical (crashes, build breaks), warnings (regressions), suggestions (style + performance) |\n\n## What Makes This Different\n\nThe existing .cursorrules for Android cover style (\"write idiomatic Kotlin\"). None of them:\n\n- Force the `kotlin-compose` plugin and reject `kotlinCompilerExtensionVersion` (Kotlin 2.0+ requirement)\n- Enforce Material 3 imports (every legacy project leaks `androidx.compose.material.*`)\n- Push `collectAsStateWithLifecycle()` over `collectAsState()`\n- Catch the `Modifier.padding(...).clickable { }` dead-zone bug\n- Teach type-safe Navigation Compose with `@Serializable` routes\n- Bundle a build-modernization skill for the catalog + KSP migration\n\n## Fixtures\n\n`tests/fixtures/anti-pattern-sample/` is an Activity + XML + LiveData + GlobalScope + Material 2 mess. `tests/fixtures/correct-sample/` is the Compose-only + ViewModel + StateFlow + Material 3 + Hilt + Version Catalog equivalent.\n\n## License\n\nMIT - see [LICENSE](LICENSE)\n\n## Links\n\n- [Jetpack Compose April 2026 release](https://android-developers.googleblog.com/2026/04/jetpack-compose-april-2026-updates.html)\n- [Kotlin releases](https://kotlinlang.org/docs/releases.html) (2.x series, K2 + Compose plugin moved in 2.0)\n- [Compose Compiler Gradle plugin](https://developer.android.com/develop/ui/compose/setup-compose-dependencies-and-compiler)\n- [Type-safe Navigation in Compose](https://developer.android.com/guide/navigation/type-safe-destinations)\n- [Material 3 Adaptive](https://developer.android.com/jetpack/androidx/releases/compose-material3-adaptive)\n- [Cursor Plugin Documentation](https://docs.cursor.com/plugins)\n- [RoninForge](https://roninforge.org)\n\n\n## More from RoninForge\n\n[RoninForge](https://roninforge.org) builds free tools for developers working with AI coding assistants:\n\n- [LLM API pricing comparison](https://roninforge.org/llm-pricing) - Claude, GPT, Gemini, DeepSeek, Mistral, and Grok token prices side by side, verified against official pricing pages\n- [GitHub Copilot AI Credits calculator](https://roninforge.org/copilot-credits-calculator) - estimate your monthly credit burn under usage-based billing\n- [All Cursor plugins](https://roninforge.org/#plugins)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Froninforge%2Froninforge-kotlin-compose","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Froninforge%2Froninforge-kotlin-compose","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Froninforge%2Froninforge-kotlin-compose/lists"}