Reusable GitHub Actions workflow for Minecraft mod releases. Handles versioning, building, publishing, and downstream modpack PRs.
- Semantic versioning via commit messages
- Gradle build with caching
- GitHub Release creation with artifacts
- Publish to Modrinth and CurseForge via mc-publish
- Auto-update mod descriptions on platforms
- Downstream modpack PR via packwiz
Copy caller-template.yaml to your mod repo as .github/workflows/release.yaml:
mkdir -p .github/workflows
curl -o .github/workflows/release.yaml https://raw.githubusercontent.com/game-design-driven/mod-release-workflow/main/caller-template.yamlThis workflow requires a single mods.toml with a strict [mc-publish] table:
[mc-publish]
modrinth = "AANobbMI"
curseforge = 394468
loader = "forge"
mc_version = "1.20.1"
modrinth_slug = "your-mod-slug"
curseforge_slug = "your-mod-slug"loader must be forge.
Template placeholders like ${...} are not allowed in [mc-publish] values.
Dependencies are read directly from mods.toml by mc-publish. No dependencies.txt is used.
Only Forge is supported; mods.toml is required and is the single source of metadata.
From your mod repo directory:
uv run /path/to/mod-release-workflow/setup.pyIt requires uv, gh, and fzf installed.
The script will configure:
mods.toml[mc-publish] metadata- Modpack sync settings
- API tokens
The workflow triggers on push to main branch.
| Input | Required | Default | Description |
|---|---|---|---|
java_version |
No | 17 |
Java version for build |
target_modpack_repo |
No | - | Downstream modpack repo (org/repo) |
enable_modrinth_sync |
No | false |
Enable Modrinth modpack sync |
enable_curseforge_sync |
No | false |
Enable CurseForge modpack sync |
curseforge_modpack_path |
No | ./curseforge |
Path to CF pack.toml in modpack |
enable_github_release |
No | true |
Enable GitHub Release creation |
manual_bump |
No | patch |
Version bump type override |
Required metadata (Modrinth ID, CurseForge ID, loader, MC version, slugs) must be defined in mods.toml under [mc-publish]. Both platforms are required; the workflow fails if either is missing.
| Secret | Required | Description |
|---|---|---|
GH_TOKEN |
Yes | GitHub PAT with repo access |
MODRINTH_TOKEN |
Yes | Modrinth API token |
CURSEFORGE_TOKEN |
Yes | CurseForge API token |
Set these via GitHub UI or the setup script:
| Variable | Description |
|---|---|
TARGET_MODPACK_REPO |
Downstream modpack repo (org/repo format) |
ENABLE_MODRINTH_SYNC |
true/false |
ENABLE_CURSEFORGE_SYNC |
true/false |
The workflow uses conventional commits for automatic versioning:
| Prefix | Bump | Example |
|---|---|---|
feat: |
minor | feat: add new crafting recipe |
overhaul: |
minor | overhaul: redesign UI |
fix: |
patch | fix: correct item texture |
refactor: |
patch | refactor: clean up event handlers |
chore: |
patch | chore: update dependencies |
docs: |
patch | docs: update readme |
- tests - Validates JSON/YAML files
- tag_and_release - Bumps version, creates git tag
- build - Builds with Gradle, uploads artifacts
- github_release - Creates GitHub Release with jars
- publish - Publishes to Modrinth/CurseForge
- update_descriptions - Syncs README.md to platform descriptions
- make_pr_for_modpack - Creates PR to update downstream modpack
The workflow creates a git tag, then builds. Use the palantir git-version plugin to automatically derive the version from the tag:
Groovy DSL (build.gradle):
plugins {
id 'com.palantir.git-version' version '3.1.0'
}
version = gitVersion()Kotlin DSL (build.gradle.kts):
plugins {
id("com.palantir.git-version") version "3.1.0"
}
val gitVersion: groovy.lang.Closure<String> by extra
version = gitVersion()No manual version management needed - the plugin reads directly from git tags.