Skip to content
cccskills
FreePublished on GitHub

convention-plugin-development

Author or modify a build-logic convention plugin. Use when changing plugin internals, the diagnostics catalog, or Rust-native wiring. Not for adding a dependency/module (gradle-build-system) or version bumps (dependency-update).

The English summary is being prepared. Showing the original description.

Works withCloudflare
See how to install

Files included (2)

  • SKILL.md12.2 KB
  • references/rust-native.md3.7 KB

SKILL.md (original)

Review the instructions the agent will receive before you install.

1. Plugin Architecture

Included Build Pattern

The project uses Gradle's included build (includeBuild) to isolate build logic from the main build. The root settings.gradle.kts includes build-logic/ which itself is a standalone Gradle project.

build-logic/
  settings.gradle.kts          -- declares :convention subproject, creates "libs" catalog
  convention/
    build.gradle.kts            -- applies kotlin-dsl, declares compileOnly AGP/plugin deps
    src/main/kotlin/            -- all precompiled script plugins and helper classes

build-logic/settings.gradle.kts creates a version catalog named libs pointing at the root gradle/libs.versions.toml. This gives convention plugins access to the same version catalog used by application modules.

How Plugins Are Registered

Every *.gradle.kts file under src/main/kotlin/ becomes a precompiled script plugin whose ID is the filename minus the .gradle.kts suffix. For example, ripdpi.android.library.gradle.kts registers as plugin ID ripdpi.android.library.

No gradlePlugin {} block or META-INF descriptor is needed -- the kotlin-dsl plugin handles registration automatically.

Dependency Declaration

build-logic/convention/build.gradle.kts declares external Gradle plugins as compileOnly dependencies so their extension types are available at compile time:

  • AGP (com.android.tools.build:gradle)
  • Kotlin Compose compiler plugin
  • Hilt, KSP, detekt, ktlint, roborazzi

The kotlinx-serialization-json library is an implementation dependency because the diagnostics catalog renderer uses it at task execution time.

2. Plugin Inventory

Plugin IDFilePurpose
ripdpi.android.applicationripdpi.android.application.gradle.ktsConfigures AGP application module: compileSdk, minSdk, targetSdk, R8/ProGuard, artifact naming (AAB), JVM 17
ripdpi.android.libraryripdpi.android.library.gradle.ktsConfigures AGP library module: compileSdk, minSdk, consumer ProGuard rules, JVM 17
ripdpi.android.nativeripdpi.android.native.gradle.ktsSets NDK version, ABI filters, jniLibs packaging policy. Applied by both application and library plugins
ripdpi.android.rust-nativeripdpi.android.rust-native.gradle.ktsCross-compiles Rust workspace into Android .so files via Cargo. Parallel per-ABI builds. See section 4
ripdpi.android.composeripdpi.android.compose.gradle.ktsEnables Compose, sets stability config, optional metrics/reports on CI
ripdpi.android.hiltripdpi.android.hilt.gradle.ktsApplies Hilt + KSP, adds hilt-android and hilt-compiler dependencies
ripdpi.android.serializationripdpi.android.serialization.gradle.ktsApplies kotlin.plugin.serialization (one-liner)
ripdpi.android.protobufripdpi.android.protobuf.gradle.ktsRuns protoc directly (no protobuf Gradle plugin). Detects host OS/arch, wires generated Java sources into AGP variants
ripdpi.android.qualityripdpi.android.quality.gradle.ktsAggregator: applies detekt + ktlint + lint
ripdpi.android.detektripdpi.android.detekt.gradle.ktsConfigures detekt: parallel, custom rules from :quality:detekt-rules, compose rules, baseline support
ripdpi.android.ktlintripdpi.android.ktlint.gradle.ktsConfigures ktlint: version pin, Android mode, excludes build/generated
ripdpi.android.lintripdpi.android.lint.gradle.ktsConfigures Android Lint: abortOnError, baseline, html+xml reports
ripdpi.android.coverageripdpi.android.coverage.gradle.ktsDelegates to jacoco plugin (one-liner)
ripdpi.android.jacocoripdpi.android.jacoco.gradle.ktsJaCoCo setup: excludes generated/Hilt/proto classes, registers jacocoDebugUnitTestReport task
ripdpi.android.roborazziripdpi.android.roborazzi.gradle.ktsScreenshot testing: enables Android resources in unit tests, sets output dir to src/test/screenshots
ripdpi.diagnostics.catalogripdpi.diagnostics.catalog.gradle.ktsRegisters generateDiagnosticsCatalog and checkDiagnosticsCatalog tasks. See section 3
ripdpi.android.testripdpi.android.test.gradle.ktsConfigures com.android.test modules (currently :baselineprofile); wires the shared Gradle Managed Device registry

Helper Kotlin Files (not plugins)

