git:20260927.920475f to git:20260927.8c42f9b

71 added, 440 removed. Audit B to B.

---
name: compose-preview
- description: Render Compose @Preview functions to PNG outside Android Studio. Use this to verify UI changes, iterate on designs, and compare before/after states across Android (Jetpack Compose) and Compose Multiplatform Desktop projects.
+ description: Render a Jetpack Compose or Compose Multiplatform @Preview to PNG in one call (MCP render_preview, or the compose-preview CLI) and look at it. Use to verify UI changes, iterate on designs, and compare before/after.
---
# Compose Preview
- Render `@Preview` composables to PNG images without launching Android Studio.
- Works on both Android (Jetpack Compose via Robolectric) and Compose Multiplatform
- Desktop (via `ImageComposeScene` + Skia).
-
- Maintained at [github.com/yschimke/skills](https://github.com/yschimke/skills)
- under `skills/compose-preview/`. The CLI, Gradle plugin, and renderer ship from
- [github.com/yschimke/compose-ai-tools](https://github.com/yschimke/compose-ai-tools);
- this skill documents how an agent drives them.
-
- Run `compose-preview --version` to see the installed CLI bundle, `compose-preview doctor`
- to compare against the latest release (warns when the local copy trails), and
- `compose-preview update` to re-run the bootstrap installer.
-
- ## Non-negotiable agent loop
-
- - After changing Compose UI, render the affected preview and **look at the
- resulting image on the surface where the person will judge it**. Use the
- typed MCP render tool when available, or the CLI and its reported `pngPath`;
- then open that image with the host's image viewer. Source, semantics, hashes,
- and a successful build are useful checks, but none of them proves what the
- UI looks like.
- - Showable evidence is part of the result. Keep the returned image or file path
- so the person can inspect the same render. If the harness cannot display the
- render, say which surface is unavailable and why; do not describe an inferred
- visual result as something you saw.
- - Prefer typed MCP tools and their published input/output schemas. Use a
- dedicated validation tool when the server exposes one. Do not hand-edit
- design or render-manifest JSON as a substitute for a typed operation; if a
- required typed or validation capability is absent, name that gap plainly.
-
- ## What this skill provides
-
- - A Gradle plugin (`ee.schimke.composeai.preview`) that discovers `@Preview`
- annotations from compiled classes and registers rendering tasks.
- - A `compose-preview` CLI that drives the Gradle build via the Tooling API
- and surfaces rendered PNG paths.
- - A VS Code extension with a preview panel, CodeLens and hover actions on
- `@Preview` functions, and commands for rendering all or a single file.
-
- ## Interactive MCP capabilities
-
- - The shared viewer, `resource_link` results, file-path lookup, prompts, and
- `render_matrix` variant choice require a compose-preview-server release after
- v3.74.0 (none has shipped them yet). Until then, treat them as absent and use
- text/image/path results. Use only what the server advertises; details in
- [mcp.md](./references/mcp.md#draft-viewer-prompts-and-fallbacks) and
- [catalog-mcp.md](./references/catalog-mcp.md#draft-viewer-and-interactive-capability-fallbacks).
-
- ## Gradle tasks
-
- Applied to each module that declares the plugin:
-
- | Task | Purpose |
- |------|---------|
- | `:<module>:composePreviewDiscover` | Scan compiled classes, emit `build/compose-previews/previews.json`. |
- | `:<module>:composePreviewRenderAll` | Discover + render every `@Preview` to PNG under `build/compose-previews/`. |
- | `:<module>:composePreviewDiscoverAndroidResources` | Walk `res/drawable*` + `res/mipmap*`, parse `AndroidManifest.xml`, emit `build/compose-previews/resources.json`. See [references/resource-previews.md](./references/resource-previews.md). |
- | `:<module>:composePreviewRenderAndroidResources` | Render every discovered XML drawable / mipmap to PNG / GIF under `build/compose-previews/renders/resources/`. |
-
- All Gradle-cacheable with strict configuration caching — unchanged inputs
- produce no re-work.
-
- ## CLI
-
- The CLI auto-detects the Gradle project root (walks up for `gradlew`) and, by
- default, every module that has the plugin applied.
-
- ```
- compose-preview <command> [options]
-
- Commands:
- show Discover + render previews; print id, path, sha256, changed flag
- list List discovered previews
- render Render previews; with --output copies a single match to disk
- a11y Render previews and print ATF accessibility findings
- extensions run a11y-annotated-preview.render
- One-shot a11y hierarchy + ATF + annotated overlay render
- doctor Verify Java 17+ + project compatibility (run before Setup)
- rc Remote Compose JSON codec, offline (compile | dump | header).
- `rc dump <doc.rc>` makes a captured .rc readable and diffable;
- `rc compile <doc.json>` builds one from AndroidX's authoring
- JSON. The two dialects are NOT inverses — see
- references/remote-compose.md before assuming a round trip.
-
- Options:
- --module <name> Target a single module (default: auto-detect)
- --variant <variant> Android build variant (default: debug)
- --filter <pattern> Case-insensitive substring match on preview id.
- Narrows what Gradle renders, not just what prints
- --id <exact> Exact match on preview id. Also narrows the render
- --json Emit JSON (show, list)
- --output <path> Copy matched preview PNG to this path (render)
- --progress Print per-task milestone/heartbeat lines to stderr
- --verbose, -v Full Gradle build output (implies --progress)
- --timeout <seconds> Gradle build timeout (default: 300)
- --force=<reason> Sanctioned escape hatch for stale renders: passes
- --rerun-tasks to Gradle. Does NOT run :clean and
- does NOT touch build/classes/. Logs the reason and
- points at issue #924 — please report.
- ```
-
- OSC 9;4 terminal progress (native taskbar/tab progress bar) is on by default
- in a TTY and auto-disables when stdout is piped. Textual progress lines are
- opt-in via `--progress`.
-
- Exit codes: `0` success, `1` build failure, `2` render failure, `3` no previews.
-
- `--json` output per entry includes the full `PreviewParams` (device, widthDp,
- heightDp, fontScale, uiMode, …), the absolute `pngPath`, the `sha256` of
- the PNG bytes, and a `changed` boolean computed against the previous
- invocation. State is persisted per-module under
- `<module>/build/compose-previews/.cli-state.json` and gets wiped by
- `./gradlew clean`.
-
- ### The `counts` block, and what "no PNG" means
-
- `show --json` wraps the rows in a versioned envelope whose `counts` block
- summarises the run, so an agent can decide what to read without walking every
- entry:
-
- ```json
- "counts": { "total": 37, "changed": 1, "unchanged": 33, "missing": 1, "skipped": 2 }
- ```
-
- The four buckets **partition** `total` — every preview is in exactly one, and
- `changed + unchanged + missing + skipped == total`. What each one means:
-
- | Bucket | Meaning |
- |--------|---------|
- | `changed` | At least one capture's `sha256` differs from the previous run. These are the PNGs worth reading. |
- | `unchanged` | Rendered, and pixel-identical to last time. |
- | `missing` | **No PNG, and that is a render failure** — the set `--missing-renders` gates on. Worth investigating. |
- | `skipped` | No PNG, and the miss is *expected*: every absent capture is declared `optional`, or the preview is a kind that never emits a PNG (an `@XrSubspacePreview` composite). Not a failure. |
-
- The same distinction shows up in the text output's per-row tags, so don't read
- a bare `[no PNG]` off every empty row:
-
- ```
- MainActivity (activity__MainActivity) [no PNG]
- RedirectUriReceiverActivity (activity__RedirectUriReceiverActivity) [no PNG, optional]
- SpatialPanelPreview (p.SpatialPanelPreview) [no PNG, by design]
- ```
-
- Only `[no PNG]` is a failure, and it marks exactly the previews the
- "Render task completed but produced no PNG for N of M preview(s)" summary
- enumerates underneath. A `[no PNG, optional]` row is a best-effort capture that
- was never guaranteed to render — a non-launcher activity that needs intent
- extras discovery can't guess, a desktop `@ColorCatalog` sheet — so treat it as
- information, not as something to fix. Per capture, the `optional` boolean on
- each entry in `captures[]` carries the same fact in the JSON.
-
- `skipped` and the qualified tags arrived together; a CLI bundle predating them
- tags every empty row `[no PNG]` and emits no `skipped` key, and its buckets do
- not add up to `total`. Check `compose-preview --version` before relying on a
- residual computed from `counts`.
-
- ## Iterating on a design
-
- `list` → edit → `show --json` → view the PNGs whose `changed: true`. Gradle
- caching means re-renders only redo what changed; the `changed` flag lets
- agents skip opening PNGs that did not move. Always view the PNG after a UI
- change on the surface where the person will judge it. If that surface is not
- available to the current harness, say so explicitly; do not assume the change
- looks correct.
-
- ### Render only the preview you're iterating on
-
- `--filter` / `--id` narrow **what Gradle renders**, not just what gets
- printed. Asking for one preview used to render the whole module — measured at
- 317s against 3s on the CLI's own 64-preview sample — so this is the flag to
- reach for when working on a single screen, rather than `--force` or deleting
- `renders/` by hand.
-
- ```sh
- compose-preview show --json --filter HomeScreen
- ```
-
- What a narrowed run does to everything else:
-
- - **Previews outside the request keep whatever PNG the previous run left on
- disk**; on a clean tree they simply have none. `show` scopes its counts to
- the request for that reason, so don't read a smaller total as previews
- having disappeared.
- - **Change detection is unaffected.** A narrowed run carries the skipped
- previews' shas forward, so a later full render doesn't report them all as
- `changed`.
- - **A filtered render is deliberately not build-cacheable**, so it can't
- poison a clean checkout — and because the filter is a task input, an
- unfiltered run afterwards re-renders everything.
- - **`render --bundle` still renders the full module by design.** A bundle
- omits previews that have no PNG, so a narrowed bundle would ship exactly
- the one preview you asked for and nothing else.
-
- For a long-lived **interaction** loop — clicking/typing by semantic ref
- (not pixels), checking "did it change?" without reading a PNG, and diffing
- semantics instead of pixels — see the Playwright-style, token-frugal
- [references/agent-loop.md](./references/agent-loop.md).
-
- ### Don't spell render filenames by hand — read them from the manifest
-
- A rendered file is named `<readable>-<digest>.<ext>`:
-
- ```
- renders/ActivityListPreview_Devices_Large_Round-4f9c2a17.png
- └──────────── readable ──────────────┘ └ digest ┘
- ```
-
- `<readable>` is the function name plus any `@Preview(name = …)` variant, with
- non-alphanumeric runs collapsed to `_`. `<digest>` is 8 hex characters derived
- from the preview id. It is what makes the name unique and stable: adding or
- renaming any *other* preview never renames this one, and two previews can never
- land on the same file — including on case-insensitive filesystems, and including
- names that differ only in punctuation.
-
- The practical consequence: **you cannot reconstruct a filename from a preview
- id, and you shouldn't try.** Read `renderOutput` off the preview in
- `previews.json` (or the `show --json` output), which is authoritative. Structural
- suffixes are appended after the digest — `…-4f9c2a17_SCROLL_top.png`,
- `…-4f9c2a17_PARAM_4.png` — so a glob on the readable prefix also works when you
- just need "every capture of this preview".
-
- Preview **ids** are unaffected and keep their full FQN
- (`com.example.PreviewsKt.HomeScreenPreview`) — `--filter` / `--id`, history
- folders and CLI state all still key by id.
-
- ## Vector (SVG) output, not just PNGs
-
- The renderer can export a preview as **scalable vector art** as well as a
- raster: `compose/semantics-wireframe` (a schematic structural wireframe) and
- `compose/figma-svg` (a **layered, editable** design-fidelity SVG — each
- composable a named `<g id>` layer, with real fills/strokes, editable text, and
- token bindings). Reach for these when the target scales to arbitrary sizes or
- must land as named layers in a design tool rather than flat pixels — they are
- what the design-catalog/Figma skills import as crisp vectors. See
- [references/data-products.md § SVG vector output](./references/data-products.md).
-
- ## Running other Gradle builds (use build-brief)
-
- `compose-preview` is the right tool for **rendering previews** — prefer it
- whenever the goal is to see a composable. For any **other** Gradle work an
- agent needs to run directly (`build`, `assemble`, `test`,
- `connectedCheck`, a custom task), reach for
- [build-brief](https://github.com/static-var/build-brief) (`bb`) instead of
- raw `./gradlew`. It wraps `gradle`/`./gradlew`, preserves the exit code,
- keeps the full raw log on disk, and trims terminal output to failed
- tasks/tests, warnings, build-scan URLs, and final status — typically a
- 90%+ token reduction on noisy builds.
-
- ```sh
- # Install once (Linux/macOS); self-contained Go binary, no JDK of its own.
- curl -fsSL https://bb.staticvar.dev/install.sh | bash
-
- build-brief test
- build-brief ./gradlew assembleDebug
- build-brief gradle build
- ```
-
- Guidance for agents: **prefer `compose-preview` for previews**; use
- `build-brief` whenever you'd otherwise invoke Gradle directly so the build
- output stays cheap to read. See
- [references/agent-cloud.md](./references/agent-cloud.md) for the cloud
- install/allowlist details.
-
- ## Designing composables for previewability
-
- `@Preview` only calls composables with zero arguments (or all-default), so
- anything taking a `ViewModel`, repository, or DI-injected service can't be
- previewed directly. Apply **state hoisting**: split each screen into a
- stateful wrapper (wires runtime deps) and a stateless inner composable that
- takes state + callbacks. Preview the stateless layer with hand-rolled
- fixtures.
-
- **Agent guidance:** if asked to iterate on a composable that accepts a
- ViewModel or injected dependency, first propose extracting a stateless
- inner composable and preview that. The one-time extraction unlocks the
- fast `compose-preview` iteration loop for every future change on that
- screen. See [references/state-hoisting.md](./references/state-hoisting.md) for
- the pattern with code.
-
- ## Setup
-
- The plugin is on Maven Central — most projects already have `mavenCentral()`
- in their plugin repositories, so no credentials or extra registry config.
-
- **Agents: check first, install only when missing.** Run
- `compose-preview --version && compose-preview doctor` to see whether the CLI
- is already available — if it is, you're done. Don't blindly re-run the
- installer between previews; the script is idempotent for same-version runs
- but still does network probes.
-
- If `compose-preview` isn't on `$PATH`, install it in this order:
-
- 1. **Run the stub bundled with this skill** (preferred — no Node needed). Its
- first run downloads the real CLI, links `~/.local/bin/compose-preview`,
- adds `~/.local/bin` to bash/zsh/fish startup files, and re-execs:
-
- ```sh
- bash "$SKILL_DIR/scripts/compose-preview" --version
- ```
-
- (`$SKILL_DIR` is the absolute path to this skill bundle, e.g.
- `~/.agents/skills/compose-preview/` or
- `~/.claude/plugins/yschimke-skills/skills/compose-preview/`.)
- 2. **No bundle on disk?** Install the skills with the
- [skills CLI](https://skills.sh), then run the stub:
-
- ```sh
- npx skills add yschimke/skills --global --yes --skill compose-preview --skill compose-ui-builder
- ~/.agents/skills/compose-preview/scripts/compose-preview --version
- ```
- 3. **No Node?** Use the canonical installer (CLI + the default skills in one
- step; `--all-skills` for every skill;
- add `-s -- --no-modify-path` to leave shell startup files alone):
-
- ```sh
- curl -fsSL https://raw.githubusercontent.com/yschimke/skills/main/scripts/install.sh | bash
- ```
-
- Then `compose-preview doctor`. A new shell picks up `~/.local/bin`. To update:
- `compose-preview update` for the CLI (and PATH), `npx skills update` for
- npx-installed skills; re-running the curl installer also upgrades (pin a
- version with `… | bash -s -- 1.79.0`).
-
- `doctor` verifies Java 17+ on `PATH` (JDK 21/25 are fine — the renderer is
- compiled to JDK 17 bytecode). If the install path isn't on `PATH`, the
- script prints the exact command to add it.
-
- From a Compose project root, install the MCP server descriptors:
-
- ```sh
- compose-preview mcp install # auto-detects Antigravity
- compose-preview mcp install --antigravity # force the Antigravity config write
- ```
-
- On Antigravity, Claude Code or Codex, the
- [`compose-ag-plugin`](https://github.com/yschimke/compose-ag-plugin#install)
- plugins are an alternative to `mcp install`. `compose-preview` wires this MCP
- server, and `compose-catalogs` wires the hosted catalog and UI Builder. The
- install commands for each harness are in this repo's
- [README](https://github.com/yschimke/skills#per-harness-plugins). Use one route
- or the other, not both: two registrations of the same server give you two copies
- of every tool.
-
- `mcp install` is a one-time bootstrap. If a render misbehaves, do **not**
- re-run it and do **not** kill the daemon — run `compose-preview mcp doctor`
- first and follow the verdict it prints. The supervisor respawns daemons
- automatically on classpath changes. See
- [references/mcp.md § Troubleshooting](./references/mcp.md#troubleshooting-first--when-not-to-act).
-
- Apply the plugin in `<module>/build.gradle.kts` (replace the version with
- the latest from
- [compose-ai-tools releases](https://github.com/yschimke/compose-ai-tools/releases/latest)):
+ Render `@Preview` composables to PNG without Android Studio (Android via
+ Robolectric, CMP Desktop via Skia). CLI, Gradle plugin and renderers ship from
+ [compose-ai-tools](https://github.com/yschimke/compose-ai-tools); the MCP server
+ from [compose-preview-server](https://github.com/yschimke/compose-preview-server).
- ```kotlin
- plugins {
- id("ee.schimke.composeai.preview") version "<latest>"
- }
+ ## Render first
- composePreview {
- variant.set("debug") // Android build variant (default: "debug")
- sdkVersion.set(35) // Robolectric SDK version (default: 35)
- enabled.set(true) // set false to skip task registration
- }
- ```
+ With the local MCP server attached (compose-preview-server 3.78.0+), one call
+ is enough. **Do not explore first.** No `list_projects`, `status`, grepping
+ source, or running Gradle before the first render; the server registers the
+ workspace itself (MCP roots or cwd).
- `sdkVersion` auto-detects from `android.compileSdk` when unset, but the render
- range is narrower than the compile range: **SDK > 35 requires JDK 21+**. On a
- project that compiles against a newer SDK (37 is current for the Android
- samples) the build fails at configuration time with
- `sdkVersion = N is outside the supported range`. Pin it explicitly, or run the
- build on JDK 21+.
+ 1. **Render.** `render_preview` with `preview: "<FunctionName>"` (the function
+ name, or an FQN suffix like `home.HomeScreenPreview`). If it returns
+ `otherMatches`, those are the other variants; pick one and render again only
+ if the person asked about it.
+ 2. **Look.** Open the image yourself. Clients that read files should pass
+ `inline=false`: the result is JSON `{uri, pngPath, widthPx, heightPx, sha256}`,
+ and you read `pngPath` with your file reader (R1). Describe only what you
+ saw. If you can't view images here, say so plainly. Don't infer.
+ 3. **Reply** with what the render shows and keep `pngPath` so the person can
+ open the same image.
- ### Zero-Code Integration (Alternative)
+ **After a source edit**, call `render_preview` again. `notify_file_changed` is
+ optional. **If the result says it is stale**, make exactly one more call with
+ `force: {"reason": "<why>"}`. **Never** run `./gradlew`, `clean`, or delete
+ `build/` dirs to chase a render; if a forced render is still wrong, read
+ [mcp.md § Troubleshooting](./references/mcp.md#troubleshooting-first--when-not-to-act)
+ (start with `compose-preview mcp doctor`).
- You can apply the plugin dynamically without modifying the project's source code by using a Gradle init script. This is useful for agents operating in environments where they shouldn't or cannot modify the build files directly.
+ **Cheaper looks.** `observe` defaults to semantics (a cheap text tree). Pass
+ `observe=png` for pixels and `observe=hash` for "did it change?" sweeps across
+ many previews. Add `details: ["a11y", "layout"]` for accessibility findings or
+ the layout tree alongside the render.
- > **VS Code users:** the [`Compose Preview` extension](https://github.com/yschimke/compose-preview-vscode) already passes a bundled init script via `--init-script` on every Gradle invocation it makes, so its renders pick up Android / Compose projects with no extra setup. The instructions below are for CLI and CI flows that go through `./gradlew` directly.
+ **No MCP tool?** Use the CLI: `compose-preview show --json --filter <Name>`,
+ then read the entry's `pngPath`. Stale: `--force=<reason>`, once. See
+ [cli.md](./references/cli.md).
- Create a file named `~/.gradle/init.d/compose-ai-tools.gradle` with the following content:
+ **Not previewable** (takes a ViewModel or injected service)? Propose extracting
+ a stateless inner composable and preview that
+ ([state-hoisting.md](./references/state-hoisting.md)).
- ```groovy
- allprojects {
- buildscript {
- repositories {
- gradlePluginPortal()
- mavenCentral()
- }
- dependencies {
- classpath "ee.schimke.composeai.preview:ee.schimke.composeai.preview.gradle.plugin:latest.release"
- }
- }
+ ## Install / update (only if missing)
- afterEvaluate { project ->
- if (System.getenv("COMPOSE_AI_TOOLS") == "true") {
- if (project.plugins.hasPlugin("com.android.application")) {
- if (!project.plugins.hasPlugin("ee.schimke.composeai.preview")) {
- project.pluginManager.apply("ee.schimke.composeai.preview")
- println "Applied ee.schimke.composeai.preview to ${project.name} via init script"
- }
- }
- }
- }
- }
- ```
+ Check with `compose-preview --version`. Install the skills and CLI:
- To enable it, set the environment variable:
```sh
- export COMPOSE_AI_TOOLS=true
+ npx skills add yschimke/skills --global --yes --skill compose-preview --skill compose-ui-builder
+ # No Node:
+ curl -fsSL https://raw.githubusercontent.com/yschimke/skills/main/scripts/install.sh | bash
```
- CMP Desktop projects additionally need
- `implementation(compose.components.uiToolingPreview)` — the bundled `@Preview`
- annotation has `SOURCE` retention and is invisible to classpath scanning
- otherwise.
-
- The Android variant relies on Robolectric with native graphics; the plugin
- takes care of the relevant test/tooling dependencies. Agents MUST NOT run
- internal tasks like `collectPreviewInfo` — they're wired by the plugin itself.
+ Update with `compose-preview update` (skills: `npx skills update`). Plugin
+ setup, MCP registration, and the Gradle init script are in
+ [setup.md](./references/setup.md).
- ## Reference docs
+ ## Reference index
- Loaded on demand. Read only what the current task needs.
+ Read only what the task needs.
- | Path | When to read |
+ | Topic | Read |
|---|---|
- | [references/permissions.md](./references/permissions.md) | Setting up agent allowlists; staging PNGs outside `build/`. |
- | [references/server-access.md](./references/server-access.md) | Getting into a gated `serve` deployment: ask for a temporary scoped grant with `compose-preview auth request`, relay the link + verification code to a human, and revoke when done — instead of asking for the server's own `--token`. |
- | [references/runtime-permissions.md](./references/runtime-permissions.md) | Pinning Android runtime permissions per render via `renderNow.overrides.permissions`; reading the `compose/permissions` data product. |
- | [references/state-hoisting.md](./references/state-hoisting.md) | Full state-hoisting pattern with code examples. |
- | [references/override-knobs.md](./references/override-knobs.md) | Author-declared editable values (`previewOverride*`): re-render a published bundle with new text / colours / counts and no source rebuild, and declare a closed value set so an axis shows its alternatives instead of a bare text field. |
- | [references/capture-modes.md](./references/capture-modes.md) | Multi-preview annotations, `@AnimatedPreview` GIFs, `@SettledPreview` for content that arrives late, MCP scripted recordings, paused-clock snapshots, scrolling captures. |
- | [references/a11y.md](./references/a11y.md) | ATF accessibility checks (`compose-preview a11y`). |
- | [references/data-products.md](./references/data-products.md) | Structured per-render data (a11y findings + hierarchy, layout tree, recomposition heat-map, editable `compose/figma-svg` + wireframe **SVG vector** export, …) via MCP tools and on-disk Gradle output. |
- | [references/mcp.md](./references/mcp.md) | Driving compose-preview from an MCP-aware agent host (push notifications, multi-workspace, in-process server bundled in the CLI). The **local** surface — daemons on your machine. |
- | [references/catalog-mcp.md](./references/catalog-mcp.md) | The **remote** surface: a `compose-preview serve` deployment's own MCP endpoint (`POST /mcp`, from [compose-preview-server](https://github.com/yschimke/compose-preview-server)). Discover and render published catalogs with no checkout — the tool table, the `request_access` / `poll_access` handshake, snapshot vs made-to-order lanes, and the render timeline. |
- | [references/agent-loop.md](./references/agent-loop.md) | Playwright-style, token-frugal interaction loop: target by semantic ref (not pixels, Desktop + Android), `observe=semantics\|hash`, `diff_semantics`, `render_preview crop` (one element), `render_matrix`, `record_preview emitTest=true`, and typed render-failure `kind`s. |
- | [references/cmp-shared.md](./references/cmp-shared.md) | Compose Multiplatform `:shared` modules (`commonMain` previews via Desktop pipeline). |
- | [references/resource-previews.md](./references/resource-previews.md) | Android XML resources (`<vector>`, `<animated-vector>`, `<adaptive-icon>`). |
- | [references/wear-ui.md](./references/wear-ui.md) | Rendering and verifying Wear UI; API and migration choices defer to Android's official Wear Compose M3 skill. |
- | [references/wear-tiles.md](./references/wear-tiles.md) | Wear Tiles (protolayout, not Compose). |
- | [references/remote-compose.md](./references/remote-compose.md) | Remote Compose dialect, `RemoteDocument`, the wrapper + connector requirement for recorded `.rc` export, and the JSON format — authoring JSON in, document JSON out, and `compose-preview rc`. |
- | [references/agent-cloud.md](./references/agent-cloud.md) | Running compose-preview in Claude Code cloud sandboxes (allowlist, JDK, install paths). |
- | [references/vscode.md](./references/vscode.md) | VS Code extension (humans, not agents). |
-
- ## Related skill
+ | Install, update, apply the Gradle plugin, `mcp install`, zero-code init script | [setup.md](./references/setup.md) |
+ | CLI commands, `--filter`/`--id`/`--force`, `counts` buckets, render filenames, SVG output, Gradle tasks, `build-brief` for non-preview builds | [cli.md](./references/cli.md) |
+ | Local MCP server: tools, history (`history_list`/`history_diff`), multi-workspace, **troubleshooting** | [mcp.md](./references/mcp.md) |
+ | Interaction loop: semantic refs, `observe` modes, `diff_semantics`, crop, `render_matrix` (variants/matrix), record → test, failure `kind`s | [agent-loop.md](./references/agent-loop.md) |
+ | Accessibility (ATF, `compose-preview a11y`) | [a11y.md](./references/a11y.md) |
+ | Per-render data (a11y, layout, recomposition, SVG) | [data-products.md](./references/data-products.md) |
+ | Multi-preview, GIFs, `@SettledPreview`, scrolling captures | [capture-modes.md](./references/capture-modes.md) |
+ | Wear Compose UI / Wear Tiles | [wear-ui.md](./references/wear-ui.md), [wear-tiles.md](./references/wear-tiles.md) |
+ | CMP `:shared` modules | [cmp-shared.md](./references/cmp-shared.md) |
+ | Android XML drawables / icons | [resource-previews.md](./references/resource-previews.md) |
+ | Runtime permissions per render | [runtime-permissions.md](./references/runtime-permissions.md) |
+ | Editable override knobs | [override-knobs.md](./references/override-knobs.md) |
+ | Display filters | [display-filters.md](./references/display-filters.md) |
+ | Remote Compose, `compose-preview rc` | [remote-compose.md](./references/remote-compose.md) |
+ | Remote catalog MCP (`serve`, no checkout) | [catalog-mcp.md](./references/catalog-mcp.md) |
+ | Gated server access (`compose-preview auth request`) | [server-access.md](./references/server-access.md) |
+ | Agent allowlists, staging PNGs | [permissions.md](./references/permissions.md) |
+ | Cloud sandboxes (Claude Code, Codex) | [agent-cloud.md](./references/agent-cloud.md), [claude-cloud.md](./references/claude-cloud.md) |
+ | VS Code extension (humans) | [vscode.md](./references/vscode.md) |
- PR-review workflows live in the sibling
- [**compose-preview-review** skill](../compose-preview-review/SKILL.md):
- authoring agent-opened PRs, and reviewing UI PRs locally (base + head
- render, diff, text comment). Wiring the CI that does this automatically —
- `compose-preview/main` baselines, PR-comment GitHub Actions, the fork-safe
- two-stage split — is the
- [**compose-preview-ci** skill](../compose-preview-ci/SKILL.md).
- They are opt-in: add one with `npx skills add yschimke/skills --global --yes
- --skill <name>` (or, without Node, the
- [`scripts/install.sh`](https://raw.githubusercontent.com/yschimke/skills/main/scripts/install.sh)
- fallback with `--skills <name>`).
+ **CI and PR review** live in opt-in sibling skills:
+ [compose-preview-ci](../compose-preview-ci/SKILL.md) (baselines, PR-comment
+ Actions) and [compose-preview-review](../compose-preview-review/SKILL.md)
+ (base vs. head render and diff). Add one with
+ `npx skills add yschimke/skills --global --yes --skill <name>`.