jdaugherty commented on PR #15805:
URL: https://github.com/apache/grails-core/pull/15805#issuecomment-5816385352

   AI Summary on how to implement this now: 
   
   # Self-publishing SkillsJars under your own groupId — findings, a Groovy 
Gradle plan, and a few asks
   
   ## Summary
   
   I like SkillsJars a lot: packaging Agent Skills as Maven artifacts solves 
versioning and distribution neatly, and the catalog makes skills easy to find. 
But as far as I can tell there's no way to publish a SkillsJar yourself — the 
only publishing path is the form on skillsjars.com, which deploys under 
`com.skillsjars`.
   
   After reading the docs, `SPEC.md`, and the Gradle plugin README, my 
understanding is:
   
   - The **catalog and the `com.skillsjars` namespace are closed.** Only their 
pipeline can publish there, and the catalog only lists that groupId.
   - The **JAR format and the build plugins are open.** You can package skills 
yourself, publish them under your own groupId (Maven Central, GitHub Packages, 
a private Nexus/Artifactory), and the current Gradle/sbt/Maven plugins will 
extract them like any catalog JAR. You just give up the catalog listing.
   
   Below is what I found, a worked plan for a Groovy Gradle build, the gotchas 
I hit, and some asks for the maintainers. Corrections welcome.
   
   ## What's closed vs. open
   
   ### Closed: the catalog and the `com.skillsjars` namespace
   
   From 
