Install
$ agentstack add skill-b33eep-claude-code-setup-standards-gradle Open-source listing — not yet scanned by AgentStack. Follow the source repository for install instructions.
Security review
⚠ Flagged1 finding(s); flagged for manual review. · v0.1.0 How review works →
- • Prompt-injection patterns
- • Secret / credential exfiltration
- • Dangerous shell & filesystem operations
- • Untrusted network calls
- • Known-malicious package signatures
- high Destructive filesystem operation.
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ● Shell / process execution Used
- ● Environment & secrets Used
- ● Dynamic code execution Used
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
Gradle Coding Standards (Gradle 9 LTS)
This skill provides comprehensive guidance for Gradle build configuration using Kotlin DSL (.gradle.kts). It covers both everyday project configuration and advanced plugin/task development patterns based on Gradle 9 LTS.
Core Principles
- Declarative over Imperative: Prefer declarative configuration that describes what you want, not how to achieve it
- Type-Safe Configuration: Use Kotlin DSL for type safety and IDE support
- Lazy Configuration: Use Providers API to defer configuration until needed
- Build Cache Friendly: Write tasks that support build caching for faster builds
- Configuration Cache Compatible: Ensure build scripts work with configuration cache for optimal performance
Section 1: Project Configuration
This section covers the common scenarios developers encounter when configuring Gradle projects: setting up build scripts, managing dependencies, applying plugins, and structuring multi-module projects.
Build Script Basics
build.gradle.kts Structure
Organize your build script in a consistent, readable order:
// 1. Plugin declarations (always first)
plugins {
java
application
id("com.github.johnrengelman.shadow") version "8.1.1"
}
// 2. Project properties and versioning
group = "com.example"
version = "1.0.0"
// 3. Repositories
repositories {
mavenCentral()
}
// 4. Dependencies
dependencies {
implementation("com.google.guava:guava:33.0.0-jre")
testImplementation("org.junit.jupiter:junit-jupiter:5.10.2")
}
// 5. Java/Kotlin configuration
java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
}
// 6. Task configuration
tasks {
test {
useJUnitPlatform()
}
jar {
manifest {
attributes("Main-Class" to "com.example.Main")
}
}
}
settings.gradle.kts Basics
// Root project name
rootProject.name = "my-project"
// Enable Gradle version catalogs (Gradle 9+)
enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
// Include subprojects
include("app")
include("lib")
include("common")
// Optional: Customize subproject location
project(":app").projectDir = file("applications/app")
Repository Configuration
repositories {
// GOOD: Standard repositories first
mavenCentral()
// GOOD: Google repository for Android/Google libraries
google()
// GOOD: Custom repository with HTTPS
maven {
name = "CompanyRepo"
url = uri("https://repo.company.com/maven")
credentials {
username = providers.gradleProperty("repoUser").orNull
password = providers.gradleProperty("repoPassword").orNull
}
}
}
// BAD: Using HTTP instead of HTTPS (security risk)
// maven { url = uri("http://insecure-repo.com/maven") }
// BAD: Exposing credentials in build script
// maven {
// url = uri("https://repo.company.com/maven")
// credentials {
// username = "hardcoded-user" // Never do this!
// password = "hardcoded-pass" // Never do this!
// }
// }
Script Organization Best Practices
// GOOD: Use extra properties for shared values
val mockitoVersion by extra("5.10.0")
val junitVersion by extra("5.10.2")
dependencies {
testImplementation("org.mockito:mockito-core:$mockitoVersion")
testImplementation("org.junit.jupiter:junit-jupiter:$junitVersion")
}
// GOOD: Extract complex configuration to functions
fun configureJavaToolchain() {
java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
vendor = JvmVendorSpec.ADOPTIUM
}
}
}
// Apply configuration
configureJavaToolchain()
Gradle Build Phases
Understanding Gradle's build phases is essential for writing efficient build scripts and understanding when your code executes.
The Three Build Phases
Every Gradle build runs through three distinct phases in order:
- Initialization Phase - Determines which projects participate in the build
- Configuration Phase - Configures all projects and builds the task graph
- Execution Phase - Executes the selected tasks
Understanding these phases helps you:
- Write faster builds (keep configuration phase light)
- Understand lazy evaluation and Provider API
- Make configuration cache work correctly
- Debug build script behavior
1. Initialization Phase
Purpose: Determine project structure and which projects participate in the build.
What runs: settings.gradle.kts files
What happens:
- Gradle locates and reads
settings.gradle.kts - Determines root project and subprojects
- Creates
Projectinstances for each project
Example:
// settings.gradle.kts (runs during initialization)
rootProject.name = "my-project"
println("Initialization phase") // Prints during initialization
include("app")
include("lib")
include("common")
// Optional: Customize subproject directories
project(":app").projectDir = file("applications/app")
Duration: Very fast (typically = providers.provider { fileTree("src") // Only evaluated when needed }
**Duration:** Can be slow if not careful (seconds to minutes for large projects)
**Key Point:** Configuration runs on **every** build, even if no tasks execute. Keep it fast!
#### 3. Execution Phase
**Purpose:** Execute the selected tasks in dependency order.
**What runs:** Task actions (`doFirst`, `doLast`, `@TaskAction`)
**What happens:**
- Tasks execute in correct dependency order
- Task inputs are read
- Task outputs are generated
- Build artifacts are created
**Example:**
```kotlin
tasks.register("myTask") {
// Configuration phase
group = "custom"
doFirst {
// Execution phase - runs first
println("Starting task")
}
doLast {
// Execution phase - runs last
println("Task completed")
}
}
// Abstract task with @TaskAction
abstract class BuildTask : DefaultTask() {
@get:InputDirectory
abstract val sourceDir: DirectoryProperty
@get:OutputDirectory
abstract val outputDir: DirectoryProperty
@TaskAction // Execution phase
fun build() {
println("Building...")
// Actual work happens here
}
}
Duration: Depends on what tasks do (compile, test, package, etc.)
Key Point: Only requested tasks (and their dependencies) execute.
When Code Runs - Quick Reference
| Code Location | Phase | Example | |---------------|-------|---------| | settings.gradle.kts (top-level) | Initialization | rootProject.name = "app" | | build.gradle.kts (top-level) | Configuration | version = "1.0" | | plugins {} block | Configuration | java | | dependencies {} block | Configuration | implementation(...) | | tasks.register { } outer block | Configuration | group = "custom" | | tasks.register { } inner block | Configuration | dependsOn("other") | | Extension configuration blocks | Configuration | java { toolchain { } } | | doFirst { } | Execution | println("starting") | | doLast { } | Execution | println("done") | | @TaskAction method | Execution | fun execute() { } | | Provider.get() in doLast | Execution | val v = provider.get() |
Common Mistakes and Anti-Patterns
// ❌ BAD: Expensive I/O during configuration
tasks.register("badTask") {
val files = File("src").listFiles() // I/O during configuration - runs every build!
println("Found ${files?.size} files")
doLast {
println("Processing ${files?.size} files")
}
}
// ✅ GOOD: Defer work to execution
tasks.register("goodTask") {
doLast {
val files = File("src").listFiles() // I/O during execution - only when task runs
println("Found ${files?.size} files")
println("Processing ${files.size} files")
}
}
// ❌ BAD: Accessing task outputs during configuration
tasks.register("badConsumer") {
val compileOutput = tasks.named("compileJava").get().outputs.files // Not ready yet!
doLast {
println(compileOutput)
}
}
// ✅ GOOD: Use providers to defer access
tasks.register("goodConsumer") {
val compileOutput = tasks.named("compileJava").map { it.outputs.files }
doLast {
println(compileOutput.get()) // Resolved during execution
}
}
// ❌ BAD: Network calls during configuration
tasks.register("badFetch") {
val response = URL("https://api.example.com/version").readText() // Slows every build!
doLast {
println("Version: $response")
}
}
// ✅ GOOD: Use providers for network calls
tasks.register("goodFetch") {
val response: Provider = providers.provider {
URL("https://api.example.com/version").readText()
}
doLast {
println("Version: ${response.get()}") // Only called during execution
}
}
// ❌ BAD: Calling .get() on providers during configuration
tasks.register("badProvider") {
val version = providers.gradleProperty("version").get() // Eager evaluation!
doLast {
println("Version: $version")
}
}
// ✅ GOOD: Defer .get() until execution
tasks.register("goodProvider") {
val version = providers.gradleProperty("version") // Lazy - not evaluated yet
doLast {
println("Version: ${version.get()}") // Evaluated here
}
}
// ❌ BAD: Mutating shared state during configuration
var counter = 0 // Global mutable state
tasks.register("bad1") {
counter++ // Modifies global state during configuration
doLast { println("Counter: $counter") }
}
tasks.register("bad2") {
counter++ // Order-dependent!
doLast { println("Counter: $counter") }
}
// ✅ GOOD: Use build services or task outputs for shared state
Why Build Phases Matter
1. Build Performance
Configuration phase runs on every build:
./gradlew tasks # Configuration runs
./gradlew clean # Configuration runs
./gradlew build # Configuration runs
./gradlew --stop # Configuration runs
Slow configuration = slow every command, even ./gradlew tasks!
2. Configuration Cache
Configuration cache stores the result of configuration phase:
# First run: Configuration + execution
./gradlew build --configuration-cache
# Configuration phase: 5 seconds
# Execution phase: 30 seconds
# Second run: Execution only
./gradlew clean build --configuration-cache
# Configuration phase: 0 seconds (reused from cache!)
# Execution phase: 30 seconds
Benefits:
- Up to 90% faster builds (skip configuration entirely)
- Especially valuable for large projects
Requirements:
- Use Provider API (lazy evaluation)
- No mutable shared state
- No accessing
projectduring execution - Serializable configuration
3. Up-to-Date Checks
Tasks are up-to-date when:
- Inputs haven't changed
- Outputs exist and are valid
Input/output annotations are evaluated during:
- Configuration: Gradle determines task inputs/outputs
- Execution: Gradle checks if task needs to run
Proper annotations enable:
- Incremental builds
- Build cache
FROM-CACHEandUP-TO-DATEoptimizations
Best Practices for Build Phases
Do:
- ✅ Keep configuration phase fast (.html
Measure configuration time
./gradlew build --configuration-cache --configuration-cache-problems=warn
See what runs during configuration
./gradlew build --info | grep "Configuration"
Test configuration cache compatibility
./gradlew build --configuration-cache ./gradlew clean build --configuration-cache # Should show "Reusing configuration cache"
#### Example: Full Build Lifecycle
```kotlin
// settings.gradle.kts
println("1. Initialization phase: settings.gradle.kts")
rootProject.name = "lifecycle-demo"
// build.gradle.kts
println("2. Configuration phase: build.gradle.kts top-level")
plugins {
java
println("3. Configuration phase: plugins block")
}
println("4. Configuration phase: after plugins")
tasks.register("demo") {
println("5. Configuration phase: task configuration")
group = "demo"
description = "Demonstrates build phases"
doFirst {
println("7. Execution phase: doFirst")
}
doLast {
println("8. Execution phase: doLast")
}
}
println("6. Configuration phase: after task registration")
// When you run: ./gradlew demo
// Output order:
// 1. Initialization phase: settings.gradle.kts
// 2. Configuration phase: build.gradle.kts top-level
// 3. Configuration phase: plugins block
// 4. Configuration phase: after plugins
// 5. Configuration phase: task configuration
// 6. Configuration phase: after task registration
// 7. Execution phase: doFirst
// 8. Execution phase: doLast
Dependency Management
Dependency Configurations
dependencies {
// GOOD: implementation - for internal dependencies (not exposed to consumers)
implementation("com.google.guava:guava:33.0.0-jre")
// GOOD: api - for dependencies exposed to consumers (libraries only)
// Only available with java-library plugin
api("org.apache.commons:commons-lang3:3.14.0")
// GOOD: compileOnly - compile-time only (not packaged)
compileOnly("org.projectlombok:lombok:1.18.30")
// GOOD: runtimeOnly - runtime only (not on compile classpath)
runtimeOnly("com.h2database:h2:2.2.224")
// GOOD: testImplementation - for test code only
testImplementation("org.junit.jupiter:junit-jupiter:5.10.2")
testImplementation("org.mockito:mockito-core:5.10.0")
// GOOD: testRuntimeOnly - test runtime only
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
}
// BAD: Using 'compile' (deprecated in Gradle 7+)
// dependencies {
// compile("some:library:1.0") // Use 'implementation' instead
// }
// BAD: Using 'runtime' (deprecated in Gradle 7+)
// dependencies {
// runtime("some:library:1.0") // Use 'runtimeOnly' instead
// }
Version Catalogs (Modern Gradle Approach)
gradle/libs.versions.toml:
[versions]
guava = "33.0.0-jre"
junit = "5.10.2"
mockito = "5.10.0"
kotlin = "2.0.0"
[libraries]
guava = { module = "com.google.guava:guava", version.ref = "guava" }
junit-jupiter = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junit" }
junit-platform-launcher = { module = "org.junit.platform:junit-platform-launcher" }
mockito-core = { module = "org.mockito:mockito-core", version.ref = "mockito" }
[bundles]
testing = ["junit-jupiter", "mockito-core"]
[plugins]
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
shadow = { id = "com.github.johnrengelman.shadow", version = "8.1.1" }
build.gradle.kts:
plugins {
alias(libs.plugins.kotlin.jvm)
}
dependencies {
// GOOD: Type-safe accessors from version catalog
implementation(libs.guava)
testImplementation(libs.bundles.testing)
testRuntimeOnly(libs.junit.platform.launcher)
}
// Benefits:
// - Centralized version management
// - Type-safe accessors with IDE completion
// - Easy to share across multi-module projects
// - Prevents version conflicts
Dependency Constraints
dependencies {
implementation("com.example:library:1.0")
// GOOD: Force specific version to resolve conflicts
constraints {
implementation("org.slf4j:slf4j-api:2.0.9") {
because("Earlier versions have security vulnerabilities")
}
}
// GOOD: Align versions across dependency group
constraints {
implementation("org.springframework.boot:spring-boot-starter-web:3.2.0")
implementation("org.springframework.boot:spring-boot-starter-data-jpa:3.2.0")
}
}
Platform/BOM Dependencies
dependencies {
// GOOD: Import BOM (Bill of Materials) for version alignment
implementation(platform("org.springframework.boot:spring-boot-dependencies:3.2.0"))
// Now you can omit versions - they come from the BOM
implementation("org.springframework.boot:spring-boot-starter-web")
imple
…
## Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- **Author:** [b33eep](https://github.com/b33eep)
- **Source:** [b33eep/claude-code-setup](https://github.com/b33eep/claude-code-setup)
- **License:** MIT
- **Homepage:** https://b33eep.github.io/claude-code-setup/
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.