Gradle-mcp verifying_compose_ui
install
source · Clone the upstream repo
git clone https://github.com/rnett/gradle-mcp
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/rnett/gradle-mcp "$T" && mkdir -p ~/.claude/skills && cp -r "$T/src/main/skills/verifying_compose_ui" ~/.claude/skills/rnett-gradle-mcp-verifying-compose-ui && rm -rf "$T"
manifest:
src/main/skills/verifying_compose_ui/SKILL.mdsource content
⚠️ FUNDAMENTAL ANDROID LIMITATION
IMPORTANT:
and image capture methods (runComposeUiTest
) are NOT supported on Android and CANNOT work.node.captureToImage()
Why This Cannot Work
The
runComposeUiTest function requires a JVM-based test runtime with desktop Compose rendering (via Skiko on JVM/Desktop). Android's ART (Android Runtime) does not support the desktop Compose testing APIs, and image capture via
captureToImage() relies on desktop-specific rendering pipelines that are fundamentally incompatible with Android.
The Solution: Use a JVM Target
For visual verification of Composables, you MUST use a JVM or Desktop target source set. This is not a workaround—it is the only supported method.
Recommended approach:
- Put your Composables in a common source set (
) that is shared across all targetscommonMain - Create or use a JVM target (e.g.,
,jvmMain
) that depends ondesktopMaincommonMain - Run the REPL on the JVM target (
orsourceSet: "jvmMain"
)sourceSet: "jvmTest"
This is the standard KMP pattern and allows you to verify your UI code without needing an Android device or emulator.
What WILL NOT Work
- ❌ Running the REPL with
sourceSet: "androidMain" - ❌ Running the REPL with
sourceSet: "androidTest" - ❌ Any attempt to use
on AndroidrunComposeUiTest - ❌ Any attempt to use
on AndroidcaptureToImage()
What WILL Work
- ✅ Running the REPL with
orsourceSet: "jvmMain"sourceSet: "jvmTest" - ✅ Running the REPL with
orsourceSet: "desktopMain"sourceSet: "desktopTest" - ✅ Using
withrunComposeUiTest
on JVM/Desktop targetscaptureToImage()
Authoritative Compose UI Preview & Visual Verification
Visually verifies and renders any @Composable or @Preview directly to high-quality images from the project-aware REPL for instant, authoritative visual feedback.
Constitution
- ALWAYS use
to render Compose components instead of running the full application for visual checks.kotlin_repl - ALWAYS provide absolute paths for
.projectRoot - ALWAYS use
andnode.captureToImage()
to return the visual output.responder.render(bitmap) - ALWAYS ensure the correct Compose UI testing dependencies are on the classpath, using
if necessary.additionalDependencies - NEVER assume a UI component renders correctly without visual verification.
- ALWAYS search for existing
functions in the project source code before creating new ones.@Preview
Directives
- ALWAYS provide absolute
: EnsureprojectRoot
is an absolute file system path for allprojectRoot
calls.kotlin_repl - Ensure dependencies: ALWAYS ensure Compose UI testing dependencies (e.g.,
) are on the classpath.androidx.compose.ui:ui-test-junit4 - Note on versions: ALWAYS check your project's version catalog and existing tests for the correct imports for
.runComposeUiTest - Render as image: ALWAYS use
andnode.captureToImage()
to return the visual output.responder.render(bitmap) - Kotlin Multiplatform (KMP) Note: The
currently only supports JVM-based source sets. ALWAYS select a JVM or Desktop target source set for visual checks.kotlin_repl - Use
if environment variables are missing: SetenvSource: SHELL
(REPL start) orenv: { envSource: "SHELL" }
(Gradle tasks) if expected env vars (e.g.,invocationArguments: { envSource: "SHELL" }
) are not found.JAVA_HOME
When to Use
- Rapid UI Prototyping & Iteration: When you need to see the visual result of a Composable change instantly without the latency of a full application launch.
- Authoritative @Preview Verification: When you want to verify the visual correctness of existing
functions.@Preview - Complex UI State & Interaction Testing: When you need to capture visual state before and after interactions (like clicks or state changes).
- Multi-Configuration Visual Auditing: When checking how a component renders across different data states or configurations (e.g., different view models or mock data).
Workflows
1. Identifying the Component
- Find the fully qualified name of the
or@Composable
function.@Preview - Search for existing previews in the source code via
.grep_search(pattern="@Preview")
2. Orchestrating the Session
- Start the REPL with the
source set (preferred) ortest
withmain
.additionalDependencies - Use
.kotlin_repl(command="start") - Use
to execute the rendering script.kotlin_repl(command="run")
3. Rendering & Verifying
- Execute a script that uses
to render and capture the component.runComposeUiTest - Inspect the returned image for visual correctness.
Examples
Viewing a simple Composable
import androidx.compose.ui.test.* import com.example.ui.MyButton runComposeUiTest { setContent { MyButton(text = "Click Me") } val node = onRoot() responder.render(node.captureToImage()) } // Reasoning: Using kotlin_repl to render a specific component and retrieve its visual representation via the responder API.
Viewing an existing @Preview
import androidx.compose.ui.test.* import com.example.ui.MyButtonPreview // Top-level preview function runComposeUiTest { setContent { MyButtonPreview() } val node = onRoot() responder.render(node.captureToImage()) } // Reasoning: Reusing an existing authoritative preview function to verify its visual correctness.
Capturing State Transitions
import androidx.compose.ui.test.* import com.example.ui.MyCounter import com.example.viewmodel.MyViewModel runComposeUiTest { val viewModel = MyViewModel() setContent { MyCounter(viewModel) } // Capture state before interaction responder.render("State before: ${viewModel.count}") responder.render(onRoot().captureToImage()) // Perform interaction onNodeWithText("Increment").performClick() // Capture state after interaction responder.render("State after: ${viewModel.count}") responder.render(onRoot().captureToImage()) } // Reasoning: Capturing visual snapshots before and after an interaction to verify state-dependent UI changes.
Troubleshooting
- No Image Returned: Ensure you are calling
.responder.render(bitmap) - ClassNotFoundException: Check if you have the correct imports and that the required testing dependencies are on the classpath.
- Empty Image: If the Composable is empty or has zero size, the image will be empty. Verify your Composable's modifiers.