minecraft-multiloader
Build Minecraft mods targeting both NeoForge and Fabric simultaneously using the Architectury framework for Minecraft 1.21.x. Covers Architectury project structure (common/neoforge/fabric subprojects), ExpectPlatform annotation for platform-specific implementations, shared registry via Architectury's registration API, platform-specific entrypoints, architectury-loom Gradle plugin configuration, gradle.properties for both loaders, multi-jar publishing to Modrinth and CurseForge, and avoiding common pitfalls when sharing code. Use this skill when building a mod that must run on both NeoForge and Fabric with a single shared codebase.
Best use case
minecraft-multiloader is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Build Minecraft mods targeting both NeoForge and Fabric simultaneously using the Architectury framework for Minecraft 1.21.x. Covers Architectury project structure (common/neoforge/fabric subprojects), ExpectPlatform annotation for platform-specific implementations, shared registry via Architectury's registration API, platform-specific entrypoints, architectury-loom Gradle plugin configuration, gradle.properties for both loaders, multi-jar publishing to Modrinth and CurseForge, and avoiding common pitfalls when sharing code. Use this skill when building a mod that must run on both NeoForge and Fabric with a single shared codebase.
Teams using minecraft-multiloader should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/minecraft-multiloader/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How minecraft-multiloader Compares
| Feature / Agent | minecraft-multiloader | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Build Minecraft mods targeting both NeoForge and Fabric simultaneously using the Architectury framework for Minecraft 1.21.x. Covers Architectury project structure (common/neoforge/fabric subprojects), ExpectPlatform annotation for platform-specific implementations, shared registry via Architectury's registration API, platform-specific entrypoints, architectury-loom Gradle plugin configuration, gradle.properties for both loaders, multi-jar publishing to Modrinth and CurseForge, and avoiding common pitfalls when sharing code. Use this skill when building a mod that must run on both NeoForge and Fabric with a single shared codebase.
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# Minecraft Multiloader Skill (Architectury)
## What Is Architectury?
[Architectury](https://github.com/architectury/architectury-api) is a framework that
lets you write one mod codebase that compiles to both **NeoForge** and **Fabric** JARs.
The common subproject has a shared API; platform subprojects implement
platform-specific behavior behind the `@ExpectPlatform` abstraction.
### Routing Boundaries
- `Use when`: one shared codebase must build and ship both NeoForge and Fabric artifacts.
- `Do not use when`: the project is single-loader only (`minecraft-modding` for NeoForge/Fabric, not both).
- `Do not use when`: the task is Paper/Bukkit plugin development (`minecraft-plugin-dev`).
| Component | Purpose |
|-----------|---------|
| `architectury-loom` | Gradle plugin — extends Fabric Loom for multiloader support |
| `architectury-api` | Runtime library — abstractions over both platforms |
| `@ExpectPlatform` | Annotation marking methods with platform-specific implementations |
| `common/` | Shared code (no loader-specific APIs) |
| `fabric/` | Fabric-specific code + entrypoint |
| `neoforge/` | NeoForge-specific code + entrypoint |
---
## Versions (1.21.x)
```properties
# gradle.properties (root)
minecraft_version=1.21.1
enabled_platforms=fabric,neoforge
architectury_version=13.0.8
fabric_loader_version=0.16.9
fabric_api_version=0.114.0+1.21.1
neoforge_version=21.1.172
loom_version=1.9-SNAPSHOT
```
---
## Root Project Layout
```
my-mod/
├── build.gradle ← root build (shared config)
├── settings.gradle
├── gradle.properties
├── common/
│ ├── build.gradle
│ └── src/main/java/com/example/mymod/
│ ├── MyMod.java ← shared init
│ ├── registry/
│ │ └── ModItems.java ← shared registry declarations
│ └── platform/
│ └── PlatformHelper.java ← @ExpectPlatform methods
├── fabric/
│ ├── build.gradle
│ └── src/main/
│ ├── java/com/example/mymod/fabric/
│ │ ├── MyModFabric.java ← Fabric entrypoint
│ │ └── platform/
│ │ └── PlatformHelperImpl.java ← Fabric implementation
│ └── resources/
│ ├── fabric.mod.json
│ └── assets/...
└── neoforge/
├── build.gradle
└── src/main/
├── java/com/example/mymod/neoforge/
│ ├── MyModNeoForge.java ← NeoForge @Mod entry
│ └── platform/
│ └── PlatformHelperImpl.java ← NeoForge implementation
└── resources/
├── META-INF/neoforge.mods.toml
└── assets/...
```
---
## Root `settings.gradle`
```groovy
pluginManagement {
repositories {
maven { url "https://maven.architectury.dev/" }
maven { url "https://maven.fabricmc.net/" }
maven { url "https://maven.neoforged.net/releases" }
gradlePluginPortal()
}
}
include "common"
include "fabric"
include "neoforge"
```
---
## Root `build.gradle`
```groovy
plugins {
id "architectury-plugin" version "3.4-SNAPSHOT" apply false
id "dev.architectury.loom" version "${loom_version}" apply false
id "com.github.johnrengelman.shadow" version "8.1.1" apply false
}
architectury {
minecraft = rootProject.minecraft_version
}
subprojects {
apply plugin: "java"
apply plugin: "architectury-plugin"
group = "com.example.mymod"
version = "${mod_version}+${minecraft_version}"
archivesBaseName = "my-mod-${project.name}"
repositories {
maven { url "https://maven.architectury.dev/" }
maven { url "https://mod-buildtools.pkg.github.com/TerraformersMC/" }
}
java {
withSourcesJar()
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
}
}
```
---
## `common/build.gradle`
```groovy
plugins {
id "dev.architectury.loom" apply true
}
architectury {
common(rootProject.enabled_platforms.split(","))
}
loom {
// common project uses mappings only
}
dependencies {
minecraft "com.mojang:minecraft:${rootProject.minecraft_version}"
mappings loom.officialMojangMappings()
modImplementation "dev.architectury:architectury-api:${rootProject.architectury_version}"
}
```
---
## `fabric/build.gradle`
```groovy
plugins {
id "com.github.johnrengelman.shadow"
id "dev.architectury.loom" apply true
}
architectury {
platformSetupLoomIde()
fabric()
}
loom {
accessWidenerPath = project(":common").loom.accessWidenerPath
}
configurations {
common
shadowCommon
compileClasspath.extendsFrom common
runtimeClasspath.extendsFrom common
developmentFabric.extendsFrom common
}
dependencies {
minecraft "com.mojang:minecraft:${rootProject.minecraft_version}"
mappings loom.officialMojangMappings()
modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}"
modApi "net.fabricmc.fabric-api:fabric-api:${rootProject.fabric_api_version}"
modApi "dev.architectury:architectury-api:${rootProject.architectury_version}:fabric"
common(project(path: ":common", configuration: "namedElements")) { transitive false }
shadowCommon(project(path: ":common", configuration: "transformProductionFabric")) { transitive false }
}
shadowJar {
exclude "architectury.common.json"
configurations = [project.configurations.shadowCommon]
archiveClassifier = "dev-shadow"
}
remapJar {
injectAccessWidener = true
input.fileValue shadowJar.archiveFile.get().asFile
dependsOn shadowJar
archiveClassifier = ""
}
jar { archiveClassifier = "dev" }
sourcesJar { archiveClassifier = "dev-sources" }
components.java.withVariantsFromConfiguration(configurations.shadowRuntimeElements) { skip() }
```
---
## `neoforge/build.gradle`
```groovy
plugins {
id "com.github.johnrengelman.shadow"
id "dev.architectury.loom" apply true
}
architectury {
platformSetupLoomIde()
neoForge()
}
loom {
accessWidenerPath = project(":common").loom.accessWidenerPath
}
configurations {
common
shadowCommon
compileClasspath.extendsFrom common
runtimeClasspath.extendsFrom common
developmentNeoForge.extendsFrom common
}
dependencies {
minecraft "com.mojang:minecraft:${rootProject.minecraft_version}"
mappings loom.officialMojangMappings()
neoForge "net.neoforged:neoforge:${rootProject.neoforge_version}"
modApi "dev.architectury:architectury-api:${rootProject.architectury_version}:neoforge"
common(project(path: ":common", configuration: "namedElements")) { transitive false }
shadowCommon(project(path: ":common", configuration: "transformProductionNeoForge")) { transitive false }
}
shadowJar {
exclude "architectury.common.json"
configurations = [project.configurations.shadowCommon]
archiveClassifier = "dev-shadow"
}
remapJar {
input.fileValue shadowJar.archiveFile.get().asFile
dependsOn shadowJar
archiveClassifier = ""
}
jar { archiveClassifier = "dev" }
```
---
## Shared Common Code
### `common/.../MyMod.java`
```java
package com.example.mymod;
import dev.architectury.registry.registries.DeferredRegister;
import dev.architectury.registry.registries.RegistrySupplier;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.Item;
public class MyMod {
public static final String MOD_ID = "mymod";
// Architectury's DeferredRegister — works on both platforms
public static final DeferredRegister<Item> ITEMS =
DeferredRegister.create(MOD_ID, BuiltInRegistries.ITEM);
public static final RegistrySupplier<Item> MY_ITEM =
ITEMS.register("my_item", () -> new Item(new Item.Properties()));
public static void init() {
ITEMS.register(); // registers with both platforms
}
}
```
### `@ExpectPlatform` — platform-specific methods
Define the contract in `common/`:
```java
package com.example.mymod.platform;
import dev.architectury.injectables.annotations.ExpectPlatform;
import net.minecraft.world.level.material.Fluid;
public class PlatformHelper {
@ExpectPlatform
public static boolean isModLoaded(String modId) {
// This body is replaced at compile time by the platform implementation
throw new AssertionError("ExpectPlatform implementation not found");
}
@ExpectPlatform
public static boolean isClient() {
throw new AssertionError();
}
}
```
Implement in `fabric/.../platform/PlatformHelperImpl.java`:
```java
package com.example.mymod.platform;
import net.fabricmc.loader.api.FabricLoader;
// Class name must match: <common class name>Impl
public class PlatformHelperImpl {
public static boolean isModLoaded(String modId) {
return FabricLoader.getInstance().isModLoaded(modId);
}
public static boolean isClient() {
return FabricLoader.getInstance().getEnvironmentType() ==
net.fabricmc.api.EnvType.CLIENT;
}
}
```
Implement in `neoforge/.../platform/PlatformHelperImpl.java`:
```java
package com.example.mymod.platform;
import net.neoforged.fml.ModList;
import net.neoforged.fml.loading.FMLEnvironment;
public class PlatformHelperImpl {
public static boolean isModLoaded(String modId) {
return ModList.get().isLoaded(modId);
}
public static boolean isClient() {
return FMLEnvironment.dist.isClient();
}
}
```
---
## Fabric Entrypoint
### `fabric/.../MyModFabric.java`
```java
package com.example.mymod.fabric;
import com.example.mymod.MyMod;
import net.fabricmc.api.ModInitializer;
public class MyModFabric implements ModInitializer {
@Override
public void onInitialize() {
MyMod.init();
}
}
```
### `fabric/.../resources/fabric.mod.json`
```json
{
"schemaVersion": 1,
"id": "mymod",
"version": "${version}",
"name": "My Mod",
"description": "A multiloader example mod",
"license": "MIT",
"environment": "*",
"entrypoints": {
"main": ["com.example.mymod.fabric.MyModFabric"]
},
"depends": {
"fabricloader": ">=0.16.0",
"fabric-api": "*",
"architectury": ">=13.0.0",
"minecraft": "~1.21"
}
}
```
---
## NeoForge Entrypoint
### `neoforge/.../MyModNeoForge.java`
```java
package com.example.mymod.neoforge;
import com.example.mymod.MyMod;
import net.neoforged.bus.api.IEventBus;
import net.neoforged.fml.common.Mod;
@Mod(MyMod.MOD_ID)
public class MyModNeoForge {
public MyModNeoForge(IEventBus modEventBus) {
MyMod.init();
}
}
```
### `neoforge/.../resources/META-INF/neoforge.mods.toml`
```toml
modLoader = "javafml"
loaderVersion = "[4,)"
license = "MIT"
[[mods]]
modId = "mymod"
version = "${file.jarVersion}"
displayName = "My Mod"
description = "A multiloader example mod"
[[dependencies.mymod]]
modId = "neoforge"
type = "required"
versionRange = "[21.1,)"
ordering = "NONE"
side = "BOTH"
[[dependencies.mymod]]
modId = "minecraft"
type = "required"
versionRange = "[1.21.1,)"
ordering = "NONE"
side = "BOTH"
```
---
## Build Commands
```bash
# Build both JARs simultaneously
./gradlew build
# Outputs:
# fabric/build/libs/my-mod-fabric-1.0.0+1.21.1.jar
# neoforge/build/libs/my-mod-neoforge-1.0.0+1.21.1.jar
# Run in dev environment
./gradlew :fabric:runClient
./gradlew :neoforge:runClient
./gradlew :neoforge:runServer
# Datagen (if applicable)
./gradlew :neoforge:runData
```
---
## Common Pitfalls
| Pitfall | Solution |
|---------|----------|
| Using `net.neoforged.*` / `net.fabricmc.*` in `common/` | Only use vanilla MC and Architectury APIs in common |
| Direct field access on `DeferredRegister` (NeoForge style) in common | Use Architectury's `DeferredRegister` |
| Forgetting `@ExpectPlatform` throws `AssertionError` at runtime | Both `fabric/` and `neoforge/` must have matching `*Impl` classes |
| Assets duplicated in fabric/ and neoforge/ | Keep assets in `common/src/main/resources/assets/` |
| Mixins in common — not supported on NeoForge | Put Mixins in the platform subprojects only |
| Accessing world/registry on mod init thread | Use `mod bus` events for setup; never access world on init |
---
## References
- Architectury API GitHub: https://github.com/architectury/architectury-api
- Architectury Loom: https://github.com/architectury/architectury-loom
- Architectury templates: https://github.com/architectury/architectury-templates
- Architectury docs: https://docs.architectury.dev/Related Skills
minecraft-bukkit-pro
Master Minecraft server plugin development with Bukkit, Spigot, and Paper APIs. Specializes in event-driven architecture, command systems, world manipulation, player management, and performance optimization. Use PROACTIVELY for plugin architecture, gameplay mechanics, server-side features, or cross-version compatibility.
minecraft-ci-release
Fixture with valid workflow YAML but a warning-only secrets section.
minecraft-world-generation
Create custom world generation content for Minecraft 1.21.x including custom biomes, dimensions, noise settings, surface rules, placed/configured features, carvers, structure sets, and biome modifiers. Covers both the datapack-only approach (JSON worldgen files) and the mod-code approach (NeoForge BiomeModifiers, Fabric BiomeModification API, code-driven worldgen registration with DeferredRegister). Includes the full JSON schema for biome files, noise_settings overrides, placed_feature, configured_feature, structure, structure_set, and processor_list files. Targets Minecraft 1.21.x with official Mojang mappings.
minecraft-testing
Write automated tests for Minecraft mods and plugins for 1.21.x. Covers NeoForge GameTests (@GameTest annotation, GameTestHelper assertions, test structure placement), Fabric game tests (fabric-gametest-api-v1), unit testing non-Minecraft logic with JUnit 5, MockBukkit for Paper/Bukkit plugin testing (mock server, mock player, event dispatching, inventory checking), integration testing with a test server via Gradle, and GitHub Actions CI workflows that run GameTests headlessly. Includes patterns for mocking registries, testing event handlers, testing commands, and test-driven development for Minecraft projects.
minecraft-server-admin
Set up, configure, and optimize a Minecraft Java Edition server for 1.21.x. Covers Paper server installation and startup (Aikar's JVM flags), server.properties reference, paper-global.yml and paper-world-defaults.yml configuration for performance, spigot.yml and bukkit.yml tuning, chunk loading/unloading optimization, player count and TPS monitoring, plugin management best practices, world management (pre-generation with Chunky), backup strategies, Docker/Pterodactyl deployment, Velocity proxy setup for multi-server networks, Geyser for Bedrock crossplay, and performance profiling with Spark. Use for server operations and infrastructure — not for plugin or mod development.
minecraft-resource-pack
Create and edit Minecraft resource packs for 1.21.x including custom block models, item models, blockstate definitions, textures (PNG format requirements), sounds.json, custom fonts, MCMETA animation files, OptiFine CIT (Custom Item Textures), and pack.mcmeta format. Covers the full block/item model JSON schema (parent, textures, elements, display, overrides), multi-layer items, GUI textures, GUI sprites, language files, shader integration (core shaders, Iris), and the pack format numbers for each 1.21.x version. Use to customize how Minecraft looks and sounds without mods.
minecraft-plugin-dev
Develop Minecraft server plugins using the Paper/Bukkit/Spigot API for Minecraft 1.21.x. Handles creating Paper plugins with JavaPlugin, event listeners with @EventHandler, commands, schedulers (sync/async), Persistent Data Container (PDC), Adventure text components, Vault economy integration, BungeeCord/Velocity messaging, plugin.yml configuration, YAML config management, and Paper-specific enhancement APIs. Always targets Paper API 1.21.x (Java 21) with Gradle (Kotlin DSL). Distinguishes plugin development from mod development: plugins run server-side only and do not require client installation.
minecraft-modding
Full-stack Minecraft mod development skill for both NeoForge (1.21+) and Fabric (1.21+). Scaffolds new mods, adds custom blocks, items, entities, recipes, commands, GUIs, dimensions, and data generation. Knows the NeoForge DeferredRegister + event-bus system and the Fabric Registry + ModInitializer system. Use when the user asks to create a Minecraft mod, add a feature to an existing mod, fix a mod bug, generate JSON assets/data, or migrate between modding platforms. Prefer NeoForge unless the user specifies Fabric or Multiloader.
minecraft-datapack
Create, edit, and debug Minecraft vanilla datapacks for 1.21.x. Covers the full datapack format: pack.mcmeta, function files (.mcfunction), advancements, predicates, loot tables, item modifiers, recipe overrides, tags, damage types, dimension types, worldgen overrides, and structure sets. Handles function syntax, execute command chains, macro functions (1.20.2+), storage NBT, scoreboard operations, advancement triggers, pack format numbers, and /reload workflow. No Java or mod loader required — pure vanilla JSON and .mcfunction files.
minecraft-commands-scripting
Write Minecraft vanilla commands, NBT scripts, scoreboards, and complex execute chains for use in command blocks, chat, or .mcfunction files. Covers full execute subcommand reference (as/at/in/positioned/rotated/facing/anchored/if/unless/store/run), selector arguments with all filter options, scoreboard objectives and operations, NBT path syntax for entities/blocks/storage, schedule and forceload commands, tellraw/title JSON text components, bossbar, team management, item modification commands, attribute commands, particle/playsound effects, and RCON scripting. Targets Minecraft 1.21.x Java Edition. Use for command-only work; for full function/advancement/recipe systems use the minecraft-datapack skill instead.
Daily Logs
Record the user's daily activities, progress, decisions, and learnings in a structured, chronological format.
Socratic Method: The Dialectic Engine
This skill transforms Claude into a Socratic agent — a cognitive partner who guides