FilePurpose
NativeBuildPolicy.ktUtility functions: resolvedNativeAbis(), resolvedNativeCargoProfile(), resolveAndroidSdkDir(), resolveRustTool(), CI/release detection
DiagnosticsCatalogAssembler.ktOrchestrates pack loading, profile loading, validation, JSON rendering
DiagnosticsCatalogDefinitions.ktSingleton entry point wiring the assembler with default sources
DiagnosticsCatalogDomain.ktDomain model: DiagnosticsCatalog, TargetPackDefinition, DiagnosticsProfileDefinition, enums
DiagnosticsCatalogDpiData.ktDPI-profile target data (domains, TCP targets, whitelist SNI) consumed by DefaultDiagnosticsCatalogProfileSource
DefaultDiagnosticsCatalogPackSource.ktDefaultDiagnosticsCatalogPackSource -- builds target pack list
DefaultDiagnosticsCatalogProfileSource.ktDefaultDiagnosticsCatalogProfileSource -- builds profile list referencing packs
DiagnosticsCatalogRendering.ktDiagnosticsCatalogJsonRenderer and DiagnosticsCatalogValidator -- serializes to JSON, validates pack refs and versions
DiagnosticsCatalogSharedData.ktShared constants (common domains, DNS servers) reused across packs
DiagnosticsCatalogSupport.ktHelper functions for building domain/DNS/TCP target lists

3. Diagnostics Catalog Generator

The catalog defines target packs (groups of network endpoints) and profiles (scan configurations referencing packs). It is checked into the repo as a JSON asset at core/diagnostics/src/main/assets/diagnostics/default_profiles.json.

Data Flow

  1. DiagnosticsCatalogPackSource builds List<TargetPackDefinition> from typed Kotlin data
  2. DiagnosticsCatalogProfileSource builds List<DiagnosticsProfileDefinition>, resolving pack refs
  3. DiagnosticsCatalogValidator checks for duplicate IDs and verifies every packRef points to a real pack with matching version
  4. DiagnosticsCatalogJsonRenderer serializes to pretty-printed JSON using kotlinx.serialization
  5. DiagnosticsCatalogAssembler orchestrates steps 1-4

Tasks

  • generateDiagnosticsCatalog -- writes the JSON to the asset path. Run manually after changing data.
  • checkDiagnosticsCatalog -- runs during check, fails if the committed file differs from what would be generated. This prevents stale catalogs from shipping.

Both tasks use DiagnosticsCatalogGeneratedAt (a date constant in DiagnosticsCatalogDomain.kt) as an @Input to force re-execution when the generation date changes.

Adding a New Target Pack or Profile

The catalog's content (packs, profiles, and how to add them) is owned by the diagnostics-system skill; this skill covers only the generator plumbing above.

4. Rust-Native Plugin

ripdpi.android.rust-native.gradle.kts is the largest and most volatile convention plugin: it cross-compiles the Rust workspace into Android .so libraries, the root-helper executable, naive-proxy and Cloudflare-origin binaries, and pluggable-transport assets.

  • Two task classes do the work: BuildRustNativeLibsTask (Cargo-built artifact groups -- .so libraries, root-helper, naive-proxy, Cloudflare-origin) and BuildPluggableTransportAssetsTask (assets built from native/pluggable-transports/sources.json). Both are @CacheableTask.
  • Artifact groups are declared as pipe-delimited "<cargo-package>|<cargo-output>|<output-name>" triples in separate rustNativeArtifactSpecs, rustRootHelperArtifactSpecs, rustNaiveProxyArtifactSpecs, and rustCloudflareOriginArtifactSpecs lists near the bottom of the plugin file. Read them directly before changing or reasoning about which artifacts get built -- this set changes independently of the skill and is not reproduced here.

For the Cargo invocation sequence, ABI-to-target-triple mapping, profile selection, task wiring into AGP's packaging pipeline, and cache-input tracking, read references/rust-native.md.

5. Adding a New Convention Plugin

Step-by-Step

  1. Create build-logic/convention/src/main/kotlin/ripdpi.<category>.<name>.gradle.kts
  2. If the plugin applies an external Gradle plugin, add its artifact as a compileOnly dependency in build-logic/convention/build.gradle.kts using the libs.plugins.<id>.map { ... } pattern
  3. Write the plugin body. Access shared properties via providers.gradleProperty("ripdpi.<property>")
  4. Apply the plugin in consuming modules: id("ripdpi.<category>.<name>")
  5. Verify with ./gradlew :app:help (or whichever module applies it) to confirm resolution

Naming Convention

  • ripdpi.android.* -- plugins that configure Android modules (AGP extensions, Kotlin, quality tools)
  • ripdpi.diagnostics.* -- plugins for the diagnostics subsystem
  • Use dots as separators. The filename IS the plugin ID.

Helper Classes

