[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6D2JMDGET8MXFNEHST1GS9Q":3,"skill-same:01M6D2JMDGET8MXFNEHST1GS9Q":91},{"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":6,"ownerHtmlUrl":57,"ownerBlogUrl":58,"ownerDescription":59,"updatedAt":60,"install":61,"resources":74},"01M6D2JMDGET8MXFNEHST1GS9Q","minecraft-ci-release",null,"Set up and review CI, artifact publishing, versioning, and release management for Minecraft 26.x or legacy 1.21.x mods and Paper plugins. Use for pipelines and releases, not gameplay implementation or server operations.","Jahrome907\u002Fminecraft-agent-skills","Jahrome907","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F222458345?v=4","01M6D2JFFY1EQCC572G6G3X1R2","Joe ","01M6D2JFS2EE87QN8QCFVFY6M8",197,"MIT","https:\u002F\u002Fgithub.com\u002FJahrome907\u002Fminecraft-agent-skills\u002Fblob\u002Fmain\u002F.agents\u002Fskills\u002Fminecraft-ci-release\u002FSKILL.md",[18,23],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000021","资料检索与研究","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","minecraft ci release","ci","release","up","artifact","Legacy","implementation","releases","release management","publishing","gameplay","server","review","use","operations","management","versioning","SET","plugins","2026-11-10 10:12:30",false,"---\nname: minecraft-ci-release\ndescription: \"Set up and review CI, artifact publishing, versioning, and release management for Minecraft 26.x or legacy 1.21.x mods and Paper plugins. Use for pipelines and releases, not gameplay implementation or server operations.\"\n---\n\n# Minecraft CI \u002F Release Skill\n\n## Routing Boundaries\n- `Use when`: the task is CI\u002FCD pipelines, artifact publishing, versioning, or release management.\n- `Do not use when`: the task is gameplay or plugin implementation (`minecraft-modding`, `minecraft-plugin-dev`, or `minecraft-datapack`).\n- `Do not use when`: the task is server runtime operations or infrastructure tuning (`minecraft-server-admin`).\n\n---\n\n## Release setup\n\nKeep each repository's existing release destinations and approval policy. A tag can\nbuild an artifact and create a GitHub Release without publishing to Modrinth or\nCurseForge. Add a publisher only when the project already uses it or the user asks\nfor it. Never add tokens to committed files.\n\nFor Minecraft 26.x, use Java 25 and state that in workflow labels\nand examples. Legacy Minecraft 1.21.x projects stay on Java 21; retain their own\nloader and Gradle conventions instead of mechanically changing their version.\n\nUse an immutable GitHub Action revision in a protected workflow. The following refs\nwere verified from the upstream tags on 2026-10-29; refresh them from the upstream\ntag before intentionally upgrading an action:\n\n```text\nactions\u002Fcheckout@v7.0.1             3d3c42e5aac5ba805825da76410c181273ba90b1\nactions\u002Fsetup-java@v6.0.0           dd06d9cba3e5552c54d9f8ea23572deb30010f7c\ngradle\u002Factions\u002Fsetup-gradle@v6.3.0  9c971963bec38e04b3d30dcc455b5382be2fdbfb\nactions\u002Fupload-artifact@v7.0.1      043fb46d1a93c77aae656e7c1c64a875d1fc6a0a\nsoftprops\u002Faction-gh-release@v3.0.3  efb35369e0ad2afab669f228072c1b0d510eae64\n```\n\n## Version and Tag Convention\n\nWhen the project uses a Minecraft-version suffix, follow `{mod_version}+{mc_version}`:\n\n```\n1.0.0+26.3  ← mod 1.0.0 for MC 26.3\n1.2.3+26.3\n2.0.0+26.3\n```\n\nUse a release version without the game suffix for the Git tag, and retain the\nMinecraft version in the artifact version when the project uses that convention:\n\n```text\nmod_version: 1.2.3\nproject\u002Fartifact version: 1.2.3+26.3\ntag: v1.2.3\n```\n\nThe release workflow must verify that `v1.2.3` matches `mod_version=1.2.3` before\nbuilding. Do not override `mod_version` from the tag, because that hides a mismatch.\nThe Gradle task and safe changelog extraction are in\n[the publishing reference](references\u002Fpublishing-gradle.md).\n\n---\n\n## Core CI Workflow (NeoForge + Fabric)\n\nThis is a Minecraft 26.x \u002F Java 25 example. Its displayed check names are\n`Build \u002F Build (fabric)`, `Build \u002F Build (neoforge)`, and `Build \u002F Test` after\nthe test job below is added. After the first successful pull request, copy the\nexact names GitHub displays into branch protection; workflow or job renames\nchange the required-check context.\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@3d3c42e5aac5ba805825da76410c181273ba90b1\n\n      - name: Set up Java 25\n        uses: actions\u002Fsetup-java@dd06d9cba3e5552c54d9f8ea23572deb30010f7c\n        with:\n          java-version: \"25\"\n          distribution: \"temurin\"\n\n      - name: Setup Gradle\n        uses: gradle\u002Factions\u002Fsetup-gradle@9c971963bec38e04b3d30dcc455b5382be2fdbfb\n        with:\n          cache-read-only: ${{ github.event_name == 'pull_request' }}\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@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a\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  test:\n    name: Test\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout\n        uses: actions\u002Fcheckout@3d3c42e5aac5ba805825da76410c181273ba90b1\n      - name: Set up Java 25\n        uses: actions\u002Fsetup-java@dd06d9cba3e5552c54d9f8ea23572deb30010f7c\n        with:\n          distribution: temurin\n          java-version: \"25\"\n      - name: Set up Gradle\n        uses: gradle\u002Factions\u002Fsetup-gradle@9c971963bec38e04b3d30dcc455b5382be2fdbfb\n      - name: Run tests\n        run: .\u002Fgradlew test --no-daemon\n```\n\n---\n\n## Tagged GitHub Release\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 tagged source\n        uses: actions\u002Fcheckout@3d3c42e5aac5ba805825da76410c181273ba90b1\n\n      - name: Set up Java 25\n        uses: actions\u002Fsetup-java@dd06d9cba3e5552c54d9f8ea23572deb30010f7c\n        with:\n          java-version: \"25\"\n          distribution: \"temurin\"\n\n      - name: Setup Gradle\n        uses: gradle\u002Factions\u002Fsetup-gradle@9c971963bec38e04b3d30dcc455b5382be2fdbfb\n\n      - name: Grant execute permission for gradlew\n        run: chmod +x gradlew\n\n      - name: Validate tag and build\n        env:\n          MOD_VERSION: ${{ github.ref_name }}\n        run: |\n          MOD_VERSION=\"${MOD_VERSION#v}\"\n          .\u002Fgradlew verifyReleaseVersion build --no-daemon \\\n            -PreleaseModVersion=\"$MOD_VERSION\"\n\n      - name: Select release artifacts\n        env:\n          RELEASE_TAG: ${{ github.ref_name }}\n        run: |\n          mkdir -p release-artifacts\n          shopt -s nullglob\n          select_primary() {\n            local loader=\"$1\"; shift\n            local matches=( \"$@\" )\n            if (( ${#matches[@]} != 1 )); then\n              printf 'Expected one %s primary JAR, found %s: %s\\n' \\\n                \"$loader\" \"${#matches[@]}\" \"${matches[*]:-none}\" >&2\n              exit 1\n            fi\n            cp \"${matches[0]}\" \"release-artifacts\u002F${loader}-${RELEASE_TAG}.jar\"\n          }\n          select_primary fabric fabric\u002Fbuild\u002Flibs\u002F*-fabric.jar\n          select_primary neoforge neoforge\u002Fbuild\u002Flibs\u002F*-neoforge.jar\n\n      - name: Create GitHub Release\n        uses: softprops\u002Faction-gh-release@efb35369e0ad2afab669f228072c1b0d510eae64\n        with:\n          files: |\n            release-artifacts\u002Ffabric-${{ github.ref_name }}.jar\n            release-artifacts\u002Fneoforge-${{ github.ref_name }}.jar\n          fail_on_unmatched_files: true\n          generate_release_notes: true\n          prerelease: ${{ contains(github.ref_name, '-alpha') || contains(github.ref_name, '-beta') || contains(github.ref_name, '-rc') }}\n```\n\nThis workflow creates a GitHub Release only. It expects one primary Fabric JAR and\none primary NeoForge JAR with loader-distinct names. Configure those classifiers in\nthe project build, then change both patterns together if its naming convention differs.\nThe selection step fails for zero or multiple matches and copies to distinct release\nnames, preventing accidental overwrite or a partial release. Add a project-specific\npublisher after version validation only when that destination is in scope.\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@3d3c42e5aac5ba805825da76410c181273ba90b1\n      - uses: actions\u002Fsetup-java@dd06d9cba3e5552c54d9f8ea23572deb30010f7c\n        with:\n          java-version: \"25\"\n          distribution: \"temurin\"\n      - uses: gradle\u002Factions\u002Fsetup-gradle@9c971963bec38e04b3d30dcc455b5382be2fdbfb\n      - run: chmod +x gradlew\n      - run: .\u002Fgradlew build --no-daemon\n      - uses: actions\u002Fupload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a\n        with:\n          name: plugin-${{ github.sha }}\n          path: build\u002Flibs\u002F*.jar\n          if-no-files-found: error\n\n  test:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions\u002Fcheckout@3d3c42e5aac5ba805825da76410c181273ba90b1\n      - uses: actions\u002Fsetup-java@dd06d9cba3e5552c54d9f8ea23572deb30010f7c\n        with:\n          java-version: \"25\"\n          distribution: \"temurin\"\n      - uses: gradle\u002Factions\u002Fsetup-gradle@9c971963bec38e04b3d30dcc455b5382be2fdbfb\n      - run: .\u002Fgradlew test --no-daemon\n```\n\n---\n\n## Publishing and Changelog Details\n\nRead [the publishing reference](references\u002Fpublishing-gradle.md) only when the\nproject publishes to Modrinth or CurseForge. It includes current plugin versions,\n26.x `jar` selection, explicit legacy Loom `remapJar` guidance, version verification,\nand a parser that fails when the expected changelog heading is missing.\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=26.3\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 | Follow the project's version policy, update the game suffix when used, and create a new release tag |\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] — 2026-10-01\n### Added\n- New `\u002Fkit` command\n- PDC-based kill tracker\n\n### Fixed\n- Death message not appearing on Paper 26.3\n\n## [1.0.0] — 2026-09-01\n### Added\n- Initial release\n```\n\nThe publishing reference extracts this section by `mod_version` and fails clearly\nwhen the expected heading is missing.\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@9c971963bec38e04b3d30dcc455b5382be2fdbfb\n  with:\n    # Read-only cache on PRs, read-write on main\n    cache-read-only: ${{ github.event_name == 'pull_request' }}\n```\n\n---\n\n## Branch Protection + Required Checks\n\nRecommended GitHub branch protection for `main`:\n- Require the observed checks: `Build \u002F Build (fabric)`, `Build \u002F Build (neoforge)`, and `Build \u002F 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 \u003Cmod-version>\nset -euo pipefail\n\nVERSION=\"${1:?Usage: release.sh \u003Cmod-version>}\"\nREMOTE=\"${RELEASE_REMOTE:-origin}\"\nBRANCH=\"${RELEASE_BRANCH:-main}\"\nEXPECTED_REMOTE_URL=\"${RELEASE_REMOTE_URL:?Set RELEASE_REMOTE_URL to the expected push URL}\"\ngit diff --check\n[[ -z \"$(git status --porcelain=v1 --untracked-files=all)\" ]] \\\n  || { echo \"Working tree contains staged, unstaged, or untracked files.\" >&2; exit 1; }\n[[ \"$(git branch --show-current)\" == \"$BRANCH\" ]] \\\n  || { echo \"Release must start from branch $BRANCH.\" >&2; exit 1; }\nmapfile -t PUSH_URLS \u003C \u003C(git remote get-url --push --all \"$REMOTE\")\n[[ ${#PUSH_URLS[@]} -eq 1 && \"${PUSH_URLS[0]}\" == \"$EXPECTED_REMOTE_URL\" ]] \\\n  || { echo \"Remote $REMOTE must have one expected push URL.\" >&2; exit 1; }\n! git rev-parse --verify --quiet \"refs\u002Ftags\u002Fv${VERSION}\" >\u002Fdev\u002Fnull \\\n  || { echo \"Local tag v${VERSION} already exists.\" >&2; exit 1; }\nset +e\ngit ls-remote --exit-code --tags \"$EXPECTED_REMOTE_URL\" \"refs\u002Ftags\u002Fv${VERSION}\" >\u002Fdev\u002Fnull\nREMOTE_TAG_STATUS=$?\nset -e\ncase \"$REMOTE_TAG_STATUS\" in\n  0) echo \"Remote tag v${VERSION} already exists.\" >&2; exit 1 ;;\n  2) ;;\n  *) echo \"Could not verify remote tag v${VERSION}.\" >&2; exit \"$REMOTE_TAG_STATUS\" ;;\nesac\n.\u002Fgradlew verifyReleaseVersion --no-daemon -PreleaseModVersion=\"$VERSION\"\ngit tag --annotate \"v${VERSION}\" --message \"Release v${VERSION}\"\ngit push \"$REMOTE\" \"HEAD:refs\u002Fheads\u002F${BRANCH}\"\ngit push \"$REMOTE\" \"refs\u002Ftags\u002Fv${VERSION}\"\n```\n\nUpdate and verify version\u002Fchangelog files before this script, then tag that release\ncommit. Set `RELEASE_BRANCH`, `RELEASE_REMOTE`, and `RELEASE_REMOTE_URL` for the\nintended release branch and exact push URL. Do not force-push or retag a published\nrelease without explicit authorization.\n\n## Workflow Snippet Validator\n\nRun the bundled validator from an installed `minecraft-ci-release` skill directory:\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\nIt validates workflow-shaped YAML, unresolved placeholders, workflow secret\ndocumentation, and remote `uses:` references pinned to full commit SHAs. Local\nactions (`.\u002F...`) and Docker actions (`docker:\u002F\u002F...`) are intentionally excluded from\nthe SHA requirement. It reads only this skill's `SKILL.md`: it does not validate a\nproject's `.github\u002Fworkflows` files or Gradle tasks. Before a real release, inspect\nthe project's generated artifacts, run `verifyReleaseVersion`, and review the exact\nworkflow diff and configured release destination.\n\n---\n\n## References\n\n- [GitHub Actions secure use](https:\u002F\u002Fdocs.github.com\u002Fen\u002Factions\u002Freference\u002Fsecurity\u002Fsecure-use)\n- [GitHub branch protection](https:\u002F\u002Fdocs.github.com\u002Fen\u002Frepositories\u002Fconfiguring-branches-and-merges-in-your-repository\u002Fmanaging-protected-branches\u002Fabout-protected-branches)\n- [Minotaur](https:\u002F\u002Fgithub.com\u002Fmodrinth\u002Fminotaur)\n- [CurseForgeGradle](https:\u002F\u002Fgithub.com\u002FDarkhax\u002FCurseForgeGradle)\n","# Minecraft CI \u002F Release Skill\n\n## Routing Boundaries\n- `Use when`: the task is CI\u002FCD pipelines, artifact publishing, versioning, or release management.\n- `Do not use when`: the task is gameplay or plugin implementation (`minecraft-modding`, `minecraft-plugin-dev`, or `minecraft-datapack`).\n- `Do not use when`: the task is server runtime operations or infrastructure tuning (`minecraft-server-admin`).\n\n---\n\n## Release setup\n\nKeep each repository's existing release destinations and approval policy. A tag can\nbuild an artifact and create a GitHub Release without publishing to Modrinth or\nCurseForge. Add a publisher only when the project already uses it or the user asks\nfor it. Never add tokens to committed files.\n\nFor Minecraft 26.x, use Java 25 and state that in workflow labels\nand examples. Legacy Minecraft 1.21.x projects stay on Java 21; retain their own\nloader and Gradle conventions instead of mechanically changing their version.\n\nUse an immutable GitHub Action revision in a protected workflow. The following refs\nwere verified from the upstream tags on 2026-10-29; refresh them from the upstream\ntag before intentionally upgrading an action:\n\n```text\nactions\u002Fcheckout@v7.0.1             3d3c42e5aac5ba805825da76410c181273ba90b1\nactions\u002Fsetup-java@v6.0.0           dd06d9cba3e5552c54d9f8ea23572deb30010f7c\ngradle\u002Factions\u002Fsetup-gradle@v6.3.0  9c971963bec38e04b3d30dcc455b5382be2fdbfb\nactions\u002Fupload-artifact@v7.0.1      043fb46d1a93c77aae656e7c1c64a875d1fc6a0a\nsoftprops\u002Faction-gh-release@v3.0.3  efb35369e0ad2afab669f228072c1b0d510eae64\n```\n\n## Version and Tag Convention\n\nWhen the project uses a Minecraft-version suffix, follow `{mod_version}+{mc_version}`:\n\n```\n1.0.0+26.3  ← mod 1.0.0 for MC 26.3\n1.2.3+26.3\n2.0.0+26.3\n```\n\nUse a release version without the game suffix for the Git tag, and retain the\nMinecraft version in the artifact version when the project uses that convention:\n\n```text\nmod_version: 1.2.3\nproject\u002Fartifact version: 1.2.3+26.3\ntag: v1.2.3\n```\n\nThe release workflow must verify that `v1.2.3` matches `mod_version=1.2.3` before\nbuilding. Do not override `mod_version` from the tag, because that hides a mismatch.\nThe Gradle task and safe changelog extraction are in\n[the publishing reference](references\u002Fpublishing-gradle.md).\n\n---\n\n## Core CI Workflow (NeoForge + Fabric)\n\nThis is a Minecraft 26.x \u002F Java 25 example. Its displayed check names are\n`Build \u002F Build (fabric)`, `Build \u002F Build (neoforge)`, and `Build \u002F Test` after\nthe test job below is added. After the first successful pull request, copy the\nexact names GitHub displays into branch protection; workflow or job renames\nchange the required-check context.\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@3d3c42e5aac5ba805825da76410c181273ba90b1\n\n      - name: Set up Java 25\n        uses: actions\u002Fsetup-java@dd06d9cba3e5552c54d9f8ea23572deb30010f7c\n        with:\n          java-version: \"25\"\n          distribution: \"temurin\"\n\n      - name: Setup Gradle\n        uses: gradle\u002Factions\u002Fsetup-gradle@9c971963bec38e04b3d30dcc455b5382be2fdbfb\n        with:\n          cache-read-only: ${{ github.event_name == 'pull_request' }}\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@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a\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  test:\n    name: Test\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout\n        uses: actions\u002Fcheckout@3d3c42e5aac5ba805825da76410c181273ba90b1\n      - name: Set up Java 25\n        uses: actions\u002Fsetup-java@dd06d9cba3e5552c54d9f8ea23572deb30010f7c\n        with:\n          distribution: temurin\n          java-version: \"25\"\n      - name: Set up Gradle\n        uses: gradle\u002Factions\u002Fsetup-gradle@9c971963bec38e04b3d30dcc455b5382be2fdbfb\n      - name: Run tests\n        run: .\u002Fgradlew test --no-daemon\n```\n\n---\n\n## Tagged GitHub Release\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 tagged source\n        uses: actions\u002Fcheckout@3d3c42e5aac5ba805825da76410c181273ba90b1\n\n      - name: Set up Java 25\n        uses: actions\u002Fsetup-java@dd06d9cba3e5552c54d9f8ea23572deb30010f7c\n        with:\n          java-version: \"25\"\n          distribution: \"temurin\"\n\n      - name: Setup Gradle\n        uses: gradle\u002Factions\u002Fsetup-gradle@9c971963bec38e04b3d30dcc455b5382be2fdbfb\n\n      - name: Grant execute permission for gradlew\n        run: chmod +x gradlew\n\n      - name: Validate tag and build\n        env:\n          MOD_VERSION: ${{ github.ref_name }}\n        run: |\n          MOD_VERSION=\"${MOD_VERSION#v}\"\n          .\u002Fgradlew verifyReleaseVersion build --no-daemon \\\n            -PreleaseModVersion=\"$MOD_VERSION\"\n\n      - name: Select release artifacts\n        env:\n          RELEASE_TAG: ${{ github.ref_name }}\n        run: |\n          mkdir -p release-artifacts\n          shopt -s nullglob\n          select_primary() {\n            local loader=\"$1\"; shift\n            local matches=( \"$@\" )\n            if (( ${#matches[@]} != 1 )); then\n              printf 'Expected one %s primary JAR, found %s: %s\\n' \\\n                \"$loader\" \"${#matches[@]}\" \"${matches[*]:-none}\" >&2\n              exit 1\n            fi\n            cp \"${matches[0]}\" \"release-artifacts\u002F${loader}-${RELEASE_TAG}.jar\"\n          }\n          select_primary fabric fabric\u002Fbuild\u002Flibs\u002F*-fabric.jar\n          select_primary neoforge neoforge\u002Fbuild\u002Flibs\u002F*-neoforge.jar\n\n      - name: Create GitHub Release\n        uses: softprops\u002Faction-gh-release@efb35369e0ad2afab669f228072c1b0d510eae64\n        with:\n          files: |\n            release-artifacts\u002Ffabric-${{ github.ref_name }}.jar\n            release-artifacts\u002Fneoforge-${{ github.ref_name }}.jar\n          fail_on_unmatched_files: true\n          generate_release_notes: true\n          prerelease: ${{ contains(github.ref_name, '-alpha') || contains(github.ref_name, '-beta') || contains(github.ref_name, '-rc') }}\n```\n\nThis workflow creates a GitHub Release only. It expects one primary Fabric JAR and\none primary NeoForge JAR with loader-distinct names. Configure those classifiers in\nthe project build, then change both patterns together if its naming convention differs.\nThe selection step fails for zero or multiple matches and copies to distinct release\nnames, preventing accidental overwrite or a partial release. Add a project-specific\npublisher after version validation only when that destination is in scope.\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@3d3c42e5aac5ba805825da76410c181273ba90b1\n      - uses: actions\u002Fsetup-java@dd06d9cba3e5552c54d9f8ea23572deb30010f7c\n        with:\n          java-version: \"25\"\n          distribution: \"temurin\"\n      - uses: gradle\u002Factions\u002Fsetup-gradle@9c971963bec38e04b3d30dcc455b5382be2fdbfb\n      - run: chmod +x gradlew\n      - run: .\u002Fgradlew build --no-daemon\n      - uses: actions\u002Fupload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a\n        with:\n          name: plugin-${{ github.sha }}\n          path: build\u002Flibs\u002F*.jar\n          if-no-files-found: error\n\n  test:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions\u002Fcheckout@3d3c42e5aac5ba805825da76410c181273ba90b1\n      - uses: actions\u002Fsetup-java@dd06d9cba3e5552c54d9f8ea23572deb30010f7c\n        with:\n          java-version: \"25\"\n          distribution: \"temurin\"\n      - uses: gradle\u002Factions\u002Fsetup-gradle@9c971963bec38e04b3d30dcc455b5382be2fdbfb\n      - run: .\u002Fgradlew test --no-daemon\n```\n\n---\n\n## Publishing and Changelog Details\n\nRead [the publishing reference](references\u002Fpublishing-gradle.md) only when the\nproject publishes to Modrinth or CurseForge. It includes current plugin versions,\n26.x `jar` selection, explicit legacy Loom `remapJar` guidance, version verification,\nand a parser that fails when the expected changelog heading is missing.\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=26.3\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 | Follow the project's version policy, update the game suffix when used, and create a new release tag |\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] — 2026-10-01\n### Added\n- New `\u002Fkit` command\n- PDC-based kill tracker\n\n### Fixed\n- Death message not appearing on Paper 26.3\n\n## [1.0.0] — 2026-09-01\n### Added\n- Initial release\n```\n\nThe publishing reference extracts this section by `mod_version` and fails clearly\nwhen the expected heading is missing.\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@9c971963bec38e04b3d30dcc455b5382be2fdbfb\n  with:\n    # Read-only cache on PRs, read-write on main\n    cache-read-only: ${{ github.event_name == 'pull_request' }}\n```\n\n---\n\n## Branch Protection + Required Checks\n\nRecommended GitHub branch protection for `main`:\n- Require the observed checks: `Build \u002F Build (fabric)`, `Build \u002F Build (neoforge)`, and `Build \u002F 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 \u003Cmod-version>\nset -euo pipefail\n\nVERSION=\"${1:?Usage: release.sh \u003Cmod-version>}\"\nREMOTE=\"${RELEASE_REMOTE:-origin}\"\nBRANCH=\"${RELEASE_BRANCH:-main}\"\nEXPECTED_REMOTE_URL=\"${RELEASE_REMOTE_URL:?Set RELEASE_REMOTE_URL to the expected push URL}\"\ngit diff --check\n[[ -z \"$(git status --porcelain=v1 --untracked-files=all)\" ]] \\\n  || { echo \"Working tree contains staged, unstaged, or untracked files.\" >&2; exit 1; }\n[[ \"$(git branch --show-current)\" == \"$BRANCH\" ]] \\\n  || { echo \"Release must start from branch $BRANCH.\" >&2; exit 1; }\nmapfile -t PUSH_URLS \u003C \u003C(git remote get-url --push --all \"$REMOTE\")\n[[ ${#PUSH_URLS[@]} -eq 1 && \"${PUSH_URLS[0]}\" == \"$EXPECTED_REMOTE_URL\" ]] \\\n  || { echo \"Remote $REMOTE must have one expected push URL.\" >&2; exit 1; }\n! git rev-parse --verify --quiet \"refs\u002Ftags\u002Fv${VERSION}\" >\u002Fdev\u002Fnull \\\n  || { echo \"Local tag v${VERSION} already exists.\" >&2; exit 1; }\nset +e\ngit ls-remote --exit-code --tags \"$EXPECTED_REMOTE_URL\" \"refs\u002Ftags\u002Fv${VERSION}\" >\u002Fdev\u002Fnull\nREMOTE_TAG_STATUS=$?\nset -e\ncase \"$REMOTE_TAG_STATUS\" in\n  0) echo \"Remote tag v${VERSION} already exists.\" >&2; exit 1 ;;\n  2) ;;\n  *) echo \"Could not verify remote tag v${VERSION}.\" >&2; exit \"$REMOTE_TAG_STATUS\" ;;\nesac\n.\u002Fgradlew verifyReleaseVersion --no-daemon -PreleaseModVersion=\"$VERSION\"\ngit tag --annotate \"v${VERSION}\" --message \"Release v${VERSION}\"\ngit push \"$REMOTE\" \"HEAD:refs\u002Fheads\u002F${BRANCH}\"\ngit push \"$REMOTE\" \"refs\u002Ftags\u002Fv${VERSION}\"\n```\n\nUpdate and verify version\u002Fchangelog files before this script, then tag that release\ncommit. Set `RELEASE_BRANCH`, `RELEASE_REMOTE`, and `RELEASE_REMOTE_URL` for the\nintended release branch and exact push URL. Do not force-push or retag a published\nrelease without explicit authorization.\n\n## Workflow Snippet Validator\n\nRun the bundled validator from an installed `minecraft-ci-release` skill directory:\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\nIt validates workflow-shaped YAML, unresolved placeholders, workflow secret\ndocumentation, and remote `uses:` references pinned to full commit SHAs. Local\nactions (`.\u002F...`) and Docker actions (`docker:\u002F\u002F...`) are intentionally excluded from\nthe SHA requirement. It reads only this skill's `SKILL.md`: it does not validate a\nproject's `.github\u002Fworkflows` files or Gradle tasks. Before a real release, inspect\nthe project's generated artifacts, run `verifyReleaseVersion`, and review the exact\nworkflow diff and configured release destination.\n\n---\n\n## References\n\n- [GitHub Actions secure use](https:\u002F\u002Fdocs.github.com\u002Fen\u002Factions\u002Freference\u002Fsecurity\u002Fsecure-use)\n- [GitHub branch protection](https:\u002F\u002Fdocs.github.com\u002Fen\u002Frepositories\u002Fconfiguring-branches-and-merges-in-your-repository\u002Fmanaging-protected-branches\u002Fabout-protected-branches)\n- [Minotaur](https:\u002F\u002Fgithub.com\u002Fmodrinth\u002Fminotaur)\n- [CurseForgeGradle](https:\u002F\u002Fgithub.com\u002FDarkhax\u002FCurseForgeGradle)\n",{"name":5,"description":7},"main","22d61ce6b7a0c5f215008824aa6b94ecc73f2a43",".agents\u002Fskills\u002Fminecraft-ci-release",11,"https:\u002F\u002Fgithub.com\u002FJahrome907\u002Fminecraft-agent-skills","https:\u002F\u002Fgithub.com\u002FJahrome907","joe-o.com","Product engineer building field tools, workflow automation, and polished web applications.","2026-10-30 08:19:45",{"source":8,"skillName":5,"commands":62,"prompt":72,"zipAvailable":73},[63,66,69],{"tool":64,"command":65},"npx","npx skills add Jahrome907\u002Fminecraft-agent-skills --skill minecraft-ci-release",{"tool":67,"command":68},"bunx","bunx skills add Jahrome907\u002Fminecraft-agent-skills --skill minecraft-ci-release",{"tool":70,"command":71},"pnpm","pnpm dlx skills add Jahrome907\u002Fminecraft-agent-skills --skill minecraft-ci-release","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FJahrome907\u002Fminecraft-agent-skills\u002Fblob\u002Fmain\u002F.agents\u002Fskills\u002Fminecraft-ci-release\u002FSKILL.md",true,[75,81,85],{"path":76,"resourceType":77,"resourceTypeDesc":78,"sizeBytes":79,"sourceHtmlUrl":80},"references\u002Fgeo_reference.md","REFERENCE","参考文档",21102,"https:\u002F\u002Fgithub.com\u002Ffadrienne\u002FMyGitHub\u002Fblob\u002Fmain\u002Fopenscience\u002Fbackend\u002Fcli\u002Fskills\u002Fdatabases\u002Fgeo-database\u002Freferences\u002Fgeo_reference.md",{"path":82,"resourceType":77,"resourceTypeDesc":78,"sizeBytes":83,"sourceHtmlUrl":84},"references\u002Fpublishing-gradle.md",5501,"https:\u002F\u002Fgithub.com\u002FJahrome907\u002Fminecraft-agent-skills\u002Fblob\u002Fmain\u002F.agents\u002Fskills\u002Fminecraft-ci-release\u002Freferences\u002Fpublishing-gradle.md",{"path":86,"resourceType":87,"resourceTypeDesc":88,"sizeBytes":89,"sourceHtmlUrl":90},"scripts\u002Fvalidate-workflow-snippets.sh","SCRIPT","脚本",6723,"https:\u002F\u002Fgithub.com\u002FJahrome907\u002Fminecraft-agent-skills\u002Fblob\u002Fmain\u002F.agents\u002Fskills\u002Fminecraft-ci-release\u002Fscripts\u002Fvalidate-workflow-snippets.sh",[92,104,109,117,125,132],{"skillNo":93,"name":5,"nameZh":6,"description":94,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":95,"categories":96,"keywords":97,"publishedAt":47},"01M6D2TV8CBAMB70CEC19VMVX5","Fixture with valid workflow YAML and a warning-only glob pattern.","https:\u002F\u002Fgithub.com\u002FJahrome907\u002Fminecraft-agent-skills\u002Fblob\u002Fmain\u002Ftests\u002Ffixtures\u002Fvalidators\u002Fci-release\u002Fwarn-only\u002FSKILL.md",[],[28,27,29,30,98,99,100,101,102,103],"fixture","pattern","only","yaml","workflow","valid",{"skillNo":105,"name":103,"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":106,"categories":107,"keywords":108,"publishedAt":47},"01M6D2TR1N9TNJPTRB66WDCY8X","https:\u002F\u002Fgithub.com\u002FJahrome907\u002Fminecraft-agent-skills\u002Fblob\u002Fmain\u002Ftests\u002Ffixtures\u002Fvalidators\u002Fci-release\u002Fvalid\u002FSKILL.md",[],[103],{"skillNo":110,"name":5,"nameZh":6,"description":111,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":112,"categories":113,"keywords":115,"publishedAt":47},"01M6D2TNBM97CCTYFCDKCFQ4AR","Fixture for a secretless workflow that passes strict validation.","https:\u002F\u002Fgithub.com\u002FJahrome907\u002Fminecraft-agent-skills\u002Fblob\u002Fmain\u002Ftests\u002Ffixtures\u002Fvalidators\u002Fci-release\u002Fsecretless-strict\u002FSKILL.md",[114],{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},[28,27,29,30,98,116,102],"validation",{"skillNo":118,"name":119,"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":120,"categories":121,"keywords":123,"publishedAt":47},"01M6D2TJ9FX4FH1TMGKQPYNZQX","non-workflow-yaml","https:\u002F\u002Fgithub.com\u002FJahrome907\u002Fminecraft-agent-skills\u002Fblob\u002Fmain\u002Ftests\u002Ffixtures\u002Fvalidators\u002Fci-release\u002Fnon-workflow-yaml\u002FSKILL.md",[122],{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},[124,101,102],"non workflow yaml",{"skillNo":126,"name":5,"nameZh":6,"description":127,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":128,"categories":129,"keywords":130,"publishedAt":47},"01M6D2TFE807BSXTEREYPWFY3G","Fixture with a mutable remote action reference.","https:\u002F\u002Fgithub.com\u002FJahrome907\u002Fminecraft-agent-skills\u002Fblob\u002Fmain\u002Ftests\u002Ffixtures\u002Fvalidators\u002Fci-release\u002Fmutable-action\u002FSKILL.md",[],[28,27,29,30,131,98],"reference",{"skillNo":133,"name":5,"nameZh":6,"description":134,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":135,"categories":136,"keywords":137,"publishedAt":47},"01M6D2TBYJ0SM3B79908DH9ECE","Fixture with valid multiline flow collections in workflow YAML.","https:\u002F\u002Fgithub.com\u002FJahrome907\u002Fminecraft-agent-skills\u002Fblob\u002Fmain\u002Ftests\u002Ffixtures\u002Fvalidators\u002Fci-release\u002Fmultiline-flow\u002FSKILL.md",[],[28,30,27,29,102,101,138,98,139,103],"flow","collections"]