kotlin-backend-jpa-ent…
Model Kotlin persistence code correctly for Spring Data JPA and Hibernate. Covers entity design, identity and equality,…
Load when authoring, writing, or designing a Kotlin Toolchain local plugin to extend the declarative build with code generation, build-time processing, custom verification, or packaging that module.yaml cannot express, or when referencing @TaskAction, @Configurable, plugin.yaml,
Claude Code
$ npx -y skills add kotlin/kotlin-agent-skills --skill kotlin-tooling-kotlin-toolchain-plugin-authoring --agent claude-code
Codex
$ npx skills add kotlin/kotlin-agent-skills --skill kotlin-tooling-kotlin-toolchain-plugin-authoring -a codex -y
Cursor
$ npx skills add kotlin/kotlin-agent-skills --skill kotlin-tooling-kotlin-toolchain-plugin-authoring -a cursor -y
Gemini CLI
$ npx skills add kotlin/kotlin-agent-skills --skill kotlin-tooling-kotlin-toolchain-plugin-authoring -a gemini-cli -y
GitHub Copilot
$ npx skills add kotlin/kotlin-agent-skills --skill kotlin-tooling-kotlin-toolchain-plugin-authoring -a github-copilot -y
OpenCode
$ npx skills add kotlin/kotlin-agent-skills --skill kotlin-tooling-kotlin-toolchain-plugin-authoring -a opencode -y
Windsurf
$ npx skills add kotlin/kotlin-agent-skills --skill kotlin-tooling-kotlin-toolchain-plugin-authoring -a windsurf -y
name: kotlin-tooling-kotlin-toolchain-plugin-authoring description: > Load when authoring, writing, or designing a Kotlin Toolchain local plugin to extend the declarative build with code generation, build-time processing, custom verification, or packaging that module.yaml cannot express, or when referencing @TaskAction, @Configurable, plugin.yaml, or jvm/amper-plugin. Skip for porting an existing Gradle plugin. license: Apache-2.0 metadata: author: github:@singleton11 version: "0.1.0"
Local plugins are the official escape hatch from declarative YAML: a `jvm/amper-plugin` module shipping task actions, settings, and generated sources/resources alongside your project. Code patterns to adapt are in [references/examples.md](references/examples.md).
Write one when you need:
transformation, version stamping).
`project.version`.
Don't write one when `module.yaml` already covers it (dependencies, JDK provisioning, source layouts, basic packaging), and never to reuse a Gradle plugin — the Kotlin Toolchain cannot consume them.
repo-root/
├── kotlin, kotlin.bat # wrappers (from `kotlin init`)
├── project.yaml # registers the plugin
├── plugins/<name>/
│ ├── module.yaml # product: jvm/amper-plugin
│ ├── plugin.yaml # tasks: + commands: + generated:
│ └── src/
│ ├── Settings.kt # @Configurable interface
│ ├── tasks/ # one @TaskAction per file
│ │ ├── Foo.kt
│ │ └── FooSteps.kt # internal shared helpers (not @TaskAction)
│ └── <domain logic>/
└── <consumer-module>/
└── module.yaml # plugins: { <name>: enabled: true, ... }Keep at least one consumer module in the repo — it is the only way to exercise the plugin end-to-end, and plugins cannot be published to any public registry yet.
modules: - consumer-app - plugins/<name> plugins: - ./plugins/<name>
Without the top-level `plugins:` block the plugin id is unresolvable from any consumer.
product: jvm/amper-plugin # marks the module as a plugin
dependencies:
- <coordinate>:<version>
- <coordinate>:<version>: runtime-only # required only at runtime
- <coordinate>:<version>: compile-only
pluginInfo:
id: <plugin-id> # what consumers write under `plugins:`
settingsClass: <fully.qualified.Settings> # the @Configurable interface
settings:
jvm:
jdk:
version: 21
kotlin:
languageVersion: 2.1Defaults go in interface property getters; nested blocks become nested `@Configurable` interfaces.
@Configurable
interface Settings {
val someValue: String get() = "default"
val checks: ChecksSettings
}
@Configurable
interface ChecksSettings {
val strict: Boolean get() = true
}Consumers override what they need in `module.yaml`; omitted values fall back to the getter default:
plugins:
<plugin-id>:
enabled: true
someValue: "override"
checks:
strict: falseTask actions are top-level `fun`s, called when the matching `plugin.yaml` entry executes.
@TaskAction
fun foo(
@Input moduleRootDir: Path,
@Output outputDir: Path,
settings: Settings,
) {
// body
}to the exact `Path` you received, or downstream references won't find the result.
A `@TaskAction` is skipped when its declared inputs are unchanged. Tasks whose real inputs are Git history, the network, or environment variables cannot be fingerprinted, so opt out:
@TaskAction(executionAvoidance = ExecutionAvoidance.Disabled)
fun foo(@Output outputDir: Path, settings: Settings) { /* ... */ }Tasks with no `@Output` are never cached and always re-run — correct for purely side-effecting tasks (releases, deployments, pushes).
tasks:
foo:
action: !<fully.qualified.foo>
moduleRootDir: ${module.rootDir}
outputDir: ${taskOutputDir}
settings: ${pluginSettings}
bar:
action: !<fully.qualified.bar>
input: ${tasks.foo.action.outputDir}/result.txt
settings: ${pluginSettings}
generated:
resources:
- directory: ${tasks.foo.action.outputDir}
commands:
- foo| Reference | Resolves to | |---|---| | `${module.rootDir}` | Directory containing the consumer's `module.yaml`. Pass as `@Input` to inspect the consumer's tree. | | `${taskOutputDir}` | Toolchain-managed per-task output directory. Pass as `@Output`. | | `${pluginSettings}` | The `@Configurable` object built from the consumer's `module.yaml`. | | `${tasks.<task>.action.<param>}` | Another task's parameter — used in `generated.*` and to wire one task's `@Input` to another's `@Output`. |
Both register a directory (usually a task's `@Output`) as a contribution to the consumer's build, and both auto-wire the producing task to run first:
A collection of AI agent skills useful for projects using the Kotlin language. Skills are following the Agent Skills standard, see agentskills.io for more information.
Model Kotlin persistence code correctly for Spring Data JPA and Hibernate. Covers entity design, identity and equality,…
Migrates Kotlin Multiplatform (KMP) projects to Android Gradle Plugin 9.0+. Handles plugin replacement…
Migrate KMP projects from CocoaPods (kotlin("native.cocoapods")) to Swift Package Manager (swiftPMDependencies DSL) — replaces…
Load when porting, converting, or reimplementing a single Gradle plugin as a Kotlin Toolchain local plugin, or when mapping…
Load when migrating or converting an entire Gradle Kotlin project (build.gradle(.kts), wrapper, libs.versions.toml, buildSrc) to…
Migrate Kotlin (and Java) code from kotlinx.collections.immutable 0.3.x / 0.4.x to the latest 0.5.x. The 0.5.x line renames every…
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…
Ask which skill or flow fits your situation. A router over the skills in this repo.