[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6EBYP9E3V1MHAFVBPY9AXJX":3,"skill-same:01M6EBYP9E3V1MHAFVBPY9AXJX":97},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":26,"publishedAt":47,"linkOnly":48,"markdownContent":49,"markdownBody":50,"frontMatter":51,"refName":52,"commitSha":53,"skillDirectory":54,"forksCount":55,"repositoryHtmlUrl":56,"repositoryHomepageUrl":57,"ownerHtmlUrl":58,"ownerBlogUrl":6,"ownerDescription":59,"updatedAt":60,"install":61,"resources":74},"01M6EBYP9E3V1MHAFVBPY9AXJX","minecraft-ci-release",null,"Set up CI\u002FCD pipelines, automated publishing, and release workflows for Minecraft mods and plugins for 1.21.x. Covers GitHub Actions matrix builds for NeoForge and Fabric, automated publishing to Modrinth (via minotaur Gradle plugin) and CurseForge (via curseforgegradle), GitHub Releases with JAR artifacts, semantic versioning conventions for Minecraft mods, CHANGELOG generation, Dependabot for Gradle wrapper and plugin updates, build caching with gradle\u002Factions\u002Fsetup-gradle, pull request checks, and release tag workflows. Also covers Paper plugin CI with shadow JAR builds.","ComeOnOliver\u002Fskillshub","ComeOnOliver","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F43215937?v=4","01M6E5JNFECJAAVFE0W7SMWWD2","Haoran Shu","01M6E5JNNDQS7AJZDYFQ8TPZCK",67,"MIT","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002FJahrome907\u002Fminecraft-codex-skills\u002Fminecraft-ci-release\u002FSKILL.md",[18,23],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000011","运维与部署","SCENARIO","使用场景",{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发",[27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46],"minecraft ci release","release","ci","minecraft","SET","gradle","caching","releases","publishing","Wrapper","up","versioning","workflows","dependabot","github actions","actions","pull","changelog","artifacts","plugin","2026-11-10 10:12:30",false,"---\nname: minecraft-ci-release\ndescription: >\n  Set up CI\u002FCD pipelines, automated publishing, and release workflows for Minecraft\n  mods and plugins for 1.21.x. Covers GitHub Actions matrix builds for NeoForge and\n  Fabric, automated publishing to Modrinth (via minotaur Gradle plugin) and CurseForge\n  (via curseforgegradle), GitHub Releases with JAR artifacts, semantic versioning\n  conventions for Minecraft mods, CHANGELOG generation, Dependabot for Gradle wrapper\n  and plugin updates, build caching with gradle\u002Factions\u002Fsetup-gradle, pull request\n  checks, and release tag workflows. Also covers Paper plugin CI with shadow JAR builds.\n---\n\n# Minecraft CI \u002F Release Skill\n\n## Workflow Overview\n\n```\nPR opened → build + test checks\nmain branch push → build artifacts\nTag push (v*) → build + publish to Modrinth + CurseForge + GitHub Releases\n```\n\n### Routing Boundaries\n- `Use when`: the task is CI\u002FCD pipelines, release automation, artifact publishing, versioning, or release governance.\n- `Do not use when`: the task is implementing gameplay\u002Fplugin\u002Fmod features (`minecraft-modding`, `minecraft-plugin-dev`, `minecraft-datapack`).\n- `Do not use when`: the task is server runtime operations and infrastructure tuning (`minecraft-server-admin`).\n\n---\n\n## Versioning Convention\n\nMinecraft mod versions follow: `{mod_version}+{mc_version}`\n\n```\n1.0.0+1.21.1   ← mod 1.0.0 for MC 1.21.1\n1.2.3+1.21.1\n2.0.0+1.21.4\n```\n\nGit tag format: `v1.0.0` (mod version only, not MC version in the tag).\n\n---\n\n## Core CI Workflow (NeoForge + Fabric)\n\n### `.github\u002Fworkflows\u002Fbuild.yml`\n```yaml\nname: Build\n\non:\n  push:\n    branches: [\"main\", \"develop\"]\n  pull_request:\n    branches: [\"main\"]\n\npermissions:\n  contents: read\n\njobs:\n  build:\n    name: Build (${{ matrix.platform }})\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        platform: [neoforge, fabric]\n      fail-fast: false\n\n    steps:\n      - name: Checkout\n        uses: actions\u002Fcheckout@v4\n\n      - name: Set up Java 21\n        uses: actions\u002Fsetup-java@v4\n        with:\n          java-version: \"21\"\n          distribution: \"temurin\"\n\n      - name: Setup Gradle\n        uses: gradle\u002Factions\u002Fsetup-gradle@v3\n        with:\n          cache-read-only: ${{ github.ref != 'refs\u002Fheads\u002Fmain' }}\n\n      - name: Grant execute permission for gradlew\n        run: chmod +x gradlew\n\n      - name: Build (${{ matrix.platform }})\n        run: .\u002Fgradlew :${{ matrix.platform }}:build --no-daemon\n\n      - name: Upload artifacts\n        uses: actions\u002Fupload-artifact@v4\n        with:\n          name: mod-${{ matrix.platform }}-${{ github.sha }}\n          path: ${{ matrix.platform }}\u002Fbuild\u002Flibs\u002F*.jar\n          if-no-files-found: error\n```\n\n---\n\n## Release Workflow (with Publishing)\n\n### `.github\u002Fworkflows\u002Frelease.yml`\n```yaml\nname: Release\n\non:\n  push:\n    tags:\n      - \"v*\"\n\npermissions:\n  contents: write      # for creating GitHub releases\n\njobs:\n  release:\n    name: Release\n    runs-on: ubuntu-latest\n\n    steps:\n      - name: Checkout\n        uses: actions\u002Fcheckout@v4\n\n      - name: Set up Java 21\n        uses: actions\u002Fsetup-java@v4\n        with:\n          java-version: \"21\"\n          distribution: \"temurin\"\n\n      - name: Setup Gradle\n        uses: gradle\u002Factions\u002Fsetup-gradle@v3\n\n      - name: Grant execute permission for gradlew\n        run: chmod +x gradlew\n\n      - name: Extract version from tag\n        id: version\n        run: echo \"MOD_VERSION=${GITHUB_REF_NAME#v}\" >> $GITHUB_OUTPUT\n\n      - name: Build all platforms\n        run: .\u002Fgradlew build --no-daemon\n\n      - name: Publish to Modrinth & CurseForge\n        run: .\u002Fgradlew publishMods --no-daemon\n        env:\n          MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }}\n          CURSEFORGE_TOKEN: ${{ secrets.CURSEFORGE_TOKEN }}\n\n      - name: Create GitHub Release\n        uses: softprops\u002Faction-gh-release@v2\n        with:\n          files: |\n            fabric\u002Fbuild\u002Flibs\u002F*.jar\n            neoforge\u002Fbuild\u002Flibs\u002F*.jar\n          generate_release_notes: true\n          draft: false\n          prerelease: ${{ contains(github.ref_name, '-alpha') || contains(github.ref_name, '-beta') || contains(github.ref_name, '-rc') }}\n```\n\n---\n\n## Paper Plugin CI\n\n### `.github\u002Fworkflows\u002Fbuild.yml` (plugin)\n```yaml\nname: Build\n\non:\n  push:\n    branches: [\"main\"]\n  pull_request:\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions\u002Fcheckout@v4\n      - uses: actions\u002Fsetup-java@v4\n        with:\n          java-version: \"21\"\n          distribution: \"temurin\"\n      - uses: gradle\u002Factions\u002Fsetup-gradle@v3\n      - run: chmod +x gradlew\n      - run: .\u002Fgradlew shadowJar --no-daemon\n      - uses: actions\u002Fupload-artifact@v4\n        with:\n          name: plugin-${{ github.sha }}\n          path: build\u002Flibs\u002F*.jar\n\n  test:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions\u002Fcheckout@v4\n      - uses: actions\u002Fsetup-java@v4\n        with:\n          java-version: \"21\"\n          distribution: \"temurin\"\n      - uses: gradle\u002Factions\u002Fsetup-gradle@v3\n      - run: .\u002Fgradlew test --no-daemon\n```\n\n---\n\n## Modrinth Publishing (minotaur)\n\n### `build.gradle.kts` (root or platform-specific)\n```kotlin\nplugins {\n    id(\"com.modrinth.minotaur\") version \"2.8.7\"\n}\n\n\u002F\u002F === Fabric subproject ===\nmodrinth {\n    token.set(System.getenv(\"MODRINTH_TOKEN\") ?: \"\")\n    projectId.set(\"YOUR-PROJECT-ID\")    \u002F\u002F from modrinth.com project slug or ID\n\n    versionNumber.set(\"${project.version}\")\n    versionType.set(\"release\")          \u002F\u002F release | beta | alpha\n\n    uploadFile.set(tasks.remapJar)      \u002F\u002F the JAR to upload\n\n    gameVersions.addAll(\"1.21.1\")\n    loaders.addAll(\"fabric\")\n\n    changelog.set(\n        rootProject.file(\"CHANGELOG.md\").readText()\n            .substringAfter(\"## [${project.version}]\")\n            .substringBefore(\"\\n## [\")\n            .trim()\n    )\n\n    dependencies {\n        required.project(\"fabric-api\")\n        \u002F\u002F optional.project(\"some-optional-mod\")\n    }\n}\n```\n\n### Combined Fabric + NeoForge publish task (root-level)\n```kotlin\n\u002F\u002F root build.gradle.kts\ntasks.register(\"publishMods\") {\n    dependsOn(\":fabric:modrinth\", \":neoforge:modrinth\")\n    dependsOn(\":fabric:curseforge\", \":neoforge:curseforge\")\n    group = \"publishing\"\n    description = \"Publish all platforms to Modrinth and CurseForge\"\n}\n```\n\n---\n\n## CurseForge Publishing\n\n### `build.gradle.kts`\n```kotlin\nplugins {\n    id(\"net.darkhax.curseforgegradle\") version \"1.1.25\"\n}\n\ntasks.register\u003Cnet.darkhax.curseforgegradle.TaskPublishCurseForge>(\"curseforge\") {\n    apiToken = System.getenv(\"CURSEFORGE_TOKEN\") ?: \"\"\n\n    val cf = upload(PROJECT_ID, tasks.named(\"remapJar\"))  \u002F\u002F or shadowJar\n    cf.changelogType = \"markdown\"\n    cf.changelog = rootProject.file(\"CHANGELOG.md\").readText()\n        .substringAfter(\"## [${project.version}]\")\n        .substringBefore(\"\\n## [\")\n        .trim()\n\n    cf.releaseType = \"release\"\n    cf.addGameVersion(\"1.21.1\")\n    cf.addModLoader(\"Fabric\")     \u002F\u002F \"NeoForge\" for NeoForge subproject\n    cf.addRequirement(\"fabric-api\")\n    \u002F\u002F cf.addJavaVersion(\"Java 21\")\n\n    \u002F\u002F Replace PROJECT_ID with your numeric CurseForge project ID\n}\n```\n\n> Replace `PROJECT_ID` with your actual numeric CurseForge project ID (found in project settings).\n\n---\n\n## `gradle.properties` Secrets Pattern\n\nNever hardcode tokens. Read them from environment:\n\n```properties\n# gradle.properties (committed)\nmod_id=mymod\nmod_version=1.0.0\nminecraft_version=1.21.1\nmodrinth_project_id=AABBCCDD\ncurseforge_project_id=123456\n\n# DO NOT commit tokens\n# Set these as GitHub repo secrets:\n# MODRINTH_TOKEN, CURSEFORGE_TOKEN\n```\n\n---\n\n## Semantic Versioning for Mods\n\n| Change | Version bump |\n|--------|-------------|\n| New features, no breaking changes | Minor: `1.1.0` |\n| Bug fixes only | Patch: `1.0.1` |\n| API\u002Fconfig breaking changes | Major: `2.0.0` |\n| Minecraft version update | Keep mod version, change `+1.21.4` suffix |\n| Pre-release | `1.0.0-beta.1`, `1.0.0-rc.1` |\n\n---\n\n## CHANGELOG.md Convention\n\n```markdown\n# Changelog\n\n## [1.1.0] — 2025-06-01\n### Added\n- New `\u002Fkit` command\n- PDC-based kill tracker\n\n### Fixed\n- Death message not appearing on Paper 1.21.11\n\n## [1.0.0] — 2025-05-01\n### Added\n- Initial release\n```\n\nAutomate CHANGELOG parsing in Gradle (as shown above in modrinth block) by extracting\nthe section between version headers.\n\n---\n\n## Dependabot Configuration\n\n### `.github\u002Fdependabot.yml`\n```yaml\nversion: 2\nupdates:\n  - package-ecosystem: \"gradle\"\n    directory: \"\u002F\"\n    schedule:\n      interval: \"weekly\"\n    groups:\n      gradle-plugins:\n        patterns:\n          - \"com.gradleup.shadow\"\n          - \"dev.architectury.loom\"\n          - \"com.modrinth.minotaur\"\n          - \"net.darkhax.curseforgegradle\"\n\n  - package-ecosystem: \"github-actions\"\n    directory: \"\u002F\"\n    schedule:\n      interval: \"weekly\"\n```\n\n---\n\n## Build Caching Best Practices\n\n```yaml\n# In all workflow jobs:\n- name: Setup Gradle\n  uses: gradle\u002Factions\u002Fsetup-gradle@v3\n  with:\n    # Read-only cache on PRs, read-write on main\n    cache-read-only: ${{ github.event_name == 'pull_request' }}\n    # Cache Minecraft assets (speeds up loom tasks by minutes)\n    gradle-home-cache-includes: |\n      caches\n      notifications\n      .gradle\u002Floom-cache\n```\n\n---\n\n## Branch Protection + Required Checks\n\nRecommended GitHub branch protection for `main`:\n- Require status checks: `build (fabric)`, `build (neoforge)`, `test`\n- Require linear history (squash\u002Frebase merges)\n- Require signed commits (optional but recommended for release workflows)\n\n---\n\n## Tag and Release Script\n\n```bash\n#!\u002Fusr\u002Fbin\u002Fenv bash\n# scripts\u002Frelease.sh \u003Cversion>\n# Usage: .\u002Fscripts\u002Frelease.sh 1.1.0\nset -euo pipefail\n\nVERSION=\"${1:?Usage: release.sh \u003Cversion>}\"\n\n# Update gradle.properties\nsed -i \"s\u002F^mod_version=.*\u002Fmod_version=${VERSION}\u002F\" gradle.properties\n\n# Stage and commit\ngit add gradle.properties\ngit commit -m \"chore: release v${VERSION}\"\n\n# Tag\ngit tag \"v${VERSION}\"\n\necho \"Created commit and tag v${VERSION}\"\necho \"Push with: git push && git push --tags\"\n```\n\n## Workflow Snippet Validator\n\nUse the bundled validator script to keep `SKILL.md` workflow snippets copy-paste safe:\n\n```bash\n# Run from the installed skill directory:\n.\u002Fscripts\u002Fvalidate-workflow-snippets.sh --root .\n\n# Strict mode treats warnings as failures:\n.\u002Fscripts\u002Fvalidate-workflow-snippets.sh --root . --strict\n```\n\nThe validator is bundled and self-contained. Run it from a copied `.agents\u002F`,\n`.codex\u002F`, or `.claude\u002F` `minecraft-ci-release` skill directory without relying\non repo-root `node_modules`.\n\nWhat it checks:\n- YAML snippet structure for workflow-like blocks (`name`, `on`, `jobs`)\n- Unresolved placeholder tokens and suspicious glob patterns\n- `${{ secrets.* }}` usage stays consistent with secrets documented in this file\n\n---\n\n## References\n\n- GitHub Actions: https:\u002F\u002Fdocs.github.com\u002Fen\u002Factions\n- minotaur (Modrinth): https:\u002F\u002Fgithub.com\u002Fmodrinth\u002Fminotaur\n- curseforgegradle: https:\u002F\u002Fgithub.com\u002FDarkhax-Minecraft\u002FCurseForgeGradle\n- softprops\u002Faction-gh-release: https:\u002F\u002Fgithub.com\u002Fsoftprops\u002Faction-gh-release\n- gradle\u002Factions: https:\u002F\u002Fgithub.com\u002Fgradle\u002Factions\n- Modrinth API docs: https:\u002F\u002Fdocs.modrinth.com\u002F\n\n","# Minecraft CI \u002F Release Skill\n\n## Workflow Overview\n\n```\nPR opened → build + test checks\nmain branch push → build artifacts\nTag push (v*) → build + publish to Modrinth + CurseForge + GitHub Releases\n```\n\n### Routing Boundaries\n- `Use when`: the task is CI\u002FCD pipelines, release automation, artifact publishing, versioning, or release governance.\n- `Do not use when`: the task is implementing gameplay\u002Fplugin\u002Fmod features (`minecraft-modding`, `minecraft-plugin-dev`, `minecraft-datapack`).\n- `Do not use when`: the task is server runtime operations and infrastructure tuning (`minecraft-server-admin`).\n\n---\n\n## Versioning Convention\n\nMinecraft mod versions follow: `{mod_version}+{mc_version}`\n\n```\n1.0.0+1.21.1   ← mod 1.0.0 for MC 1.21.1\n1.2.3+1.21.1\n2.0.0+1.21.4\n```\n\nGit tag format: `v1.0.0` (mod version only, not MC version in the tag).\n\n---\n\n## Core CI Workflow (NeoForge + Fabric)\n\n### `.github\u002Fworkflows\u002Fbuild.yml`\n```yaml\nname: Build\n\non:\n  push:\n    branches: [\"main\", \"develop\"]\n  pull_request:\n    branches: [\"main\"]\n\npermissions:\n  contents: read\n\njobs:\n  build:\n    name: Build (${{ matrix.platform }})\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        platform: [neoforge, fabric]\n      fail-fast: false\n\n    steps:\n      - name: Checkout\n        uses: actions\u002Fcheckout@v4\n\n      - name: Set up Java 21\n        uses: actions\u002Fsetup-java@v4\n        with:\n          java-version: \"21\"\n          distribution: \"temurin\"\n\n      - name: Setup Gradle\n        uses: gradle\u002Factions\u002Fsetup-gradle@v3\n        with:\n          cache-read-only: ${{ github.ref != 'refs\u002Fheads\u002Fmain' }}\n\n      - name: Grant execute permission for gradlew\n        run: chmod +x gradlew\n\n      - name: Build (${{ matrix.platform }})\n        run: .\u002Fgradlew :${{ matrix.platform }}:build --no-daemon\n\n      - name: Upload artifacts\n        uses: actions\u002Fupload-artifact@v4\n        with:\n          name: mod-${{ matrix.platform }}-${{ github.sha }}\n          path: ${{ matrix.platform }}\u002Fbuild\u002Flibs\u002F*.jar\n          if-no-files-found: error\n```\n\n---\n\n## Release Workflow (with Publishing)\n\n### `.github\u002Fworkflows\u002Frelease.yml`\n```yaml\nname: Release\n\non:\n  push:\n    tags:\n      - \"v*\"\n\npermissions:\n  contents: write      # for creating GitHub releases\n\njobs:\n  release:\n    name: Release\n    runs-on: ubuntu-latest\n\n    steps:\n      - name: Checkout\n        uses: actions\u002Fcheckout@v4\n\n      - name: Set up Java 21\n        uses: actions\u002Fsetup-java@v4\n        with:\n          java-version: \"21\"\n          distribution: \"temurin\"\n\n      - name: Setup Gradle\n        uses: gradle\u002Factions\u002Fsetup-gradle@v3\n\n      - name: Grant execute permission for gradlew\n        run: chmod +x gradlew\n\n      - name: Extract version from tag\n        id: version\n        run: echo \"MOD_VERSION=${GITHUB_REF_NAME#v}\" >> $GITHUB_OUTPUT\n\n      - name: Build all platforms\n        run: .\u002Fgradlew build --no-daemon\n\n      - name: Publish to Modrinth & CurseForge\n        run: .\u002Fgradlew publishMods --no-daemon\n        env:\n          MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }}\n          CURSEFORGE_TOKEN: ${{ secrets.CURSEFORGE_TOKEN }}\n\n      - name: Create GitHub Release\n        uses: softprops\u002Faction-gh-release@v2\n        with:\n          files: |\n            fabric\u002Fbuild\u002Flibs\u002F*.jar\n            neoforge\u002Fbuild\u002Flibs\u002F*.jar\n          generate_release_notes: true\n          draft: false\n          prerelease: ${{ contains(github.ref_name, '-alpha') || contains(github.ref_name, '-beta') || contains(github.ref_name, '-rc') }}\n```\n\n---\n\n## Paper Plugin CI\n\n### `.github\u002Fworkflows\u002Fbuild.yml` (plugin)\n```yaml\nname: Build\n\non:\n  push:\n    branches: [\"main\"]\n  pull_request:\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions\u002Fcheckout@v4\n      - uses: actions\u002Fsetup-java@v4\n        with:\n          java-version: \"21\"\n          distribution: \"temurin\"\n      - uses: gradle\u002Factions\u002Fsetup-gradle@v3\n      - run: chmod +x gradlew\n      - run: .\u002Fgradlew shadowJar --no-daemon\n      - uses: actions\u002Fupload-artifact@v4\n        with:\n          name: plugin-${{ github.sha }}\n          path: build\u002Flibs\u002F*.jar\n\n  test:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions\u002Fcheckout@v4\n      - uses: actions\u002Fsetup-java@v4\n        with:\n          java-version: \"21\"\n          distribution: \"temurin\"\n      - uses: gradle\u002Factions\u002Fsetup-gradle@v3\n      - run: .\u002Fgradlew test --no-daemon\n```\n\n---\n\n## Modrinth Publishing (minotaur)\n\n### `build.gradle.kts` (root or platform-specific)\n```kotlin\nplugins {\n    id(\"com.modrinth.minotaur\") version \"2.8.7\"\n}\n\n\u002F\u002F === Fabric subproject ===\nmodrinth {\n    token.set(System.getenv(\"MODRINTH_TOKEN\") ?: \"\")\n    projectId.set(\"YOUR-PROJECT-ID\")    \u002F\u002F from modrinth.com project slug or ID\n\n    versionNumber.set(\"${project.version}\")\n    versionType.set(\"release\")          \u002F\u002F release | beta | alpha\n\n    uploadFile.set(tasks.remapJar)      \u002F\u002F the JAR to upload\n\n    gameVersions.addAll(\"1.21.1\")\n    loaders.addAll(\"fabric\")\n\n    changelog.set(\n        rootProject.file(\"CHANGELOG.md\").readText()\n            .substringAfter(\"## [${project.version}]\")\n            .substringBefore(\"\\n## [\")\n            .trim()\n    )\n\n    dependencies {\n        required.project(\"fabric-api\")\n        \u002F\u002F optional.project(\"some-optional-mod\")\n    }\n}\n```\n\n### Combined Fabric + NeoForge publish task (root-level)\n```kotlin\n\u002F\u002F root build.gradle.kts\ntasks.register(\"publishMods\") {\n    dependsOn(\":fabric:modrinth\", \":neoforge:modrinth\")\n    dependsOn(\":fabric:curseforge\", \":neoforge:curseforge\")\n    group = \"publishing\"\n    description = \"Publish all platforms to Modrinth and CurseForge\"\n}\n```\n\n---\n\n## CurseForge Publishing\n\n### `build.gradle.kts`\n```kotlin\nplugins {\n    id(\"net.darkhax.curseforgegradle\") version \"1.1.25\"\n}\n\ntasks.register\u003Cnet.darkhax.curseforgegradle.TaskPublishCurseForge>(\"curseforge\") {\n    apiToken = System.getenv(\"CURSEFORGE_TOKEN\") ?: \"\"\n\n    val cf = upload(PROJECT_ID, tasks.named(\"remapJar\"))  \u002F\u002F or shadowJar\n    cf.changelogType = \"markdown\"\n    cf.changelog = rootProject.file(\"CHANGELOG.md\").readText()\n        .substringAfter(\"## [${project.version}]\")\n        .substringBefore(\"\\n## [\")\n        .trim()\n\n    cf.releaseType = \"release\"\n    cf.addGameVersion(\"1.21.1\")\n    cf.addModLoader(\"Fabric\")     \u002F\u002F \"NeoForge\" for NeoForge subproject\n    cf.addRequirement(\"fabric-api\")\n    \u002F\u002F cf.addJavaVersion(\"Java 21\")\n\n    \u002F\u002F Replace PROJECT_ID with your numeric CurseForge project ID\n}\n```\n\n> Replace `PROJECT_ID` with your actual numeric CurseForge project ID (found in project settings).\n\n---\n\n## `gradle.properties` Secrets Pattern\n\nNever hardcode tokens. Read them from environment:\n\n```properties\n# gradle.properties (committed)\nmod_id=mymod\nmod_version=1.0.0\nminecraft_version=1.21.1\nmodrinth_project_id=AABBCCDD\ncurseforge_project_id=123456\n\n# DO NOT commit tokens\n# Set these as GitHub repo secrets:\n# MODRINTH_TOKEN, CURSEFORGE_TOKEN\n```\n\n---\n\n## Semantic Versioning for Mods\n\n| Change | Version bump |\n|--------|-------------|\n| New features, no breaking changes | Minor: `1.1.0` |\n| Bug fixes only | Patch: `1.0.1` |\n| API\u002Fconfig breaking changes | Major: `2.0.0` |\n| Minecraft version update | Keep mod version, change `+1.21.4` suffix |\n| Pre-release | `1.0.0-beta.1`, `1.0.0-rc.1` |\n\n---\n\n## CHANGELOG.md Convention\n\n```markdown\n# Changelog\n\n## [1.1.0] — 2025-06-01\n### Added\n- New `\u002Fkit` command\n- PDC-based kill tracker\n\n### Fixed\n- Death message not appearing on Paper 1.21.11\n\n## [1.0.0] — 2025-05-01\n### Added\n- Initial release\n```\n\nAutomate CHANGELOG parsing in Gradle (as shown above in modrinth block) by extracting\nthe section between version headers.\n\n---\n\n## Dependabot Configuration\n\n### `.github\u002Fdependabot.yml`\n```yaml\nversion: 2\nupdates:\n  - package-ecosystem: \"gradle\"\n    directory: \"\u002F\"\n    schedule:\n      interval: \"weekly\"\n    groups:\n      gradle-plugins:\n        patterns:\n          - \"com.gradleup.shadow\"\n          - \"dev.architectury.loom\"\n          - \"com.modrinth.minotaur\"\n          - \"net.darkhax.curseforgegradle\"\n\n  - package-ecosystem: \"github-actions\"\n    directory: \"\u002F\"\n    schedule:\n      interval: \"weekly\"\n```\n\n---\n\n## Build Caching Best Practices\n\n```yaml\n# In all workflow jobs:\n- name: Setup Gradle\n  uses: gradle\u002Factions\u002Fsetup-gradle@v3\n  with:\n    # Read-only cache on PRs, read-write on main\n    cache-read-only: ${{ github.event_name == 'pull_request' }}\n    # Cache Minecraft assets (speeds up loom tasks by minutes)\n    gradle-home-cache-includes: |\n      caches\n      notifications\n      .gradle\u002Floom-cache\n```\n\n---\n\n## Branch Protection + Required Checks\n\nRecommended GitHub branch protection for `main`:\n- Require status checks: `build (fabric)`, `build (neoforge)`, `test`\n- Require linear history (squash\u002Frebase merges)\n- Require signed commits (optional but recommended for release workflows)\n\n---\n\n## Tag and Release Script\n\n```bash\n#!\u002Fusr\u002Fbin\u002Fenv bash\n# scripts\u002Frelease.sh \u003Cversion>\n# Usage: .\u002Fscripts\u002Frelease.sh 1.1.0\nset -euo pipefail\n\nVERSION=\"${1:?Usage: release.sh \u003Cversion>}\"\n\n# Update gradle.properties\nsed -i \"s\u002F^mod_version=.*\u002Fmod_version=${VERSION}\u002F\" gradle.properties\n\n# Stage and commit\ngit add gradle.properties\ngit commit -m \"chore: release v${VERSION}\"\n\n# Tag\ngit tag \"v${VERSION}\"\n\necho \"Created commit and tag v${VERSION}\"\necho \"Push with: git push && git push --tags\"\n```\n\n## Workflow Snippet Validator\n\nUse the bundled validator script to keep `SKILL.md` workflow snippets copy-paste safe:\n\n```bash\n# Run from the installed skill directory:\n.\u002Fscripts\u002Fvalidate-workflow-snippets.sh --root .\n\n# Strict mode treats warnings as failures:\n.\u002Fscripts\u002Fvalidate-workflow-snippets.sh --root . --strict\n```\n\nThe validator is bundled and self-contained. Run it from a copied `.agents\u002F`,\n`.codex\u002F`, or `.claude\u002F` `minecraft-ci-release` skill directory without relying\non repo-root `node_modules`.\n\nWhat it checks:\n- YAML snippet structure for workflow-like blocks (`name`, `on`, `jobs`)\n- Unresolved placeholder tokens and suspicious glob patterns\n- `${{ secrets.* }}` usage stays consistent with secrets documented in this file\n\n---\n\n## References\n\n- GitHub Actions: https:\u002F\u002Fdocs.github.com\u002Fen\u002Factions\n- minotaur (Modrinth): https:\u002F\u002Fgithub.com\u002Fmodrinth\u002Fminotaur\n- curseforgegradle: https:\u002F\u002Fgithub.com\u002FDarkhax-Minecraft\u002FCurseForgeGradle\n- softprops\u002Faction-gh-release: https:\u002F\u002Fgithub.com\u002Fsoftprops\u002Faction-gh-release\n- gradle\u002Factions: https:\u002F\u002Fgithub.com\u002Fgradle\u002Factions\n- Modrinth API docs: https:\u002F\u002Fdocs.modrinth.com\u002F\n\n",{"name":5,"description":7},"main","def8531e65114c0fca8fb8551c1871ee0eed705c","skills\u002FJahrome907\u002Fminecraft-codex-skills\u002Fminecraft-ci-release",24,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub","https:\u002F\u002Fskillshub.wtf","https:\u002F\u002Fgithub.com\u002FComeOnOliver","AI & Blockchain Engineer\r\n","2026-06-24 22:07:19",{"source":8,"skillName":5,"commands":62,"prompt":72,"zipAvailable":73},[63,66,69],{"tool":64,"command":65},"npx","npx skills add ComeOnOliver\u002Fskillshub --skill minecraft-ci-release",{"tool":67,"command":68},"bunx","bunx skills add ComeOnOliver\u002Fskillshub --skill minecraft-ci-release",{"tool":70,"command":71},"pnpm","pnpm dlx skills add ComeOnOliver\u002Fskillshub --skill minecraft-ci-release","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002FJahrome907\u002Fminecraft-codex-skills\u002Fminecraft-ci-release\u002FSKILL.md",true,[75,81,85,89,93],{"path":76,"resourceType":77,"resourceTypeDesc":78,"sizeBytes":79,"sourceHtmlUrl":80},"agents\u002Fopenai.yaml","REFERENCE","参考文档",119,"https:\u002F\u002Fgithub.com\u002FThamielis\u002F.agents\u002Fblob\u002Fmain\u002Fplugins\u002Fcircleci\u002Fskills\u002Fconfig\u002Fagents\u002Fopenai.yaml",{"path":82,"resourceType":77,"resourceTypeDesc":78,"sizeBytes":83,"sourceHtmlUrl":84},"references\u002Fcache-optimization.md",5880,"https:\u002F\u002Fgithub.com\u002FThamielis\u002F.agents\u002Fblob\u002Fmain\u002Fplugins\u002Fcircleci\u002Fskills\u002Fconfig\u002Freferences\u002Fcache-optimization.md",{"path":86,"resourceType":77,"resourceTypeDesc":78,"sizeBytes":87,"sourceHtmlUrl":88},"references\u002Fpatterns.md",3381,"https:\u002F\u002Fgithub.com\u002FThamielis\u002F.agents\u002Fblob\u002Fmain\u002Fplugins\u002Fcircleci\u002Fskills\u002Fconfig\u002Freferences\u002Fpatterns.md",{"path":90,"resourceType":77,"resourceTypeDesc":78,"sizeBytes":91,"sourceHtmlUrl":92},"references\u002Fpersisting-data.md",3139,"https:\u002F\u002Fgithub.com\u002FThamielis\u002F.agents\u002Fblob\u002Fmain\u002Fplugins\u002Fcircleci\u002Fskills\u002Fconfig\u002Freferences\u002Fpersisting-data.md",{"path":94,"resourceType":77,"resourceTypeDesc":78,"sizeBytes":95,"sourceHtmlUrl":96},"references\u002Ftest-results-and-splitting.md",2851,"https:\u002F\u002Fgithub.com\u002FThamielis\u002F.agents\u002Fblob\u002Fmain\u002Fplugins\u002Fcircleci\u002Fskills\u002Fconfig\u002Freferences\u002Ftest-results-and-splitting.md",[98,108,118,127,133,140],{"skillNo":99,"name":100,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":101,"categories":102,"keywords":104,"publishedAt":47},"01M6FKJN13GMG4KY57J3QD8GY5","model-hierarchy-skill","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzscole\u002Fmodel-hierarchy-skill\u002Fmodel-hierarchy-skill\u002FSKILL.md",[103],{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},[105,106,107],"model","model hierarchy","model hierarchy skill",{"skillNo":109,"name":110,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":111,"categories":112,"keywords":114,"publishedAt":47},"01M6FKJJJ6GCAMR4PPPRD12M5X","zoom-mcp","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fzoom-mcp\u002FSKILL.md",[113],{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},[115,116,117],"MCP","zoom","zoom mcp",{"skillNo":119,"name":120,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":121,"categories":122,"keywords":123,"publishedAt":47},"01M6FKJE3KYT3KPEZMEEHYKA6K","zoom-apps-sdk","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fzoom-apps-sdk\u002FSKILL.md",[],[124,125,126,116],"sdk","zoom apps sdk","apps",{"skillNo":128,"name":129,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":130,"categories":131,"keywords":132,"publishedAt":47},"01M6FKJ9EDH9Q5VWDF8HAJRSP0","windows","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwindows\u002FSKILL.md",[],[129],{"skillNo":134,"name":135,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":136,"categories":137,"keywords":139,"publishedAt":47},"01M6FKJ666BEEFC3AE9GJ72Q93","whiteboard","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwhiteboard\u002FSKILL.md",[138],{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},[135],{"skillNo":141,"name":142,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":143,"categories":144,"keywords":145,"publishedAt":47},"01M6FKJ21WFCDGTJQ2Q91T9DVW","websockets","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwebsockets\u002FSKILL.md",[],[142]]