Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions .agents/guidelines/writing-style.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Writing style

Apply these rules to changed Markdown and KDoc prose. Preserve a file's valid local
structure when it is more specific.

## Write for the reader

- Explain the reader's problem before the implementation or solution details.
- Use direct, active sentences and concrete verbs.
- Prefer precise project terms over synonyms, marketing language, or jargon.
- State prerequisites before steps and expected outcomes after them.
- Verify factual claims against current code, tests, build configuration, or behavior.

## Format prose consistently

- Keep changed Markdown and KDoc prose at no more than 100 characters per source line.
- Use sentence case for headings.
- Use one top-level heading and do not skip heading levels.
- Format paths, identifiers, Gradle tasks, properties, flags, commands, and literals as code.
- Put multiline commands, configuration, source, output, and other machine text in fenced
code blocks with a language identifier when one applies.
- Align Markdown tables in source: pad every cell so column pipes line up vertically,
and size separator cells to the padded column widths. Re-align the full table after any edit.
- Use relative links for repository files.
- Prefer reference-style links for external destinations.

## Use typography deliberately

- Reserve typographic quotation marks for actual page or section titles, such as “Requirements”.
- Do not use quotation marks for emphasis, identifiers, invented labels, or technical
terms. Use plain prose, italics, or code formatting as appropriate.
- Do not leave runts or orphans. Reflow or rewrite a paragraph, list item, or table cell
whose final source line contains one word or an unusually short fragment.
- Avoid widows in rendered or paginated material. Keep headings with their following
content and avoid isolating a paragraph's opening or closing line.
- Avoid rivers when a rendered layout shows repeated aligned gaps through adjacent lines.
Reflow or rephrase the smallest affected passage.
- Do not add manual line breaks or non-breaking spaces merely to force a Markdown layout.

## Edit minimally

- Correct grammar only where needed for correctness, clarity, or consistency.
- Limit rewording and reflow to the affected sentence or paragraph.
- Preserve the author's meaning, the document's ownership, and established terminology.
- Do not restyle unrelated prose while making a focused change.
- Preserve code, machine-generated text, exact command output, logs, URLs, frontmatter,
serialized data, and license or copyright text verbatim unless the task targets it.
58 changes: 58 additions & 0 deletions .agents/skills/gradle-engineer/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
---
name: gradle-engineer
description: >-
Apply repository-specific Gradle engineering policy when changing or reviewing
build scripts, buildSrc, Kotlin DSL, GitHub Actions workflows, CI configuration,
plugin, extension, or task APIs, lazy configuration, task state,
configuration-cache behavior, TestKit coverage, consumer compatibility,
or publication metadata.
---

# Gradle engineering

Preserve Gradle semantics across the plugin and its build. Treat configuration avoidance,
task state, consumer compatibility, and cross-platform behavior as public contracts.

## Start

1. Read [`PROJECT.md`](../../../PROJECT.md) for the project map and supported behavior.
2. Read the affected build scripts, plugin API, and task types, along with
nearby unit and functional tests in full.
3. Trace values from the extension through `Provider` wiring into task inputs,
execution behavior, outputs, and local state.
4. Read [Gradle practices](references/gradle-practices.md) before editing; use it
as the source of truth for Gradle implementation and verification policy.
5. Clarify only material ambiguity in the public DSL, compatibility floor, or test target.

## Preserve CI behavior

- Read each changed workflow and the Gradle configuration it invokes in full.
- Preserve least-privilege permissions, supported operating-system coverage,
compatibility toolchains, and wrapper-based execution unless the request changes them.
- Keep CI commands aligned with local verification and publication tasks.

## Cross-domain work

- Apply [`kotlin-engineer`](../kotlin-engineer/SKILL.md) to Kotlin source and build logic.
- Apply [`security-engineer`](../security-engineer/SKILL.md) to release
downloads, integrity metadata, offline reuse, tokens, archives, and paths.

## Verify

Run the narrowest relevant command first, then broaden:

1. `./gradlew :gradle-plugin:test --tests <test-class>`
2. `./gradlew :gradle-plugin:functionalTest --tests <test-class>`
3. `./gradlew :gradle-plugin:test :gradle-plugin:functionalTest`
4. `./gradlew :gradle-plugin:validatePlugins`
5. `./gradlew check`

Add or run the minimum-version TestKit scenario when compatibility-sensitive
code changes. Exercise configuration-cache reuse when plugin or task wiring changes.
Exercise platform-specific behavior on the relevant operating system; report any
unavailable supported-platform probe instead of treating another host as proof.

## Report

