Set up CI/CD 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/actions/setup-gradle, pull request checks, and release tag workflows. Also covers Paper plugin CI with shadow JAR builds. Use when the task is CI/CD pipelines, release automation, artifact publishing, versioning, or release governance for Minecraft mods or plugins.
npx skills add https://github.com/Jahrome907/minecraft-agent-skills --skill minecraft-ci-release
PR opened → build + test checks
main branch push → build artifacts
Tag push (v*) → build + publish to Modrinth + CurseForge + GitHub Releases
Use when: the task is CI/CD pipelines, release automation, artifact publishing, versioning, or release governance.Do not use when: the task is implementing gameplay/plugin/mod features (minecraft-modding, minecraft-plugin-dev, minecraft-datapack).Do not use when: the task is server runtime operations and infrastructure tuning (minecraft-server-admin).Minecraft mod versions follow: {mod_version}+{mc_version}
1.0.0+1.21.11 ← mod 1.0.0 for MC 1.21.11
1.2.3+1.21.11
2.0.0+1.21.11
Git tag format: v1.0.0 (mod version only, not MC version in the tag).
.github/workflows/build.ymlname: Build
on:
push:
branches: ["main", "develop"]
pull_request:
branches: ["main"]
permissions:
contents: read
jobs:
build:
name: Build (${{ matrix.platform }})
runs-on: ubuntu-latest
strategy:
matrix:
platform: [neoforge, fabric]
fail-fast: false
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Java 21
uses: actions/setup-java@v4
with:
java-version: "21"
distribution: "temurin"
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4
with:
cache-read-only: ${{ github.ref != 'refs/heads/main' }}
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Build (${{ matrix.platform }})
run: ./gradlew :${{ matrix.platform }}:build --no-daemon
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: mod-${{ matrix.platform }}-${{ github.sha }}
path: ${{ matrix.platform }}/build/libs/*.jar
if-no-files-found: error
.github/workflows/release.ymlname: Release
on:
push:
tags:
- "v*"
permissions:
contents: write # for creating GitHub releases
jobs:
release:
name: Release
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Java 21
uses: actions/setup-java@v4
with:
java-version: "21"
distribution: "temurin"
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Extract version from tag
id: version
run: echo "MOD_VERSION=${GITHUB_REF_NAME#v}" >> $GITHUB_OUTPUT
- name: Build all platforms
run: ./gradlew build --no-daemon
- name: Publish to Modrinth & CurseForge
run: ./gradlew publishMods --no-daemon
env:
MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }}
CURSEFORGE_TOKEN: ${{ secrets.CURSEFORGE_TOKEN }}
- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
files: |
fabric/build/libs/*.jar
neoforge/build/libs/*.jar
generate_release_notes: true
draft: false
prerelease: ${{ contains(github.ref_name, '-alpha') || contains(github.ref_name, '-beta') || contains(github.ref_name, '-rc') }}
.github/workflows/build.yml (plugin)name: Build
on:
push:
branches: ["main"]
pull_request:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
java-version: "21"
distribution: "temurin"
- uses: gradle/actions/setup-gradle@v4
- run: chmod +x gradlew
- run: ./gradlew shadowJar --no-daemon
- uses: actions/upload-artifact@v4
with:
name: plugin-${{ github.sha }}
path: build/libs/*.jar
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
java-version: "21"
distribution: "temurin"
- uses: gradle/actions/setup-gradle@v4
- run: ./gradlew test --no-daemon
build.gradle.kts (root or platform-specific)plugins {
id("com.modrinth.minotaur") version "2.8.7"
}
// === Fabric subproject ===
modrinth {
token.set(System.getenv("MODRINTH_TOKEN") ?: "")
projectId.set("YOUR-PROJECT-ID") // from modrinth.com project slug or ID
versionNumber.set("${project.version}")
versionType.set("release") // release | beta | alpha
uploadFile.set(tasks.remapJar) // the JAR to upload
gameVersions.addAll("1.21.11")
loaders.addAll("fabric")
changelog.set(
rootProject.file("CHANGELOG.md").readText()
.substringAfter("## [${project.version}]")
.substringBefore("\n## [")
.trim()
)
dependencies {
required.project("fabric-api")
// optional.project("some-optional-mod")
}
}
// root build.gradle.kts
tasks.register("publishMods") {
dependsOn(":fabric:modrinth", ":neoforge:modrinth")
dependsOn(":fabric:curseforge", ":neoforge:curseforge")
group = "publishing"
description = "Publish all platforms to Modrinth and CurseForge"
}
build.gradle.ktsplugins {
id("net.darkhax.curseforgegradle") version "1.1.25"
}
tasks.register<net.darkhax.curseforgegradle.TaskPublishCurseForge>("curseforge") {
apiToken = System.getenv("CURSEFORGE_TOKEN") ?: ""
val cf = upload(PROJECT_ID, tasks.named("remapJar")) // or shadowJar
cf.changelogType = "markdown"
cf.changelog = rootProject.file("CHANGELOG.md").readText()
.substringAfter("## [${project.version}]")
.substringBefore("\n## [")
.trim()
cf.releaseType = "release"
cf.addGameVersion("1.21.11")
cf.addModLoader("Fabric") // "NeoForge" for NeoForge subproject
cf.addRequirement("fabric-api")
// cf.addJavaVersion("Java 21")
// Replace PROJECT_ID with your numeric CurseForge project ID
}
> Replace PROJECT_ID with your actual numeric CurseForge project ID (found in project settings).
gradle.properties Secrets PatternNever hardcode tokens. Read them from environment:
# gradle.properties (committed)
mod_id=mymod
mod_version=1.0.0
minecraft_version=1.21.11
modrinth_project_id=AABBCCDD
curseforge_project_id=123456
# DO NOT commit tokens
# Set these as GitHub repo secrets:
# MODRINTH_TOKEN, CURSEFORGE_TOKEN
| Change | Version bump |
|--------|-------------|
| New features, no breaking changes | Minor: 1.1.0 |
| Bug fixes only | Patch: 1.0.1 |
| API/config breaking changes | Major: 2.0.0 |
| Minecraft version update | Keep mod version, change +1.21.11 suffix |
| Pre-release | 1.0.0-beta.1, 1.0.0-rc.1 |
# Changelog
## [1.1.0] — 2025-06-01
### Added
- New `/kit` command
- PDC-based kill tracker
### Fixed
- Death message not appearing on Paper 1.21.11
## [1.0.0] — 2025-05-01
### Added
- Initial release
Automate CHANGELOG parsing in Gradle (as shown above in modrinth block) by extracting
the section between version headers.
.github/dependabot.ymlversion: 2
updates:
- package-ecosystem: "gradle"
directory: "/"
schedule:
interval: "weekly"
groups:
gradle-plugins:
patterns:
- "com.gradleup.shadow"
- "dev.architectury.loom"
- "com.modrinth.minotaur"
- "net.darkhax.curseforgegradle"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
# In all workflow jobs:
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4
with:
# Read-only cache on PRs, read-write on main
cache-read-only: ${{ github.event_name == 'pull_request' }}
# Cache Minecraft assets (speeds up loom tasks by minutes)
gradle-home-cache-includes: |
caches
notifications
.gradle/loom-cache
Recommended GitHub branch protection for main:
build (fabric), build (neoforge), test#!/usr/bin/env bash
# scripts/release.sh <version>
# Usage: ./scripts/release.sh 1.1.0
set -euo pipefail
VERSION="${1:?Usage: release.sh <version>}"
# Update gradle.properties
sed -i "s/^mod_version=.*/mod_version=${VERSION}/" gradle.properties
# Stage and commit
git add gradle.properties
git commit -m "chore: release v${VERSION}"
# Tag
git tag "v${VERSION}"
echo "Created commit and tag v${VERSION}"
echo "Push with: git push && git push --tags"
Use the bundled validator script to keep SKILL.md workflow snippets copy-paste safe:
# Run from the installed skill directory:
./scripts/validate-workflow-snippets.sh --root .
# Strict mode treats warnings as failures:
./scripts/validate-workflow-snippets.sh --root . --strict
The validator is bundled and self-contained. Run it from a copied .agents/,
.codex/, or .claude/ minecraft-ci-release skill directory without relying
on repo-root node_modules.
What it checks:
name, on, jobs)${{ secrets.* }} usage stays consistent with secrets documented in this fileThis skill should be used as a mandatory final sanity check before git commit, PR creation, or declaring work done. Triggers on "commit", "push", "PR", "pull request", "done", "finished", "complete", "ship", "deploy", "ready to merge". Catches security vulnerabilities, logic errors, and business rule bugs that slip through despite passing tests.
Audits code against CI/CD style rules, quality guidelines, and best practices, then rewrites code to meet standards without breaking functionality. Use this skill after functionality validation to ensure code is not just correct but also maintainable, readable, and production-ready. The skill applies linting rules, enforces naming conventions, improves code organization, and refactors for clarity while preserving all behavioral correctness verified by functionality audits.
Create a new implementation plan file for new features, refactoring existing code or upgrading packages, design, architecture or infrastructure.
CI/CD reference for Megatron-LM. Covers CI pipeline structure, PR scope labels, triggering internal GitLab CI (which force-pushes the current branch to a pull-request/BRANCH ref — always dry-run and verify the destination first; never run against shared or protected branches), and CI failure investigation.
>- Parses and processes SARIF files from static analysis tools like CodeQL, Semgrep, or other scanners. Triggers on "parse sarif", "read scan results", "aggregate findings", "deduplicate alerts", or "process sarif output". Handles filtering, deduplication, format conversion, and CI/CD integration of SARIF data. Does NOT run scans — use the Semgrep or CodeQL skills for that.
Detects anemic domain models, validates and refactors them into rich domain models, and enforces tactical DDD patterns (Entities, Value Objects, Aggregates, Domain Services, Domain Events). Use when the user asks to validate, review, or check domain models or DDD code; detect anemia; refactor domain objects; improve encapsulation; or mentions terms like "anemic model", "rich domain", "aggregate", "value object", "domain event", "ubiquitous language", "is this good DDD", "does this follow DDD", or "check my domain". Do NOT use for module or service boundary design, architectural decomposition, strategic DDD context mapping, or code outside the domain layer (DTOs, controllers, infrastructure adapters).
End-to-end iOS red-team pipeline — IPA acquisition (App Store extraction, TestFlight, enterprise/ad-hoc sideload), class-dump/Hopper/Ghidra static analysis, Info.plist + entitlements + Keychain secret extraction, App Transport Security (ATS) misconfig + certificate-pinning bypass (frida-ios-dump, objection, SSL Kill Switch 2), URL-scheme / Universal Link hijack, exported-service enumeration, Frida runtime instrumentation. Companion to apk-redteam-pipeline for the iOS side of a mobile app catalogue. Use when target has an iOS app (App Store listing, TestFlight link, enterprise MDM distribution), when an IPA URL is found hosted on a web server, or when post-recon mentions "iOS app" / "mobile app" in scope alongside an Apple developer account.
Validate KQL (Kusto Query Language) files used in Azure Quick Review (azqr) against their recommendation definitions. Use when the user wants to validate KQL syntax, check semantic alignment with recommendations, verify property names against Azure REST API schemas, or audit KQL queries before a pull request. WHEN: "validate kql", "check kql files", "kql syntax error", "validate aks kql", "run kql validator", "validate azure resource graph queries", "check recommendations alignment", "validate kql for <service>".
Take jahrome907/minecraft-ci-release from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.