[`[SPEC.md](https://github.com/skillsjars/skillsjars/blob/main/SPEC.md)`](https://github.com/skillsjars/skillsjars/blob/main/SPEC.md):
   
   - The catalog browses Agent Skills that live on Maven Central under 
`com.skillsjars`; the groupId is always `com.skillsjars`, and the artifactId is 
`<org>__<repo>__<skill>`.
   - Publishing is a `POST /deploy` with `org` and `repo`. The service 
shallow-clones the public GitHub repo, builds one JAR per `SKILL.md`, versions 
it as `YYYY_MM_DD-<shorthash>` from the latest commit, GPG-signs the JAR and 
POM, and uploads the bundle to Maven Central.
   - Skills without a resolvable license are skipped.
   
   Since SkillsJars owns that namespace on Central, there's no way to publish 
into it yourself, and self-published artifacts won't appear in the catalog.
   
   ### Open: the format and the plugins
   
   - **JAR layout** 
([[docs](https://www.skillsjars.com/docs)](https://www.skillsjars.com/docs)): 
`META-INF/skills/<org>/<repo>/<skill>/SKILL.md`, with any files the skill 
references alongside it. The docs already describe packaging SkillsJars 
yourself with the Maven plugin's `package` goal, and the POM property 
convention `skillsjars.skill.<name>.allowed-tools`, which the plugin validates 
against the frontmatter.
   - **Gradle plugin** 
([[README](https://github.com/skillsjars/skillsjars-gradle-plugin)](https://github.com/skillsjars/skillsjars-gradle-plugin)):
 [[PR 
#1](https://github.com/skillsjars/skillsjars-gradle-plugin/pull/1)](https://github.com/skillsjars/skillsjars-gradle-plugin/pull/1)
 (merged 2026-09-06, released as 0.1.0 per the maintainer's comment) brought 
sbt-plugin parity. The plugin now:
     - resolves dependencies from a dedicated `skill` configuration (`skill 
'group:artifact:version'`), **for any groupId**, keeping them off the 
compile/runtime classpath;
     - looks for skill content in `META-INF/skills/` and 
`META-INF/resources/skills/`;
     - adds `packageSkillsJars`, which packs local `skills/` directories into 
`META-INF/skills/...` and is wired into `processResources`/`jar` when the 
`java` plugin is applied;
     - exposes a `skillsjars { gitHubUrl; allowedTools; outputDir }` extension 
and validates `allowed-tools` declarations during packaging.
   - **Spring AI**: the SkillsTool reads straight from 
`classpath:/META-INF/skills`, so JVM agents pick up self-published skills with 
no extraction step and no groupId dependence.
   
   > ⚠️ 
[[skillsjars.com/docs](https://www.skillsjars.com/docs)](https://www.skillsjars.com/docs)
 and 
[[/setup](https://www.skillsjars.com/setup)](https://www.skillsjars.com/setup) 
still show Gradle plugin `0.0.2`, and the setup guide says that version scans 
resolvable configurations for the `com.skillsjars` group only. Consumers on 
0.0.2 will not extract self-published JARs; they need ≥ 0.1.0.
   
   ## Plan: self-publishing from a Groovy Gradle project
   
   ### Layout
   
   One subproject per skill if you want independent versions (mirrors the 
one-JAR-per-skill model of the catalog); a single project if the skills should 
travel together — `packageSkillsJars` packs everything under `skills/`.
   
   ```
   agent-skills/
   ├── settings.gradle
   ├── build.gradle
   ├── skills/
   │   └── geb-testing/
   │       ├── SKILL.md
   │       └── references/
   └── .github/workflows/publish.yml
   ```
   
   ### Producer `build.gradle`
   
   ```groovy
   plugins {
       id 'java-library'
       id 'maven-publish'
       id 'signing'
       id 'com.skillsjars.gradle-plugin' version '0.1.0'
   }
   
   group = 'com.yourorg.skills'
   version = '1.0.0'   // semver — no longer tied to the date-hash scheme
   
   skillsjars {
       // Sets the path inside the JAR: 
META-INF/skills/yourorg/agent-skills/<skill>/
       gitHubUrl = 'https://github.com/yourorg/agent-skills'
       // Only for skills whose SKILL.md declares allowed-tools; the plugin 
validates the match
       allowedTools = ['geb-testing': 'Bash Read Edit']
   }
   
   // Central expects -sources and -javadoc jars even for resource-only 
artifacts; empty ones are fine
   java {
       withSourcesJar()
       withJavadocJar()
   }
   
   // Mirror what SkillsJars.com does: derive POM name/description from the 
frontmatter
   def frontMatter(File skillMd) {
       def m = (skillMd.text =~ /(?s)\A---\R(.*?)\R---/)
       m.find() ? m.group(1).readLines().findAll { it.contains(':') }
                   .collectEntries { def (k, v) = it.split(/:/, 2); 
[(k.trim()): v.trim()] } : [:]
   }
   def fm = frontMatter(file('skills/geb-testing/SKILL.md'))   // single-line 
YAML values only
   
   publishing {
       publications {
           skill(MavenPublication) {
               from components.java
               artifactId = 'geb-testing'
               pom {
                   name = fm.name
                   description = fm.description
                   url = 'https://github.com/yourorg/agent-skills'
                   licenses {
                       license {
                           name = fm.license ?: 'MIT'
                           url = 'https://opensource.org/licenses/MIT'
                       }
                   }
                   developers { developer { id = 'yourorg'; name = 'Your Org' } 
}
                   scm {
                       url = 'https://github.com/yourorg/agent-skills'
                       connection = 
'scm:git:https://github.com/yourorg/agent-skills.git'
                   }
                   // Same property convention as catalog JARs, readable 
without opening the JAR
                   properties = ['skillsjars.skill.geb-testing.allowed-tools': 
'Bash Read Edit']
               }
           }
       }
       repositories {
           maven {
               name = 'GitHubPackages'
               url = uri('https://maven.pkg.github.com/yourorg/agent-skills')
               credentials {
                   username = System.getenv('GITHUB_ACTOR')
                   password = System.getenv('GITHUB_TOKEN')
               }
           }
       }
   }
   
   signing {
       def key = System.getenv('SIGNING_KEY')
       if (key) {
           useInMemoryPgpKeys(key, System.getenv('SIGNING_PASSWORD'))
           sign publishing.publications
       }
   }
   ```
   
   ### Where to publish
   
   - **GitHub Packages / private Nexus / Artifactory** — no signing or POM 
ceremony required, but consumers need credentials in their `repositories {}` 
block.
   - **Maven Central under your own groupId** — go through the Sonatype Central 
Portal with a portal-aware plugin (e.g. `com.vanniktech.maven.publish` or 
`com.gradleup.nmcp`; check current versions). Requires a verified namespace, 
GPG signatures, full POM metadata (name, description, url, licenses, 
developers, scm), and sources/javadoc jars.
   
   ### Consumer `build.gradle`
   
   ```groovy
   plugins { id 'com.skillsjars.gradle-plugin' version '0.1.0' }
   
   repositories {
       mavenCentral()
       maven {
           url = uri('https://maven.pkg.github.com/yourorg/agent-skills')
           credentials { /* token */ }
       }
   }
   
   dependencies {
       skill 'com.yourorg.skills:geb-testing:1.0.0'                        // 
self-published
       skill 'com.skillsjars:anthropics__skills__pdf:2026_02_25-3d59511'   // 
from the catalog, same mechanism
   }
   
   skillsjars {
       outputDir = layout.projectDirectory.dir('.claude/skills')
   }
   ```
   
   Then `./gradlew extractSkillsJars`, add the output directory to 
`.gitignore`, and put the extract command in `AGENTS.md` / `CLAUDE.md` so 
agents run it on checkout.
   
   ### Local verification
   
   ```bash
   ./gradlew publishToMavenLocal
   unzip -l 
~/.m2/repository/com/yourorg/skills/geb-testing/1.0.0/geb-testing-1.0.0.jar | 
grep META-INF/skills
   ```
   
   Then add `mavenLocal()` to a consumer project and run `extractSkillsJars` 
before publishing anywhere remote.
   
   ### CI
   
   One workflow: on tag → `./gradlew publish`, with `GITHUB_TOKEN` (or Central 
Portal credentials), `SIGNING_KEY`, and `SIGNING_PASSWORD` as secrets.
   
   ## Gotchas
   
   1. **Extraction directory naming.** Extraction writes 
`skillsjars__yourorg__agent-skills__geb-testing/`, not `geb-testing/`. 
[[skillsjars-maven-plugin#4](https://github.com/skillsjars/skillsjars-maven-plugin/issues/4)](https://github.com/skillsjars/skillsjars-maven-plugin/issues/4)
 notes that some assistants require the skill directory to match the 
frontmatter `name`. A small `Sync` task that renames after extraction works 
around it.
   2. **Plugin version skew.** The public docs still reference 0.0.2, whose 
extractor only saw the `com.skillsjars` group. Anyone consuming self-published 
JARs must be on ≥ 0.1.0.
   3. **Libraries carrying their own skill.** Putting `skills/` in a library 
project bakes the skill into that library's JAR. Classpath-reading agents 
(Spring AI) find it automatically, but file-based assistants still need the 
consumer to list the coordinate under `skill` for extraction.
   4. **Discoverability is the real cost.** For public skills the two paths 
coexist: self-publish under your groupId for semver and private consumers, 
*and* run the same public repo through the skillsjars.com form so it also 
appears in the catalog as 
`com.skillsjars:yourorg__agent-skills__geb-testing:<date-hash>`.
   
   ## Asks / questions for the maintainers
   
   1. Update 
[[/docs](https://www.skillsjars.com/docs)](https://www.skillsjars.com/docs) and 
[[/setup](https://www.skillsjars.com/setup)](https://www.skillsjars.com/setup) 
to 0.1.0 and document the `skill` configuration, `packageSkillsJars`, and the 
`skillsjars {}` extension for Gradle.
   2. Document self-publishing (JAR layout + POM property conventions) as a 
supported path, even if the catalog stays `com.skillsjars`-only. Right now the 
only hint is one sentence about packaging with the Maven plugin.
   3. Would the catalog ever index skills outside `com.skillsjars` — e.g. an 
opt-in registration of coordinates, or an indexer that looks for 
`META-INF/skills` in Central artifacts? That would keep self-published skills 
discoverable, which is the main thing lost today.
   4. Does the Gradle plugin's `allowedTools` map get written into the 
generated POM as `skillsjars.skill.<name>.allowed-tools`, or is that left to 
`maven-publish` (as in the plan above)? The README isn't explicit.
   5. A flag on the extract tasks to use the frontmatter `name` as the output 
directory (see maven-plugin#4) would help assistants that require 
directory/name parity.
   
   ## References
   
   - Docs: https://www.skillsjars.com/docs
   - Setup guide: https://www.skillsjars.com/setup
   - SPEC.md: https://github.com/skillsjars/skillsjars/blob/main/SPEC.md
   - Gradle plugin: https://github.com/skillsjars/skillsjars-gradle-plugin
   - Gradle plugin PR #1 (sbt parity, 0.1.0): 
https://github.com/skillsjars/skillsjars-gradle-plugin/pull/1
   - sbt plugin: https://github.com/skillsjars/skillsjars-sbt-plugin
   - Maven plugin: https://github.com/skillsjars/skillsjars-maven-plugin
   - Directory-naming issue: 
https://github.com/skillsjars/skillsjars-maven-plugin/issues/4


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to