First mod to bring the PKL language runtime to Minecraft. https://akoto.dev
  • Kotlin 58.1%
  • Pkl 41.4%
  • Just 0.5%
Find a file
2026-06-27 20:32:21 +02:00
.forgejo/workflows ♻️ refactor release workflow 2026-06-27 20:32:21 +02:00
examples mekanism support 2026-05-31 18:03:50 +02:00
gradle/wrapper Init :) 2026-05-26 19:37:47 +02:00
src/main meka udoate 2026-06-10 22:17:39 +02:00
.gitignore bump version to 0.3.3, rename schemas repo to pkl4mc 2026-05-31 15:47:33 +02:00
build.gradle.kts ⬆️ upgrade mod-publish-plugin to 2.1.1 2026-06-27 20:32:08 +02:00
CHANGELOG.md add ci/cd pipeline 2026-06-27 14:51:52 +02:00
gradle.properties 🐛 fix corrupted properties line and reduce xmx 2026-06-27 20:32:12 +02:00
gradlew Init :) 2026-05-26 19:37:47 +02:00
gradlew.bat Init :) 2026-05-26 19:37:47 +02:00
justfile 🔨 script justfile release commit format 2026-06-27 20:32:21 +02:00
LICENSE Init :) 2026-05-26 19:37:47 +02:00
PklProject Add PklProject local for development 2026-05-31 00:34:44 +02:00
PklProject.deps.json Add projecte support 2026-05-31 16:46:44 +02:00
README.md bump 2026-06-10 22:24:52 +02:00
settings.gradle.kts Init :) 2026-05-26 19:37:47 +02:00

pkl4mc

First mod to bring the PKL lang to Minecraft.

[DISCLAIMER] This was originally a dumb idea I had and built for self use and to learn more about PKL runtime and JVM. If it's useful to you too, great.

Unfinished docs -> nothingseries.org/pkl4mc/

What the hell is PKL?

PKL (Pickle) is a typed, composable configuration language by Apple in 2024. It gives autocomplete, type checking and reusable schemas.

Why PKL?

Minecrafts datapack files are JSON. JSON has no variables, no comments, no types and no reuse. Typo a field name? Silent failure, you will probably find out when your loot table doesn't drop anything, or your ore doesn't generate.

PKL kinda fixes this, it will catche the typo before the world loads and lets you define shared logic once.

Here is a smelting recipe in JSON:

{
  "type": "minecraft:smelting",
  "category": "misc",
  "ingredient": { "item": "minecraft:sea_pickle" },
  "result": "nothingcore:cooked_sea_pickle",
  "experience": 0.7,
  "cookingtime": 200
}

And here in PKL:

import "pklmc:recipe.pkl" as recipe

local r: recipe.SmeltingRecipe = new {
  category = "misc"
  ingredient { item = "minecraft:sea_pickle" }
  result = "nothingcore:cooked_sea_pickle"
  experience = 0.7
  cookingtime = 200
}

output { renderer = new JsonRenderer {}; value = r }

Type a field wrong in PKL and it tells you immediately.

Features

Virtual Datapack

Drop .pkl files in config/pkl4mc/data/ and they get evaluated and injected into the data system on world load. No datagen, kinda like KubeJS.

Zip & Folder Datapacks

Same structure as vanilla world/datapacks/, just with .pkl files inside instead of JSON.

config/pkl4mc/
  data/                     ← loose .pkl files (KubeJS-like)
    <namespace>/
      recipes/
      loot_tables/
  datapacks/
    pack.zip              ← zip datapack with .pkl files inside
    pack/                 ← folder datapack with .pkl files
      <namespace>/
        recipes/
        loot_tables/

Commands

Command Description
/pkl errors PKL evaluation errors since last reload
/pkl reload Reload all PKL datapacks without restarting
/pkl convert namespace:path Convert any loaded JSON resource to PKL

The convert command is a migration tool which dumps any vanilla or mod JSON as PKL to config/pkl4mc/data/. Good starting point if you're porting anything.

/pkl convert minecraft:recipes/stick
/pkl convert minecraft:loot_tables/chests/ancient_city
/pkl convert nothingcore:cooked_sea_pickle

Schemas

PKL schemas for vanilla data formats ship inside the jar. IDE autocompletes and type validations work via PKL's language server. (schema coverage is still a wip btw)

Amends style (set fields directly)

Schema Usage
Recipes amends "@pkl4mc/recipe.pkl"
Advancements amends "@pkl4mc/advancement.pkl"
Tags amends "@pkl4mc/tag.pkl"
Dimension types amends "@pkl4mc/dimension_type.pkl"
Biomes amends "@pkl4mc/biome.pkl"
Placed features amends "@pkl4mc/placed_feature.pkl"
Structures amends "@pkl4mc/structure.pkl"
Structure sets amends "@pkl4mc/structure_set.pkl"
Noise settings amends "@pkl4mc/noise_settings.pkl"
Loot tables amends "@pkl4mc/loot_table.pkl"
Configured features amends "@pkl4mc/configured_feature.pkl"

Import style (pick a typed class):

Schema Usage
Configured carvers import "@pkl4mc/configured_carver.pkl" as carver

Config API

So... now that your datapacks are already in PKL, why go back to TOML for configs? For mod devs evaluate PKL files directly to typed Kotlin (or Java) objects.

@Serializable
data class MyConfig(val tickRate: Int, val enabled: Boolean)

val config = PklConfig.load<MyConfig>(
    FMLPaths.CONFIGDIR.get().resolve("mymod/config.pkl")
)

So who is this for?

Probably for modpack or datapack devs, who wanna try something new and maybe hate json for some reason. Also for mod devs who wanna depend on pkl4mc as a library and use PklConfig.

Stack

Version
Minecraft 1.20.1 Forge
Kotlin for Forge 4.12.0
pkl-core 0.31.1 (shaded, ANTLR relocated)

License