{"id":48837245,"url":"https://github.com/yschimke/compose-ai-tools","last_synced_at":"2026-06-14T18:01:10.508Z","repository":{"id":351416698,"uuid":"1208417484","full_name":"yschimke/compose-ai-tools","owner":"yschimke","description":"Helping the Agents Compose the Things","archived":false,"fork":false,"pushed_at":"2026-06-14T15:18:35.000Z","size":121441,"stargazers_count":90,"open_issues_count":18,"forks_count":3,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-14T15:18:40.138Z","etag":null,"topics":["agent-skills","android","claude-code","claude-skills","compose-multiplatform","compose-preview","gradle-plugin","jetpack-compose","kotlin","skill-md","vscode-extension","wear-os"],"latest_commit_sha":null,"homepage":"https://yschimke.github.io/compose-ai-tools/","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/yschimke.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":"docs/ROADMAP_1_0.md","authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"docs/AGENTS.md","dco":null,"cla":null}},"created_at":"2026-04-12T08:49:11.000Z","updated_at":"2026-06-14T15:01:41.000Z","dependencies_parsed_at":"2026-04-21T10:02:07.479Z","dependency_job_id":null,"html_url":"https://github.com/yschimke/compose-ai-tools","commit_stats":null,"previous_names":["yschimke/compose-ai-tools"],"tags_count":101,"template":false,"template_full_name":null,"purl":"pkg:github/yschimke/compose-ai-tools","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yschimke%2Fcompose-ai-tools","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yschimke%2Fcompose-ai-tools/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yschimke%2Fcompose-ai-tools/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yschimke%2Fcompose-ai-tools/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yschimke","download_url":"https://codeload.github.com/yschimke/compose-ai-tools/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yschimke%2Fcompose-ai-tools/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34331812,"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-06-14T02:00:07.365Z","response_time":62,"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":["agent-skills","android","claude-code","claude-skills","compose-multiplatform","compose-preview","gradle-plugin","jetpack-compose","kotlin","skill-md","vscode-extension","wear-os"],"created_at":"2026-04-15T00:02:38.392Z","updated_at":"2026-06-14T18:01:10.494Z","avatar_url":"https://github.com/yschimke.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"# compose-ai-tools\n\n**[Documentation](https://yschimke.github.io/compose-ai-tools/)** —\ninstall, VS Code Marketplace, and one-page-per-product reference for\neach data extension.\n\nRender `@Preview` composables to PNG outside Android Studio, so AI coding\nagents can see what they're changing. Works with Jetpack Compose (Android,\nvia Robolectric) and Compose Multiplatform Desktop (via `ImageComposeScene`).\n\nRenders include\n[paused-clock animation captures](https://github.com/yschimke/skills/blob/main/skills/compose-preview/references/capture-modes.md#animations-and-the-paused-frame-clock-android-only)\n(GIF or single frame) and opt-in\n[ATF accessibility checks](https://github.com/yschimke/skills/blob/main/skills/compose-preview/references/a11y.md)\nwith annotated overlays.\n\nAlso renders [Android XML resources](https://github.com/yschimke/skills/blob/main/skills/compose-preview/references/resource-previews.md) —\nvector drawables, adaptive launcher icons, animated-vector drawables — and indexes the icon\nattributes in `AndroidManifest.xml` so tooling can link manifest lines to the same rendered PNG.\nModules without any matching resources self-no-op, so this comes along for free with the plugin.\n\n## The agent loop\n\nThese tools give AI coding agents a tight, token-frugal feedback loop over\nCompose UI — the way [Playwright](https://playwright.dev) gave web agents one\nover the DOM: act by a stable reference, observe structure rather than pixels,\nand turn exploration into durable tests. The capabilities below are exposed by\nthe preview daemon's MCP server (and, where noted, the `compose-preview` CLI);\nsee [`docs/daemon/MCP.md`](docs/daemon/MCP.md) for the full tool surface.\n\n- **Target by semantic ref, not pixels.** `interactive/input` and\n  `record_preview` accept a `target` (`testTag` / `role`+`text` / a stable\n  node `ref`) that the daemon resolves to the node's centre, so a click\n  survives layout changes instead of breaking on a coordinate. Works on\n  Android (Robolectric) and Desktop (Skiko).\n- **Token-frugal observation.** `render_preview observe=semantics|hash`\n  returns the `compose/semantics` tree + a hash + dimensions instead of a\n  base64 PNG — typically a few hundred tokens versus ~1.5k. Fetch pixels only\n  when you actually need to look.\n- **Semantics diff.** `diff_semantics` (MCP) and `compose-preview\n  diff-semantics` (CLI) diff two semantics trees and report what changed\n  *semantically* (text, label, role, testTag, overflow…), matched by stable\n  ref — a deterministic, pixel-free regression signal, the Compose analogue of\n  Playwright's aria-snapshot diff.\n- **Matrix render.** `render_matrix` (and the `compose-preview render-matrix`\n  CLI) renders one preview across a cross-product of\n  `device × locale × uiMode × fontScale` in a single call, returning a per-cell\n  hash and which cells changed — \"does this survive small screen + RTL + large\n  font?\" without N screenshots. Opt into a stitched contact-sheet image when you\n  want to eyeball every cell at once.\n- **Recording → test.** `record_preview emitTest=true` turns a scripted\n  interaction into a runnable Compose UI test (semantic targets become\n  `onNodeWithTag(...).performClick()` steps; each `recording.probe` is diffed\n  against the previous probe's captured semantics into `assertExists()` /\n  `assertDoesNotExist()` assertions).\n- **Structured failures.** A failed render reports a typed `kind` plus a\n  one-line fix hint for recognized signatures (classpath skew, Robolectric SDK\n  mismatch, missing `@Composable`, …) instead of an opaque message.\n\nCost budget for these in [`docs/TOKEN_USAGE.md`](docs/TOKEN_USAGE.md).\n\n## What it ships\n\n- **Agent skills** — the `compose-preview` and `compose-preview-review`\n  skill bundles live in\n  [`yschimke/skills`](https://github.com/yschimke/skills). Point any\n  agent that can fetch a URL at them; each skill is a complete\n  install-and-iterate playbook. Bootstrap a host machine (CLI + skills\n  in one shot) with the installer in\n  [`yschimke/skills`](https://github.com/yschimke/skills/blob/main/scripts/install.sh):\n\n  ```sh\n  curl -fsSL https://raw.githubusercontent.com/yschimke/skills/main/scripts/install.sh | bash\n  ```\n- **VS Code extension** — published to the\n  [VS Code Marketplace](https://marketplace.visualstudio.com/items?itemName=yuri-schimke.compose-preview)\n  and [Open VSX](https://open-vsx.org/extension/yuri-schimke/compose-preview)\n  (for VSCodium / Cursor / Windsurf). Install from inside the IDE: open\n  the Extensions view (⇧⌘X / Ctrl+Shift+X), search **Compose Preview**,\n  click *Install*. Source in [`vscode-extension/`](vscode-extension/).\n- **GitHub Actions** — composite actions for CI:\n  [`install`](.github/actions/install/) (CLI on `$PATH`),\n  [`apply`](.github/actions/apply/) (unified pipeline — baselines on push,\n  before/after PR comments, a11y + notification surfaces).\n\n## Setup\n\nThe plugin is published to [Maven Central](https://central.sonatype.com/artifact/ee.schimke.composeai/compose-preview-plugin)\n— no auth, no PAT.\n\n\u003c!-- x-release-please-start-version --\u003e\n```kotlin\n// \u003cmodule\u003e/build.gradle.kts\nplugins {\n    id(\"ee.schimke.composeai.preview\") version \"0.15.5\"\n}\n```\n\u003c!-- x-release-please-end --\u003e\n\nWorking examples: [`samples/android/build.gradle.kts`](samples/android/build.gradle.kts),\n[`samples/wear/build.gradle.kts`](samples/wear/build.gradle.kts),\n[`samples/cmp/build.gradle.kts`](samples/cmp/build.gradle.kts).\n\n### Zero-Code Integration (Alternative)\n\nYou can apply the plugin dynamically without modifying the project's source code, useful for AI agents on the CLI, in CI, or when exploring the tool without committing changes. The `compose-preview` CLI ships a bundled Gradle init script and passes it via `--init-script` on every invocation, so projects that already apply `com.android.application` / `com.android.library` / `org.jetbrains.compose` pick up the preview plugin without an edit to `build.gradle.kts`:\n\n```sh\ncompose-preview list                # scan @Preview annotations\ncompose-preview render              # render every @Preview to PNG\ncompose-preview render-matrix --id com.example.MyPreview --ui-mode light,dark --font-scale 1.0,2.0\n                                    # one preview across a device × locale × uiMode × fontScale grid\n```\n\nFor direct `./gradlew` use (e.g., a CI step that needs extra Gradle flags), materialise the same init script once and thread its path through each invocation:\n\n```sh\nINIT_SCRIPT=\"$(compose-preview init-script --path)\"\n./gradlew --init-script \"$INIT_SCRIPT\" :app:composePreviewDiscover\n./gradlew --init-script \"$INIT_SCRIPT\" :app:composePreviewRenderAll\n```\n\n\u003e **VS Code users:** the [`Compose Preview` extension](vscode-extension/) already auto-injects via `--init-script` on every Gradle invocation it makes — no extra setup needed.\n\nThe CLI's [auto-inject script](cli/src/main/kotlin/ee/schimke/composeai/cli/AutoInject.kt) detects projects that already declare the plugin (either literally as `id(\"ee.schimke.composeai.preview\") version \"...\"` or via a `gradle/libs.versions.toml` alias resolved through `alias(libs.plugins.\u003cx\u003e)`) and skips the classpath injection for those builds, so mixed setups work without conflicts.\n\nRequires Java 17+, Gradle 8.13+, AGP 8.13.0+ (Android), Kotlin 2.0.21+,\nCompose Multiplatform 1.10.3+ (Desktop). The bottom edge of the supported\nconsumer envelope is exercised on every push by the\n[`agp8-min` job](.github/workflows/integration.yml) against the fixture\nunder [`.github/ci/fixtures/agp8-min/`](.github/ci/fixtures/agp8-min/);\nthe project's own build runs on a newer toolchain (see\n[`docs/AGENTS.md`](docs/AGENTS.md)).\n\n## Samples\n\nSource under [`samples/`](samples/). Rendered baselines (PNGs and animation\nGIFs, regenerated on every push to `main`) are browsable inline on the\n[`compose-preview/main`](https://github.com/yschimke/compose-ai-tools/tree/compose-preview/main)\nbranch:\n\n- [`samples:android`](https://github.com/yschimke/compose-ai-tools/tree/compose-preview/main#samplesandroid) — phone, font-family showcase, scrolling captures, animation timelines.\n- [`samples:wear`](https://github.com/yschimke/compose-ai-tools/tree/compose-preview/main#sampleswear) — Wear OS Material 3 Expressive, `EdgeButton`, tile previews.\n- [`samples:cmp`](https://github.com/yschimke/compose-ai-tools/tree/compose-preview/main#samplescmp) — Compose Multiplatform Desktop.\n- [`samples:remotecompose`](https://github.com/yschimke/compose-ai-tools/tree/compose-preview/main#samplesremotecompose) — Remote Compose against `wear-compose-remote-material3`.\n- [`samples:xr-spatial`](https://github.com/yschimke/compose-ai-tools/tree/compose-preview/main#samplesxr-spatial) — Jetpack Compose for XR (`androidx.xr.compose`), 2D Home-Space fallback of `Orbiter` / `SpatialElevation` / `SpatialPanel` content.\n\nATF a11y findings for the same samples are on the\n[`compose-preview/a11y/main`](https://github.com/yschimke/compose-ai-tools/tree/compose-preview/a11y/main)\nbranch.\n\n## Integration previews\n\nThe [integration matrix](.github/workflows/integration.yml) renders the\nplugin against real-world external Compose projects on every push to `main`.\nEach render-enabled project publishes its own browsable\n`compose-preview/integration/\u003cslug\u003e` branch — same gallery layout as\n`compose-preview/main`, with a **CI notes** section recording any\nworkarounds the harness applied (consumer patches, stubbed credentials,\nnon-blocking status):\n\n- [`wear-os-samples` (ComposeStarter)](https://github.com/yschimke/compose-ai-tools/tree/compose-preview/integration/wear-os-samples) — full Android render + daemon round-trip, isolated-projects + configuration-cache.\n- [`wear-os-samples` (WearTilesKotlin)](https://github.com/yschimke/compose-ai-tools/tree/compose-preview/integration/wear-tiles) — Wear Tiles render path (`kind: TILE`).\n- [`adaptive-apps-samples` (AdaptiveJetStream)](https://github.com/yschimke/compose-ai-tools/tree/compose-preview/integration/jetstream-xr) — XR spatial Compose, rendered on the `androidx.xr.compose` alpha14 baseline.\n\n## Agent PR hall of fame\n\nReal-world PRs opened by AI coding agents that used `compose-preview` to\nverify their changes.\n\n\u003c!-- Add interesting agent PRs here as they happen — link + one-liner. --\u003e\n\n- [`yschimke/meshcore-mobile#36`](https://github.com/yschimke/meshcore-mobile/pull/36) — renders Play Store listing screenshots (phone + 7\"/10\" tablet) directly from `Play Store — …` `@Preview` composables, replacing hand-crafted PNGs.\n\nHave one to add? Open a PR or [an issue](https://github.com/yschimke/compose-ai-tools/issues/new).\n\n## More\n\n- [Documentation site](https://yschimke.github.io/compose-ai-tools/) — installation, VS Code Marketplace, and the per-product data-extension reference.\n- [How it works](docs/HOW_IT_WORKS.md) — discovery, renderer, caching, project structure, plugin configuration.\n- [CI install action](.github/actions/install/README.md) — pin the CLI on `$PATH` in any GitHub Actions job, with version-catalog + Renovate recipes.\n- [Cloud sandbox setup](https://github.com/yschimke/skills/blob/main/skills/compose-preview/references/agent-cloud.md) — Claude Code on the web, network allowlist.\n- [CI workflows](https://github.com/yschimke/skills/blob/main/skills/compose-preview-review/references/ci-previews.md) — `compose-preview/main` baselines, PR diff comments.\n- [Development](docs/DEVELOPMENT.md) — building plugin, CLI, and extension from source; consuming `-SNAPSHOT` builds.\n- [Architecture (contributor)](docs/AGENTS.md) — class-by-class map of the four-stage pipeline.\n- [Releases](https://github.com/yschimke/compose-ai-tools/releases) ·\n  [Changelog](CHANGELOG.md) ·\n  [License (Apache 2.0)](LICENSE)\n\n## Reusable Codex PR review workflow (Preview-gated)\n\nUse `.github/workflows/codex-pr-review-reusable.yml` to run AI PR review **only after** preview generation succeeds and with both code + visual context. The reusable workflow supports Codex, Claude, or Gemini based on which API key is configured (exactly one).\n\n### Minimal caller setup\nThis repository wires the reusable workflow in `.github/workflows/codex-pr-review.yml` using a `preview` job plus a thin `uses:` call to the reusable workflow.\n\nIn this repository the unified `.github/workflows/compose-preview.yml` runs on every push to `main`, every PR, and `workflow_dispatch`. Consumer repos can split that into separate workflows (or keep one workflow per surface) based on their needs.\n\n\n```yaml\nname: PR Review (Codex + Preview)\n\non:\n  pull_request:\n    types: [opened, synchronize, reopened]\n\njobs:\n  preview:\n    runs-on: ubuntu-latest\n    outputs:\n      preview_status: ${{ job.status }}\n    steps:\n      - uses: actions/checkout@v4\n      - run: ./gradlew :app:composePreviewRenderAll\n      - uses: actions/upload-artifact@v4\n        with:\n          name: compose-preview-images\n          path: app/build/compose-previews/renders\n      - uses: actions/upload-artifact@v4\n        with:\n          name: compose-preview-diff-images\n          path: app/build/compose-previews/diffs\n      - uses: actions/upload-artifact@v4\n        with:\n          name: compose-preview-metadata\n          path: app/build/compose-previews/**/*.json\n\n  codex-review:\n    needs: [preview]\n    uses: yschimke/compose-ai-tools/.github/workflows/codex-pr-review-reusable.yml@main\n    with:\n      preview_status: ${{ needs.preview.result }}\n      strict_mode: true\n    secrets:\n      codex_api_key: ${{ secrets.CODEX_API_KEY }}\n      claude_api_key: ${{ secrets.CLAUDE_API_KEY }}\n      gemini_api_key: ${{ secrets.GEMINI_API_KEY }}\n      github_token: ${{ secrets.GITHUB_TOKEN }}\n```\n\n### Artifact contract\n\n- Agent selection is key-driven: set exactly one of `codex_api_key`, `claude_api_key`, or `gemini_api_key`.\n- Codex has a built-in default command. Claude/Gemini require `claude_review_command` / `gemini_review_command` inputs unless you wrap them in your own caller.\n- `compose-preview-images`: rendered head/PR preview images.\n- `compose-preview-diff-images`: visual diffs (baseline vs PR/head), if your preview pipeline generates them.\n- `compose-preview-baseline`: optional baseline images used to generate diffs.\n- `compose-preview-metadata`: preview index and mapping files (for example: preview id → file path/module).\n\n### Runtime/toolchain provided by reusable workflow\n\n- Java 21 (`actions/setup-java`, `JAVA_HOME` from the action).\n- Android SDK (`android-actions/setup-android`).\n- `compose-preview-review` skill installation from `yschimke/skills`.\n- Code diff capture (`git diff`) plus artifact download for visual review.\n\n### Failure modes / troubleshooting\n\n- **Preview failed/cancelled/skipped**: workflow posts a blocked comment and does not run Codex visual review.\n- **Artifacts missing**: workflow posts a blocked comment with “missing context” details.\n- **Strict mode enabled** + blocking findings: reusable workflow fails its check.\n- **PR branch update** (`update_pr_branch`, default `true`): workflow attempts to commit `.codex/review-output/{codex-review.md,codex-review.json}` to the PR branch; for fork PRs or restricted tokens it skips with a warning.\n- **No preview diffs available**: Codex still reviews code + available preview images and explicitly marks missing visual-diff context.\n\n### Optional integration patterns\n\n- `needs:` pattern (shown above): same workflow, same run.\n- `workflow_run` pattern: trigger a second workflow after preview workflow completion and pass `preview_status: success` plus artifact names into the reusable workflow call.\n\n### Example review comment template\n\n```md\n## Codex PR Review\n\n### Code findings\n- [blocking] `ui/ProfileCard.kt:84` Null-state branch removed; can crash in empty profile payload.\n- [warning] `ui/Theme.kt:42` Hard-coded color bypasses design token.\n\n### Preview findings\n- [blocking] `ProfileCard_Default.png` text overlaps avatar at 320dp width.\n- [warning] `SettingsScreen_Dark.png` contrast drop on secondary action.\n\n### Missing context / blocked checks\n- Baseline metadata for `WearSummaryPreview` missing.\n- Visual diff for `TabletLandscape` not present in uploaded artifacts.\n```\n\n### Validation recipe with intentional bad UI change\n\n1. Intentionally regress a composable (for example, shrink parent width and increase fixed text size to force clipping).\n2. Run your preview job to regenerate preview images and visual diffs.\n3. Open/update a PR and confirm:\n   - Preview job succeeds.\n   - Reusable Codex workflow runs after preview (`needs`/`workflow_run` gate).\n   - PR comment includes both code and preview findings.\n   - In strict mode, blocking visual regression findings fail the check.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyschimke%2Fcompose-ai-tools","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyschimke%2Fcompose-ai-tools","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyschimke%2Fcompose-ai-tools/lists"}