Summarize the Gradle contract changed, focused and full checks run, supported
consumer/platform coverage, and any remaining unverified behavior.
4 changes: 4 additions & 0 deletions .agents/skills/gradle-engineer/agents/openai.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
interface:
display_name: "Gradle Engineer"
short_description: "Build robust Gradle plugin, build logic, and CI"
default_prompt: "Use $gradle-engineer to implement this Gradle, build-logic, or CI change."
163 changes: 163 additions & 0 deletions .agents/skills/gradle-engineer/references/gradle-practices.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
# Gradle practices

Use these rules when changing build logic or the Gradle-facing implementation.
Verify current versions and paths in the checkout before relying on this map.

## Contents

- [Project ownership](#project-ownership)
- [Lazy configuration](#lazy-configuration)
- [Task state and caching](#task-state-and-caching)
- [Configuration cache](#configuration-cache)
- [Compatibility and Kotlin runtime](#compatibility-and-kotlin-runtime)
- [Kotlin DSL and build logic](#kotlin-dsl-and-build-logic)
- [Cross-platform behavior](#cross-platform-behavior)
- [Publication](#publication)
- [Test strategy](#test-strategy)
- [Repository exclusions](#repository-exclusions)

## Project ownership

- Keep repository composition and dependency repositories in `settings.gradle.kts`.
- Keep shared coordinates and version application in the root build and `version.gradle.kts`.
- Keep build-only constants and dependency coordinates in `buildSrc/`.
- Keep shared JVM compilation and test setup in the `jvm-module` convention plugin.
- Keep plugin declarations, generated sources, and functional-test sources in
`gradle-plugin/build.gradle.kts`, together with publication metadata.
- Keep extension defaults and task registration in `EmbedCodePlugin`.
- Keep user-configurable values in `EmbedCodeExtension`.
- Keep execution behavior in typed task classes. Keep pure release, platform,
JSON, and checksum rules in focused Kotlin files.

## Lazy configuration

- Use `tasks.register`, `tasks.named`, provider mapping, and `flatMap`.
- Pass `TaskProvider` and provider-backed files through the graph; avoid `get()`
and other eager reads during configuration.
- Use conventions for defaults and preserve later user configuration.
- Use `disallowChanges()` only for values owned entirely by the plugin after wiring.
- Preserve task dependencies carried by `Provider<Directory>` and `ConfigurableFileCollection`.
- Avoid configuration-time downloads, process execution, directory creation,
and file reads whose result belongs to task execution.
- Select underscore-prefixed fallback task names from names already present when
the plugin is applied. Preserve the documented limitation for tasks registered later.

## Task state and caching

- Mark scalar and collection configuration with `@Input`.
- Mark source directories with `@InputDirectory` or `@InputFiles`; declare
`@Optional` only when absence is valid.
- Mark consumed artifacts with `@InputFile`.
- Mark reproducible task products with output annotations.
- Mark retained caches, downloaded assets, and integrity markers that should
not enter the build cache with `@LocalState`.
- Mark services, roots used only to validate other properties, working
directories, and secrets with `@Internal`.
- Choose `PathSensitivity.RELATIVE` for project content and
`PathSensitivity.NONE` when only file bytes matter.
- Disable build caching for in-place document mutation, external mutable
release state, or tasks whose primary purpose is validating local state.
- Override up-to-date behavior only with an explicit invariant; keep the install
task configured to rerun so it authenticates local installation state.

Classify each property by its role in task state:

```kotlin
// Correct: configuration is an input, retained cache data is local state,
// and a secret stays out of task fingerprints.
@get:Input
public abstract val version: Property<String>

@get:LocalState
public abstract val cachedAssetFile: RegularFileProperty

@get:Internal
public abstract val githubToken: Property<String>
```

Do not flatten properties with different roles into inputs or outputs:

```kotlin
// Incorrect: the secret enters task fingerprints, and mutable cache data
// is presented as a reproducible task output.
@get:Input
public abstract val githubToken: Property<String>

@get:OutputFile
public abstract val cachedAssetFile: RegularFileProperty
```

## Configuration cache

- Inject `ExecOperations` and other Gradle services into task types.
- Resolve extension values into task properties during configuration.
- Avoid retaining `Project`, extension objects, closures over project state, or
arbitrary mutable objects for task execution.
- Keep task actions dependent only on declared task properties, injected
services, and intentional internal/local state.
- Verify a second invocation reports configuration-cache reuse after changing
plugin application, registration, task properties, or process execution.

## Compatibility and Kotlin runtime

- Read the minimum supported Gradle version from `README.md` and keep it covered
by a versioned TestKit scenario.
- Treat the wrapper as the development runtime, not as the consumer floor.
- Read the build JDK and bytecode targets from `BuildSettings`; read Kotlin
language and API levels from `jvm-module.gradle.kts`.
- Keep plugin standard-library dependencies `compileOnly`. Supply explicit test
runtime dependencies where tests need Gradle and Kotlin classes.
- Avoid Kotlin or Gradle APIs introduced after the supported consumer floor
unless a compatible alternative and versioned TestKit coverage protect their use.
- Change the floor together with `README.md`, compatibility tests, relevant
build settings, and publication claims.

## Kotlin DSL and build logic

- Prefer typed Kotlin DSL accessors and typed task registration.
- Keep reusable module policy in convention plugins rather than copying blocks between projects.
- Keep dependency coordinates centralized only when that improves ownership;
avoid abstraction for a single opaque use.
- Keep public plugin configuration in `build.gradle.kts`. Do not require users
to maintain an additional YAML file.
- Treat internally generated JSON configuration as task implementation state,
not as a public configuration surface.

## Cross-platform behavior

- Use Gradle file properties and Java path APIs instead of string concatenation for paths.
- Preserve Windows `.exe` naming and Linux/macOS executable permissions.
- Keep path comparisons case- and separator-aware. Do not use a probe on one
supported operating system as proof for another.
- Avoid shell-specific execution; pass executable and arguments separately.
- Preserve stable argument ordering and messages when tests or users rely on them.
- Add platform conditions only for unsupported host behavior; do not hide portable failures.

## Publication

- Keep `io.spine.embed-code` and its implementation class stable unless migration is requested.
- Keep display name, description, website, VCS URL, and tags consistent with README terminology.
- Keep Maven artifact ID, POM name, description, license, developers, and SCM
coordinates aligned with the plugin declaration.
- Keep `LICENSE` in published JARs and keep sources and Javadoc artifacts.
- Run `validatePlugins` after changing task annotations, plugin declarations,
extension types, or publication configuration.

## Test strategy

- Use unit tests for pure version, checksum, JSON, and platform rules.
- Use TestKit functional tests for plugin application, DSL wiring, task
dependencies, task-name collisions, help output, configuration-cache reuse,
publication-facing behavior, and real Gradle failures.
- Keep a versioned TestKit probe on the minimum supported Gradle version.
- Assert task outcomes, generated files, process arguments, and actionable
output rather than internal registration details alone.
- Run focused tests while iterating, then unit and functional tests, `validatePlugins`, and `check`.

## Repository exclusions

- Preserve `FAIL_ON_PROJECT_REPOS` in `settings.gradle.kts`; do not add
organization-wide repository content filters unless this repository explicitly adopts them.
- Do not require dependency group names to contain `spine`.
- Keep `installEmbedCode` ungrouped and absent from the standard task list; keep
`checkEmbedding` and `embedCode` as the user-facing tasks.
32 changes: 32 additions & 0 deletions .agents/skills/kotlin-engineer/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
name: kotlin-engineer
description: >-
Use for implementing, refactoring, explaining, or reviewing Kotlin source and
Kotlin DSL files (`.kt` and `.kts`) in this repository, especially public
plugin APIs, Gradle task types, extensions, and build logic.
---

# Kotlin engineer

## Workflow

1. Read [the project context](../../../PROJECT.md), the complete affected files,
their nearest tests, and the build configuration that defines their runtime.
2. Identify whether the change affects a public Gradle API, task execution,
build configuration, serialization, file handling, or network behavior.
3. Read [the Kotlin policy](references/kotlin-policy.md) before editing; use it
as the source of truth for compatibility, declarations, style, failures, and KDoc.
4. Preserve the existing architecture and behavior outside the requested scope.
Prefer the smallest idiomatic change that makes the contract explicit.
5. Add or update tests through
[test-engineer](../test-engineer/SKILL.md) for every behavioral change.
6. Verify with the narrowest relevant Gradle task, then run the broader check
required by the changed surface.
7. Report the affected contract, files changed, and verification performed.

## Cross-domain work

- Apply [gradle-engineer](../gradle-engineer/SKILL.md) when Kotlin declarations
participate in Gradle APIs, task modeling, providers, or plugin lifecycle.
- Apply [security-engineer](../security-engineer/SKILL.md) when Kotlin changes affect
downloads, checksums, archives, paths, caches, processes, or credentials.
4 changes: 4 additions & 0 deletions .agents/skills/kotlin-engineer/agents/openai.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
interface:
display_name: "Kotlin Engineer"
short_description: "Implement idiomatic, compatible Kotlin changes"
default_prompt: "Use $kotlin-engineer to implement this Kotlin change in the repository."
Loading