Jelly for Android
Add a feedback toolbar to your Android debug builds. Long-press any Compose or XML element, write a note, and send your coding agent the exact source-backed feedback.
com.rajandube:jelly:0.2.3Why it works well with Compose
Compose screens can be tricky to inspect because a simple layout like a Column or Box can swallow the whole touch area.
Jelly checks both the Compose semantics tree and the slot tree, then chooses the most precise hit. So when you tap a button, card, row, or layout, Jelly can capture the element your feedback is actually about.
Mixed Compose and XML screens are supported too.
Set it up
It takes roughly 40 lines across five files. The main idea is simple: use the real SDK in debug and a no-op version everywhere else.
Declare the dependency
Add Jelly to your version catalog, then pull it into the app module with
debugImplementationso it never enters release builds.# gradle/libs.versions.toml [versions] jelly = "0.2.3" [libraries] jelly = { group = "com.rajandube", name = "jelly", version.ref = "jelly" }// app/build.gradle.kts dependencies { debugImplementation(libs.jelly) }Not using a version catalog? Use
debugImplementation("com.rajandube:jelly:0.2.3")directly.Wire the no-op source set
Point every non-debug variant at
src/notDebug/java. AGP already foldssrc/debug/javainto debug builds, so debug gets the real installer and every other variant gets the stub.// app/build.gradle.kts → android { sourceSets { … } } listOf("release", "qa", "dev_test", "release_test").forEach { variant -> getByName(variant).java.srcDir("src/notDebug/java") }List every non-debug build type your project defines. Use
kotlin.srcDir(…)if your sources live underkotlin/.Add the no-op stub
The non-debug fallback — same function name, no Jelly import — so release code compiles without the SDK on the classpath.
// app/src/notDebug/java/your/app/devtools/QaInstaller.kt package your.app.devtools import android.app.Application fun installQaTools(application: Application) { // No-op in non-debug builds. }Add the real installer
The debug override. The
dev.jelly.*import only resolves here — which is exactly why the stub above exists.// app/src/debug/java/your/app/devtools/QaInstaller.kt package your.app.devtools import android.app.Application import dev.jelly.Jelly import dev.jelly.JellyConfig fun installQaTools(application: Application) { Jelly.install(application = application, config = JellyConfig()) }Call it from
Application.onCreateOne call. The linker resolves the stub or the real installer per variant, so this line compiles everywhere and installs the toolbar only in debug.
import your.app.devtools.installQaTools class MyApp : Application() { override fun onCreate() { super.onCreate() installQaTools(this) } }
Source attribution
Every annotation includes a Source: File.kt:42 line automatically. Jelly walks the call stack and finds the first frame outside Jelly, Compose, and Kotlin internals.
For more precision inside a screen, tag a root area with:
Modifier.jellySource("LoginScreen.kt", 42)Everything inside inherits that source.
APPLICATION_PANEL sub-window and does not need special permissions. Bottom sheets and dialogs can sit above it, so dismiss them first before annotating. For React Native content inside Android, use Jelly for React Native.What gets shared
Jelly exports the element, hierarchy, source file, position, feedback, intent, severity, and screenshot. The format matches iOS, React Native, and web, so your coding agent receives the same structure everywhere.