checkout-kit / android
AGENTS.md7 starsChanged 24 days agoMITView on GitHub
Guidance for AI agents when working in the Android platform. Shopify Checkout Kit for Android publishes Maven artifacts that are consumed by third-party Android apps via Maven Central, so changes to public surfaces have real consumer impact and real reversal cost once released. The main modules are: The sample is a separate Gradle build (samples/CheckoutKitAndroidDemo/settings.gradle) that includes :shopify-checkout from source. The sample's gradle.properties and Gradle wrapper are independent of the Android root's. The standalone Kotlin protocol Gradle root also has…
Where files are headingNew AGENTS.md files have more rules about keeping secrets out of the code, and fewer about code style.
Of the AGENTS.md files we read, the 31,542 first seen in the last six months, against the older ones: the kind of rule that gained most share, and the kind that lost most. About files like this in general, not this one, and an estimate, since a kind is a pattern in the words.
In this repository3 other files it gives its agents.
- AGENTS.mdAGENTS.md
- platforms/swift/.cursor/rules/swift-development.mdcCursor rule
- platforms/swift/.cursor/rules/swift-test.mdcCursor rule
The file
We split this AGENTS.md into the rules it gives an agent
7 rules. About 0 are common, 2 are distinctive, and 5 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈2
Distinctive · estimate
This author's own choices. Worth a look.
5
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 61
Prefer generated protocol models: Before adding hand-written protocol DTOs, check the generated models in
- Very specific: line 70
Every PR is gated in CI by the platform aggregate ./gradlew apiCheck (all feature modules) from platforms/android and ./gradlew …
- Distinctive: line 72
If a change intentionally modifies public API (adding, removing, or changing any public class, method, field, or property):
- Very specific: line 74
Run dev android api dump to regenerate both baselines.
- Very specific: line 76
Commit the updated .api file in the same PR as the code change.
- Very specific: line 78
If apiCheck fails and you did *not* intend to change public API, the diff tells you what inadvertently leaked out.
- Very specific: line 109
After the Android artifact is published, update platforms/react-native/package.json (checkoutKit.nativeSdkVersions.android) in the React …
≈ “Common” is an estimate: at least 1 in 5 of the 40,246 AGENTS.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
AGENTS.md
Guidance for AI agents when working in the Android platform.
Project overview
Shopify Checkout Kit for Android publishes Maven artifacts that are consumed by third-party Android apps via Maven Central, so changes to public surfaces have real consumer impact and real reversal cost once released.
The main modules are:
shopify-checkout-kit/— the fused distribution bundle, published as the singlecom.shopify:checkout-kitAAR. It has no sources.shopify-checkout/— the internal Android library module that owns checkout sources, resources, tests and its API baseline. It has no Maven publication.build-logic/—shopify.android-featureconventions for feature modules andshopify.checkout-kit-publicationconventions for the fused SDK's variants, archives, signing, and artifact verification.../../protocols/universal-commerce-protocol/embedded-checkout-protocol/languages/kotlin/embedded-checkout-protocol/— the Embedded Checkout Protocol Kotlin artifact, published ascom.shopify:embedded-checkout-protocol. The Android Gradle project path is:embedded-checkout-protocol, and the Kotlin package iscom.shopify.ucp.embedded.checkout.samples/CheckoutKitAndroidDemo/— a demo app that consumes Checkout Kit from source and the published Kotlin protocol artifact transitively. Changes here never reach consumers; this module is for internal testing and developer onboarding.
The sample is a separate Gradle build (samples/CheckoutKitAndroidDemo/settings.gradle) that includes :shopify-checkout from source. The sample's gradle.properties and Gradle wrapper are independent of the Android root's. The standalone Kotlin protocol Gradle root also has its own wrapper at ../../protocols/universal-commerce-protocol/embedded-checkout-protocol/languages/kotlin/gradlew; keep its Gradle version aligned with the Android root wrapper.
The library and sample resolve the pinned protocol artifact from Maven Central by default, including in CI. To develop against unreleased protocol source, pass --local to an Android build, test, lint, format, check, or API command (for example dev android test --local) or pass -PuseLocalProtocol=true to Gradle. Only this explicit mode includes :embedded-checkout-protocol in the Android builds. Remote Kit publication rejects local mode; publishToMavenLocal remains available for React Native's explicit --local workflow. Test protocol source independently with dev protocol test kotlin.
Where to make changes
- Checkout Kit source:
shopify-checkout/src/main/java/com/shopify/checkoutkit/. - Embedded Checkout Protocol source, generated models, and generated event catalog:
../../protocols/universal-commerce-protocol/embedded-checkout-protocol/languages/kotlin/embedded-checkout-protocol/src/main/java/com/shopify/ucp/embedded/checkout/. - Library tests:
shopify-checkout/src/test/java/com/shopify/checkoutkit/. "No test, no merge" is a listed reject criterion in the repo-root.github/CONTRIBUTING.md. - Protocol tests:
../../protocols/universal-commerce-protocol/embedded-checkout-protocol/languages/kotlin/embedded-checkout-protocol/src/test/java/com/shopify/ucp/embedded/checkout/. - Java interop is a first-class concern — the library is commonly consumed from Java code.
shopify-checkout/src/test/java/com/shopify/checkoutkit/InteropTest.javaexercises the public API from Java specifically; treat breakage there as a consumer-facing issue.
Key components
ShopifyCheckout.kt— the public checkout feature entry point. Companion APIs manage shared configuration, preloading, and SDK-owned presentation; instances provide app-hosted checkout content.CheckoutService.kt— internal shared checkout state and lifecycle implementation behindShopifyCheckout.ShopifyCheckoutKit.kt— SDK version metadata.CheckoutBottomSheet.kt— the bottom sheet that hosts the WebView, including the progress indicator, gesture coordination, and checkout error coordination.CheckoutWebView.kt— the Checkout WebView. Configures WebView behavior, instruments page loads, and owns the ECP bridge.CheckoutProtocol.kt— the curated consumer-facing Checkout Kit protocol API. This is where supported events/delegations are intentionally exposed.EmbeddedCheckoutProtocolBridge.kt— connects the WebView message transport to the ECP client. Owns transport attachment, message filtering, protocol execution, and default-client composition.WebMessageTransport.kt— the WebView messaging boundary. Its production implementation receives messages through AndroidX WebMessageListener and sends responses through JavaScript evaluation; tests inject a fake implementation.../../protocols/universal-commerce-protocol/embedded-checkout-protocol/languages/kotlin/embedded-checkout-protocol/src/main/java/com/shopify/ucp/embedded/checkout/EmbeddedCheckoutProtocol.kt— the generated low-level Embedded Checkout Protocol event catalog.../../protocols/universal-commerce-protocol/embedded-checkout-protocol/languages/kotlin/embedded-checkout-protocol/src/main/java/com/shopify/ucp/embedded/checkout/ProtocolCodec.kt— hand-written JSON-RPC request/response helpers.../../protocols/universal-commerce-protocol/embedded-checkout-protocol/languages/kotlin/embedded-checkout-protocol/src/main/java/com/shopify/ucp/embedded/checkout/Descriptors.kt— reusable protocol descriptor and codec types.Configuration.kt— runtime config container (color scheme, log level).CheckoutListener.kt+DefaultCheckoutListener— consumer-implemented lifecycle interface (failure, cancellation, permission prompts, file chooser). Changes here are consumer API changes.CheckoutPresentation.kt— Kotlin-first builder for per-presentation callbacks (onFail,onDismiss, browser/system hooks, ECPconnect(...)). Builds aDefaultCheckoutListenerinternally.
Testing patterns
- Tests use Robolectric (
@RunWith(RobolectricTestRunner::class)) to exercise Android framework code without a device. - Drain immediate main-thread work with
shadowOf(Looper.getMainLooper()).idle(). It does not advance delayed tasks. UseidleFor(...)when a test deliberately needs delayed work to run, such as preload expiry. AvoidrunToEndOfTasks()in preload tests: it advances the scheduler through delayed work and fires the five-minute expiry timer. - Assertion library is AssertJ; mocking is Mockito + Mockito-Kotlin. Mockito is on 5.x because the library targets JVM 11. Don't introduce new assertion/mocking libraries without discussion.
- Tests live in the same package as the class under test (file name:
ClassNameTest.kt).
Conventions
-Xexplicit-api=strictis on for both published Kotlin artifacts. Every public class, method, field, and property must have an explicit visibility modifier. "Accidentally public" is not a thing here. This is a consumer-protection rule — if you see a public-by-default declaration, it was deliberate.- Max line length: 140 (detekt-enforced). Detekt config:
gradle/detekt.config.yml. - Library JVM target: 11. Consumers must build with JDK 11+ to consume the published artifacts. Raising further is a major-version discussion.
- Library Kotlin
apiVersion/languageVersionare pinned at 2.0. Set throughgradle/android-library-versions.gradleso the published artifacts stay consumable by Kotlin 2.0+ projects even though the compiler itself is on a newer 2.x. Bumping this pin is the consumer-facing breaking change, not bumping the compiler - treat it as a planned major-version event. - Kotlin/JVM compatibility values live in
gradle/android-library-versions.gradle. Android SDK levels live inbuild-logic/src/main/groovy/shopify.android-feature.gradle. Dependency, plugin, and Android artifact versions live ingradle/libs.versions.toml. - Protocol vs kit boundary: the protocol artifact should own generated raw wire names, generated models, thin descriptors, and encoding/decoding helpers. Checkout Kit should own curation, default behavior, WebView integration, and the higher-level consumer API.
- Prefer generated protocol models. Before adding hand-written protocol DTOs, check the generated models in
../../protocols/universal-commerce-protocol/embedded-checkout-protocol/languages/kotlin/embedded-checkout-protocol/src/main/java/com/shopify/ucp/embedded/checkout/Models.ktand the OpenRPC schema. Use generated UCP/ECP types for wire payloads; reserve local DTOs for Android-internal transport helpers that are not represented in the schema.
Public API surface
The Android public APIs are captured by the binary-compatibility-validator Gradle plugin:
shopify-checkout/api/shopify-checkout.apiforcom.shopify:checkout-kit.../../protocols/universal-commerce-protocol/embedded-checkout-protocol/languages/kotlin/embedded-checkout-protocol/api/embedded-checkout-protocol.apiforcom.shopify:embedded-checkout-protocol.
Every PR is gated in CI by the platform aggregate ./gradlew apiCheck (all feature modules) from platforms/android and ./gradlew :embedded-checkout-protocol:apiCheck from protocols/universal-commerce-protocol/embedded-checkout-protocol/languages/kotlin — the build fails if either compiled public API diverges from the committed baselines.
If a change intentionally modifies public API (adding, removing, or changing any public class, method, field, or property):
- Run
dev android api dumpto regenerate both baselines. For project-scoped updates, run./gradlew :shopify-checkout:apiDumpfromplatforms/androidor./gradlew :embedded-checkout-protocol:apiDumpfromprotocols/universal-commerce-protocol/embedded-checkout-protocol/languages/kotlin. - Review the
.apidiffs — they are the single best indicator of consumer impact, and reviewers will focus on them. - Commit the updated
.apifile in the same PR as the code change.
If apiCheck fails and you did not intend to change public API, the diff tells you what inadvertently leaked out. Fix the leak rather than updating the baseline — you've accidentally shifted the consumer contract.
Common commands
- Published protocol resolution:
./gradlew :shopify-checkout:verifyPublishedProtocol. Unit tests and remote publication run this automatically to require the catalog-pinned external module on release and unit-test classpaths. Explicit local mode skips it; remote publication still rejects local mode. - Tests:
./gradlew test(ordev android test) - API surface:
./gradlew apiCheck/./gradlew apiDumpfor every Checkout Kit feature,./gradlew :embedded-checkout-protocol:apiCheck/./gradlew :embedded-checkout-protocol:apiDumpfromprotocols/universal-commerce-protocol/embedded-checkout-protocol/languages/kotlinfor protocol, ordev android api check/dev android api dumpfor both. - Publication and sibling-feature integration:
./scripts/check_publication(checks a temporary second feature, then rebuilds the normal SDK and tests Gradle-metadata and POM-only consumers). - Lint:
./gradlew detekt lintRelease(ordev android lint); read-only. Formatting opts into corrections explicitly. - Format:
./gradlew detekt --auto-correct(ordev android format) - Full local verification:
./gradlew clean test detekt lintRelease assembleRelease - Kotlin protocol only: from the repo root,
cd protocols/universal-commerce-protocol/embedded-checkout-protocol/languages/kotlin && ./gradlew test apiCheck - Sample app build (from
samples/CheckoutKitAndroidDemo/):./gradlew assembleDebug
Consumer requirements
Raising any of these is a consumer-facing breaking change and needs visible release notes:
minSdk(library's minimum supported Android API level at runtime)compileSdkfloor for consumers (enforced viaaarMetadata.minCompileSdkon the library, or implicitly raised by any transitiveandroidxdependency whose own metadata demands a newercompileSdk)- Kotlin compiler /
apiVersion/languageVersion - JVM target
Transitive androidx bumps can silently raise the compileSdk floor — review dependabot PRs with this in mind, and run ./gradlew :shopify-checkout:apiCheck and check aarMetadata output when bumping any androidx.* dependency.
Release process
Android Kit versions come from its release pull request (pnpm changeset android version). It updates package.json here and copies the version to checkoutKitAndroid in gradle/libs.versions.toml. Update the Gradle/Maven install snippets in README.md in that pull request. Add an Android changeset instead of bumping the version by hand; see Versions and release notes.
In the catalog, embeddedCheckoutProtocolAndroidRelease is the independent protocol release version, and embeddedCheckoutProtocolAndroid is the already-published protocol version Kit consumes. Bump the dependency only after publishing the protocol release.
After the Android artifact is published, update platforms/react-native/package.json (checkoutKit.nativeSdkVersions.android) in the React Native release flow if RN should consume that published com.shopify:checkout-kit SemVer. RN CI resolves this value from Maven, so do not point it at an unpublished Android version.
Embedded Checkout Protocol releases are tagged embedded-checkout-protocol/YYYY.MM.DD.PATCH[-prerelease.N] and publish only com.shopify:embedded-checkout-protocol. Android Kit releases are tagged android/X.Y.Z and publish only com.shopify:checkout-kit; the Android publish workflow fails if the referenced protocol version is not already available on Maven Central. Swift releases use bare X.Y.Z.
Publishing goes through GitHub Releases → the relevant repo-root publish workflow → manual approval gate before Maven Central deploy. Full procedure: the repo-root .github/CONTRIBUTING.md release sections.
Things not to touch without discussion
- Library Kotlin
apiVersion/languageVersionpin (2.0). Consumer compatibility floor; raising it is a deliberate major-version decision. The compiler version itself is not the lever. minSdk/ JVM target. Same story.-Xexplicit-api=strict. Removing this would let implicit public declarations ship; keeping it is a consumer-protection invariant.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