Place reusable Kotlin code in plain .kt files alongside the plugins (not inside a package). These files are compiled into the same classpath and are directly accessible from any precompiled script plugin in the module.

6. Common Pitfalls

Configuration Cache Compatibility

The project enables org.gradle.configuration-cache=true. Every plugin must be configuration-cache safe:

  • Do not capture Project references in task actions. Use @Input/@InputFile properties.
  • Use providers.gradleProperty() instead of reading properties eagerly at configuration time.
  • Task classes that call ExecOperations must inject it via @Inject constructor.

AGP API Compatibility

  • Use extensions.configure<ApplicationExtension> (the DSL type), not the internal BaseAppModuleExtension. Internal types break across AGP upgrades.
  • For variant-aware wiring, use ApplicationAndroidComponentsExtension or LibraryAndroidComponentsExtension with onVariants {}.
  • The protobuf plugin uses variant.sources.java?.addGeneratedSourceDirectory() to wire generated sources -- this is the modern AGP variant API approach.

Included Build Quirks

  • Version catalog access in build.gradle.kts uses libs.versions.<name> and libs.plugins.<name>. Inside precompiled script plugins, use the<VersionCatalogsExtension>().named("libs") or versionCatalogs.named("libs").
  • Changes to build-logic/ sources require a Gradle sync in the IDE. Gradle does not auto-detect included build source changes in all cases.
  • The kotlin-dsl plugin implicitly applies java-gradle-plugin and kotlin("jvm"). Do not apply them again.

Baseline Policy

Per project rules (CLAUDE.md): never extend detekt baselines, lint baselines, or LoC baselines to suppress new violations. Fix the underlying issue. Baselines exist only for legacy debt.

Rust-Native Cache Misses

If the Rust build runs unexpectedly, or skips when a rebuild was expected:

  1. Every Rust-native task's @InputFiles tracks the whole native/rust/crates/ tree, Cargo.lock, rust-toolchain.toml, .cargo/, and vendor/ automatically -- there is no manually maintained per-crate allowlist to fall out of sync. See references/rust-native.md for the exact input set.
  2. Check if Cargo.lock changed (a dependency update triggers a rebuild).
  3. Verify the profile selection logic -- local dev should use android-jni-dev.

Protobuf Plugin

The project deliberately avoids the protobuf-gradle-plugin and instead uses a custom GenerateProtoLiteSourcesTask that downloads protoc as a detached configuration and runs it directly. This avoids version conflicts and configuration-cache issues with the official plugin.

See Also

  • gradle-build-system skill -- everyday dependency/module lookups and build-failure triage; start there before this deeper reference.
  • dependency-update skill -- version-catalog and cross-ecosystem (Gradle + Cargo) update workflows.

Reviews

No reviews yet. Tell others what you thought.

Comments

No login needed. Share how it worked for you, ask a question, or note where it did not run.

No comments yet. Be the first to write one.

Comments are published right away. Do not include personal information such as email addresses or phone numbers. Up to 2 URLs.

0 / 1,000 characters

This form is protected by reCAPTCHA, and the Google Privacy Policy and Terms of Service apply.

More skills from this repository

RIPDPI's own Compose conventions: ViewModel pattern, Route/Screen split, DataStore->StateFlow, RipDpiThemeTokens. Use for how this app does Compose, not generic Compose API questions (see compose).

The English summary is being prepared. Showing the original description.

po4yka/RIPDPI81Updated Oct 21, 2026

ADB-based RIPDPI device/emulator debugging: build/install/launch, logcat filtering, fixture port-forwarding, instrumented tests, crash/ANR triage. Use when debugging on a real device or emulator.

The English summary is being prepared. Showing the original description.

po4yka/RIPDPI81Updated Oct 21, 2026

RIPDPI Appium launch-contract reference: start routes and permission/service/data presets. Use when a test launches to the wrong screen or a new automation route is added. General flakiness: appium-test-debug.

The English summary is being prepared. Showing the original description.

po4yka/RIPDPI81Updated Oct 21, 2026

RIPDPI Appium test authoring: page objects, resource-id locators, assertions, wait tiers. Use when writing a new Appium test or page object, or adding coverage for a new screen.

The English summary is being prepared. Showing the original description.

po4yka/RIPDPI81Updated Oct 21, 2026

RIPDPI Appium failure triage: flaky tests, locator/session/wait issues, screenshot and element-tree debugging. Use when an Appium test fails or is flaky.

The English summary is being prepared. Showing the original description.

po4yka/RIPDPI81Updated Oct 21, 2026

Add or modify a GitHub Actions job. Use when editing a file under .github/workflows/. Not for running a workflow locally (local-ci-act) or release signing (release-signing).

The English summary is being prepared. Showing the original description.

po4yka/RIPDPI81Updated Oct 21, 2026

See all skills by po4yka

Report a problem with this skill