.agents/skills/minecraft-datapack/SKILL.md
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.
npx skillsauth add jahrome907/minecraft-codex-skills minecraft-datapackInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
A datapack is a folder (or .zip) placed in a world's datapacks/ directory that
extends or overrides vanilla Minecraft behavior using JSON files and .mcfunction
scripts. No Java, no mods. Requires only a running Minecraft server or singleplayer world.
Datapacks can:
Use when: the deliverable is datapack files (pack.mcmeta, data/...) and .mcfunction/JSON content.Do not use when: the request is command-only snippets not tied to a datapack file tree (minecraft-commands-scripting).Do not use when: the request requires loader APIs, Java code, or runtime mod behavior (minecraft-modding).| Minecraft Version | Preferred pack metadata |
|-------------------|---------------------------|
| 1.21 / 1.21.1 | pack_format: 48 |
| 1.21.2 / 1.21.3 | pack_format: 57 |
| 1.21.4 | pack_format: 61 |
| 1.21.5 | pack_format: 71 |
| 1.21.6 | pack_format: 80 |
| 1.21.7 / 1.21.8 | pack_format: 81 |
| 1.21.9 / 1.21.10 | min_format: 88.0, max_format: 88.0 |
| 1.21.11 | min_format: 94.1, max_format: 94.1 |
Use pack_format through 1.21.8. Starting in 1.21.9, Mojang replaced that
single field with explicit min_format / max_format values.
Keep pack.mcmeta exact for the patch you target instead of trying to span the
entire 1.21.x line with one metadata block.
my-datapack/
├── pack.mcmeta
└── data/
└── <namespace>/ ← use your pack's name (e.g., mypack)
├── function/
│ ├── main.mcfunction
│ └── tick.mcfunction
├── advancement/
│ └── custom_advancement.json
├── recipe/
│ └── custom_recipe.json
├── loot_table/
│ └── custom_loot.json
├── predicate/
│ └── is_night.json
├── item_modifier/
│ └── add_name.json
└── tags/
├── block/
│ └── climbable.json
├── entity_type/
│ └── bosses.json
└── function/
├── load.json ← runs on /reload
└── tick.json ← runs every game tick
pack.mcmeta{
"pack": {
"pack_format": 81,
"description": "My Custom Datapack v1.0"
}
}
{
"pack": {
"min_format": 94.1,
"max_format": 94.1,
"description": "My Custom Datapack v1.0"
}
}
data/<namespace>/tags/function/load.json{
"values": [
"<namespace>:setup"
]
}
data/<namespace>/tags/function/tick.json{
"values": [
"<namespace>:tick"
]
}
data/<namespace>/function/setup.mcfunction# Runs once on /reload
scoreboard objectives add deaths deathCount
scoreboard objectives add kills playerKillCount
tellraw @a {"text":"[MyPack] Loaded!","color":"green"}
data/<namespace>/function/tick.mcfunction# Runs every tick — KEEP THIS SHORT
# Only put fast, targeted operations here
execute as @a[scores={deaths=1..}] run function mypack:on_death_check
# as: change execution entity
execute as @a run say Hi from each player
# at: change execution position to entity's location
execute as @a at @s run particle flame ~ ~ ~ 0 0 0 0 1
# positioned: change position without changing executor
execute positioned 0 64 0 run setblock ~ ~ ~ stone
# if/unless conditions
execute if block ~ ~-1 ~ minecraft:grass_block run say Standing on grass
execute unless entity @a[tag=vip] run say No VIPs online
# store result into score
execute store result score @s mypack.health run data get entity @s Health
# Chained
execute as @a[gamemode=!spectator] at @s if block ~ ~-1 ~ #minecraft:logs run give @s minecraft:apple
# in: change dimension
execute in minecraft:the_nether run say This runs in the Nether
# Create objectives
scoreboard objectives add kills playerKillCount
scoreboard objectives add points dummy
scoreboard objectives setdisplay sidebar points
# Modify scores
scoreboard players set @s points 0
scoreboard players add @s points 10
scoreboard players remove @s points 5
scoreboard players operation @s points += @s kills
# Test scores
execute if score @s points matches 100.. run say Reached 100 points!
execute if score @s points matches ..0 run say Score is zero or negative
execute if score PlayerA points < PlayerB points run say A has fewer points than B
# Read entity NBT
data get entity @s Health
data get entity @s Inventory[0]
# Modify entity NBT
data modify entity @s Health set value 20.0f
data modify entity @s CustomName set value '{"text":"Boss","color":"red"}'
# Storage (global key-value store)
data modify storage mypack:data config.difficulty set value "hard"
data get storage mypack:data config.difficulty
# Copy from entity to storage
data modify storage mypack:log last_player_pos set from entity @s Pos
@a # all players
@p # nearest player
@r # random player
@e # all entities
@s # executing entity
@n # nearest entity (1.21+)
# Selector arguments
@a[gamemode=survival]
@a[gamemode=!spectator]
@e[type=minecraft:zombie,distance=..10]
@e[type=minecraft:player,tag=vip]
@a[scores={kills=1..10}]
@a[nbt={playerGameType:0}]
@e[sort=nearest,limit=1,type=!minecraft:player]
@a[x=0,y=64,z=0,dx=10,dy=10,dz=10] # AABB selection
@a[team=red]
@a[level=30..]
@a[name=Steve]
Macro functions let you pass dynamic arguments to a function.
data/mypack/function/greet.mcfunction)# Macro argument: $(name)
$tellraw @a {"text":"Welcome $(name)!","color":"gold"}
$scoreboard players set $(name) points 0
run function + with# Pass values from storage
data modify storage mypack:tmp input set value {name:"Steve"}
function mypack:greet with storage mypack:tmp input
# Pass values from entity NBT
function mypack:greet with entity @p {}
# Pass value from block NBT
function mypack:greet with block 0 64 0 {}
data/<namespace>/advancement/my_advancement.json{
"display": {
"icon": {
"id": "minecraft:diamond"
},
"title": {"text": "Diamond Hunter"},
"description": {"text": "Mine your first diamond"},
"frame": "task",
"show_toast": true,
"announce_to_chat": true,
"hidden": false
},
"criteria": {
"mined_diamond": {
"trigger": "minecraft:item_picked_up",
"conditions": {
"item": {
"items": ["minecraft:diamond"]
}
}
}
},
"rewards": {
"function": "mypack:on_diamond_obtained",
"experience": 10
}
}
| Trigger | When it fires |
|---------|--------------|
| minecraft:impossible | Never (use for manual grants) |
| minecraft:tick | Every tick while player is online |
| minecraft:player_killed_entity | Player kills an entity |
| minecraft:entity_killed_player | Entity kills a player |
| minecraft:item_picked_up | Player picks up an item |
| minecraft:placed_block | Player places a block |
| minecraft:inventory_changed | Player inventory changes |
| minecraft:changed_dimension | Player changes dimension |
| minecraft:consume_item | Player consumes an item |
| minecraft:location | Player at a specific location |
| minecraft:recipe_unlocked | Player unlocks a recipe |
data/<namespace>/recipe/shaped.json){
"type": "minecraft:crafting_shaped",
"pattern": [
"DDD",
"D D",
"DDD"
],
"key": {
"D": { "item": "minecraft:diamond" }
},
"result": {
"id": "minecraft:diamond_block",
"count": 1
}
}
{
"type": "minecraft:crafting_shapeless",
"ingredients": [
{ "item": "minecraft:wheat" },
{ "item": "minecraft:wheat" },
{ "item": "minecraft:wheat" }
],
"result": {
"id": "minecraft:bread",
"count": 2
}
}
{
"type": "minecraft:smelting",
"ingredient": { "item": "minecraft:beef" },
"result": { "id": "minecraft:cooked_beef" },
"experience": 0.35,
"cookingtime": 200
}
To remove a vanilla recipe, create a file at the same path under data/minecraft/recipe/
in your datapack with just {} as the content:
{}
For example, to disable the piston recipe, create:
data/minecraft/recipe/piston.json containing only {}.
Get the exact filename from the vanilla jar:
jar xf minecraft.jar data/minecraft/recipe/
{
"type": "minecraft:smithing_transform",
"template": { "item": "minecraft:netherite_upgrade_smithing_template" },
"base": { "item": "minecraft:diamond_sword" },
"addition": { "item": "minecraft:netherite_ingot" },
"result": { "id": "minecraft:netherite_sword" }
}
data/<namespace>/loot_table/custom_chest.json{
"type": "minecraft:chest",
"pools": [
{
"rolls": { "type": "minecraft:uniform", "min": 3, "max": 8 },
"entries": [
{
"type": "minecraft:item",
"name": "minecraft:diamond",
"weight": 5,
"functions": [
{
"function": "minecraft:set_count",
"count": { "type": "minecraft:uniform", "min": 1, "max": 3 }
}
]
},
{
"type": "minecraft:item",
"name": "minecraft:gold_ingot",
"weight": 20
},
{
"type": "minecraft:empty",
"weight": 30
}
]
}
]
}
data/<namespace>/predicate/is_daytime.json{
"condition": "minecraft:time_check",
"value": { "min": 0, "max": 12000 }
}
data/<namespace>/predicate/player_has_diamond.json{
"condition": "minecraft:entity_properties",
"entity": "this",
"predicate": {
"inventory": {
"items": [
{ "items": ["minecraft:diamond"] }
]
}
}
}
execute if predicate mypack:is_daytime run say It is daytime!
execute unless predicate mypack:player_has_diamond run tell @s You need a diamond!
data/minecraft/tags/block/climbable.json — override vanilla){
"replace": false,
"values": [
"minecraft:ladder",
"minecraft:vine",
"#minecraft:wool"
]
}
data/<namespace>/tags/item/my_fuel.json){
"replace": false,
"values": [
"minecraft:coal",
"minecraft:charcoal",
"minecraft:blaze_rod"
]
}
Use "replace": false to append to existing tags. Use "replace": true to completely
override (use with care for vanilla tags).
data/minecraft/worldgen/noise_settings/overworld.json)Edit inside an existing copy — do NOT create from scratch without the full JSON.
Get the vanilla version from the Minecraft jar: jar xf minecraft.jar data/.
{
"spawn_costs": {
"minecraft:zombie": {
"energy_budget": 0.12,
"charge": 0.7
}
}
}
# Place datapack in world folder
/datapacks/my-datapack/
# Or as a zip
/datapacks/my-datapack.zip
# In-game commands
/datapack list # see all datapacks
/datapack enable "file/my-datapack"
/datapack disable "file/my-datapack"
/reload # hot-reload all datapacks without restart
.mcfunction or .json files/reload in-game (or /minecraft:reload if a mod intercepts it)latest.log for syntax errors| Error | Cause | Fix |
|-------|-------|-----|
| Unknown or invalid command | Syntax error in function | Check whitespace, selector, trailing space |
| Datapack did not load | Invalid JSON in any file | Validate with jq . < file.json |
| pack metadata mismatch | Wrong pack_format or min_format / max_format values | Update pack.mcmeta for the exact 1.21.x patch |
| Function not running on tick | Missing tick tag or wrong namespace | Check tags/function/tick.json path |
| Macro error | $ line but no with | Provide with storage/entity/block |
Use the bundled validator script before shipping a datapack update:
# Run from the installed skill directory (for example `.codex/skills/minecraft-datapack`):
./scripts/validate-datapack.sh --root /path/to/datapack
# Strict mode treats warnings as failures:
./scripts/validate-datapack.sh --root /path/to/datapack --strict
What it checks:
pack.mcmeta and data/**/*.jsontags/function/load.json and tags/function/tick.json references resolve to real .mcfunction filestools
Operate WorldEdit safely and efficiently for Minecraft 1.21.x server build/admin workflows. Covers selection mechanics, region operations, masks and patterns, clipboards and schematics, brushes and terraforming, undo/history safety, and practical runbooks for spawn edits, arena resets, block cleanup, and path shaping. Use for command-driven world operations, not plugin development.
development
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 compact JSON patterns and validator-backed reference checks for biome, dimension, placed_feature, configured_feature, structure, structure_set, and biome_modifier files. Targets Minecraft 1.21.x with official Mojang mappings. Use when the user asks about Minecraft worldgen, custom biomes, datapack JSON for dimensions or features, or mod-based biome modification with NeoForge or Fabric.
tools
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. Use when the user asks about testing Minecraft mods or plugins, writing GameTests, setting up MockBukkit, or configuring CI for Minecraft projects.
tools
Set up, configure, and operate Minecraft Java Edition servers for 1.21.x across Paper, Purpur, Folia, Velocity networks, and modded (Fabric/NeoForge) deployments. Covers deployment selection, performance tuning playbooks, plugin operations, proxy/forwarding setup, backup and recovery runbooks, live incident troubleshooting, Docker/Pterodactyl patterns, and security hardening. Use for server infrastructure and operations, not plugin or mod feature development.