Skip to main content

Modkeel

Compile the mods Mojang left behind

Python License PyPI CI


Modkeel is a CLI tool that finds, compiles, and verifies unofficial Minecraft mod forks for versions the original authors don't support. When Mojang releases a patch version (like 1.21.10), major mods skip it -- but community forks exist on GitHub as uncompiled branches. Modkeel finds them, builds them, and validates the output.

Playing the mods, not building them? The Modkeel Companion mod backs up your worlds when your mods change and fixes crashes in one click.

Quick Start

pipx install modkeel        # or: pip install modkeel
modkeel compile repos.txt -m 1.21.10 -l neoforge -lv 64 -t "$(cat github_token.txt)"

Quick Demo

Search for a mod

modkeel search

Compile mods from a list

modkeel compile

Check status

modkeel status

GIFs generated with VHS. See demo/README.md to regenerate.

How It Works

For each repository in your list, Modkeel runs:

  1. Modrinth Check -- Search for a pre-compiled JAR first (skip compilation if found)
  2. Fork Discovery -- Search GitHub for compatible forks and independent ports
  3. Branch Scoring -- Rank branches by version match, loader match, and freshness
  4. Pre-validation -- Check gradle.properties via GitHub API before cloning
  5. Cross-loader Fallback -- If no NeoForge match, try Fabric forks via Sinytra Connector
  6. Compile -- Clone, run gradlew build, validate output JAR
  7. Multi-pass Dependencies -- Retry failed mods with mavenLocal() after others succeed
  8. Docker Testing (opt-in) -- Boot a headless MC server to verify mods load

Requirements

  • Python 3.10+
  • Git (in PATH)
  • JDK 17 or 21 (for Gradle compilation)
  • Docker (optional, for --docker-test)
python --version  # 3.10+
git --version
java -version     # 17 or 21

Installation

pipx install modkeel        # isolated install of the `modkeel` command (recommended)
pip install modkeel         # or into the current environment

From source, to work on Modkeel itself:

git clone https://github.com/Modkeel/modkeel.git
cd modkeel
pip install -e ".[dev]"

Releases and their notes: GitHub Releases.

Usage

Compile Mods

modkeel compile repos.txt \
  --mc-version 1.21.10 \
  --loader neoforge \
  --loader-version 64 \
  --github-token "$(cat github_token.txt)"

Compile and Install to Instance

modkeel compile repos.txt \
  -m 1.21.10 -l neoforge -lv 64 \
  --instance "/path/to/minecraft/instance" \
  -t "$(cat github_token.txt)"

Compile and Test in Docker

modkeel compile repos.txt \
  -m 1.21.10 -l neoforge -lv 64 \
  --docker-test \
  -t "$(cat github_token.txt)"

Search Without Compiling

modkeel search "Create" -m 1.21.10 -l neoforge -t "$(cat github_token.txt)"

Get One Mod

modkeel get "Create" -m 1.21.10 -l neoforge -lv 21.10.64

get (and search, without downloading) tries, in order, and prints what it tried:

  1. The mod's official build for that Minecraft version.
  2. An official build for an older version of the same line that still runs on it: its metadata must allow your version, every Minecraft class it uses must exist there, no method or field it calls may have been removed or renamed since the version it was built for, and its mixins must still find their targets (with matching parameters). A static check, so test it in game (or with --docker-test).
  3. A community fork compiled for that version (needs a token and -lv).
  4. Last resort: an older official build refused only by its declared Minecraft range. Modkeel adds your version to that range, but keeps the result only if its bytecode resolves and a headless server boots with it (needs Docker). The file is renamed ...+modkeel-relaxed-... and carries META-INF/modkeel-relaxed.txt.

It never downloads a different mod with a similar name: addons are listed separately.

When nothing runs on your version, Modkeel looks for the nearest Minecraft version with an official build and says so: in a terminal a 15-second countdown starts the search (Enter starts it now, n stops it); without a terminal it only prints the command to run. --fallback auto|never decides without asking. A result for another version goes to out/mc-<version>/ and is never installed into --instance. compile does the same for the whole list (never with --strict): it proposes a version where more of the mods have an official build than were built on yours. On the few versions nearest yours, a mod also counts when its older build passes the static checks there. JARs from the first run that also pass the static checks on the new version are copied instead of built again; mods with an official build there are downloaded fresh.

The last lines say what the JAR passed (Evidence: metadata ✓ · linkage ✓ · ...). With --docker-test, a headless server boots with each result before it is accepted: a JAR that crashes it (for example a mixin whose target changed) is removed and the next candidate is tried. Without Docker the JAR is kept and the output says the test did not run.

compile follows the same order for each repository, with one more step after the official build: the author's own branch for that version, prebuilt or compiled, comes before an older build. --strict never uses an older build. The report says which source each mod came from and, for failures, everything that was tried.

Check Status

modkeel status

Legacy: python mod_auto_compiler.py ... still works but is deprecated. Use modkeel compile instead.

Repository File Format

The repos.txt file contains one repository URL per line:

# Base URL -- Modkeel finds the best branch automatically
https://github.com/Creators-of-Create/Create
https://github.com/mezz/JustEnoughItems

# Specific branch
https://github.com/PepperCode1/Continuity/tree/1.21.10/dev

# Comments start with #

Command Reference

modkeel compile

Option Description Default
repos_file Text file with repository URLs (required)
-m, --mc-version Minecraft version (required)
-l, --loader Mod loader: neoforge, forge, fabric (required)
-lv, --loader-version Loader version number (required)
-i, --instance Minecraft instance path --
-o, --output-dir Output directory out
-t, --github-token GitHub API token --
--strict Require exact MC version match off
--no-cross-loader Disable Sinytra Connector fallback off
--docker-test Test mods in Docker server off
--docker-timeout Docker timeout (seconds) 180
--output-report Save report to file --
--log-file Write log to file --
--no-share Skip anonymous data sharing (sharing is not live yet) off
Option Description Default
query Mod name to search (required)
-m, --mc-version Minecraft version (required)
-l, --loader Mod loader neoforge
-t, --github-token GitHub API token --

modkeel status

No arguments. Shows version, config, cached loaders, and known NeoForge versions.

modkeel move

Moves a pack to another Minecraft version: point it at a mods folder (it is only read) and the version you want, and the whole pack lands in out/mc-<version>/.

modkeel move ~/.minecraft/mods -m 1.21.10
modkeel move "All the Mods 10" -m 1.21.10     # an instance, by name

Each JAR is identified exactly by its hash on Modrinth (no name to guess). For one Modrinth does not know, Modkeel reads what your launcher recorded when it installed the mod (Prism's mods/.index, CurseForge's minecraftinstance.json, a packwiz pack): a Modrinth project id there is exact too, and a CurseForge-only mod is reported as such. Otherwise the id and name in the JAR's metadata are looked up and marked as a guess. Then every mod goes through the same sources as get. A JAR that is on no catalog is checked as it is: if your own file passes the checks on the new version, it is reused. When some mods have no build there, Modkeel proposes the nearest version where more of the pack runs (--fallback ask|auto|never). Shared dependencies are downloaded once.

When the pack is a Prism Launcher instance, the moved pack is also added to Prism as a new instance next to it, " ()": the loader at a version for the new Minecraft, the moved mods, your settings, options.txt, config/, resource and shader packs. Your worlds are not copied (opening one on a new version upgrades it for good: copy it yourself, from a backup), and the old instance is never changed. --no-new-instance leaves only the folder. The Modrinth App and CurseForge keep their instances in their own database, so for them the pack stays in out/mc-<version>/.

modkeel instances

Lists the instances of the launchers on this machine (Prism Launcher, Modrinth App, CurseForge, and the official launcher's .minecraft/mods) with their Minecraft version, loader and number of mods, so modkeel move can take an instance's name instead of a folder. Nothing is changed; --json prints them for scripts.

$ modkeel instances
 Name              Minecraft   Loader             Mods   Launcher
 All the Mods 10   1.21.1      neoforge 21.1.77   412    Prism Launcher
 Cobblemon         1.21.1      fabric 0.16.14     88     Modrinth App

modkeel serve --stdio

Runs the engine for another program (the upcoming Modkeel app, a script, an editor plugin) over JSON lines on stdin/stdout: you send a request, Modkeel streams back its progress as events, asks the questions only you can answer (move to another Minecraft version? a GitHub token?) and ends with a result. Nothing but protocol lines is written to stdout.

$ modkeel serve --stdio
{"type":"hello","protocol":1,"modkeel":"0.1.5","methods":["get","instances","move"]}
{"type":"request","id":"1","method":"get","params":{"query":"Sodium","mc_version":"1.21.10","loader":"fabric"}}
{"type":"event","id":"1","event":{"kind":"mod_identified","query":"Sodium","title":"Sodium",...}}
...
{"type":"result","id":"1","result":{"mod":"Sodium","target":"1.21.10","delivered":{...},...}}

A question ({"type":"question","qid":"1.1",...}) waits for {"type":"answer","qid":"1.1", "value":...}; an answer of the wrong type, or closing stdin, takes the safe choice (keep the version, no token). {"type":"cancel","id":"1"} stops a request. The full message list is in modkeel/core/wire.py.

GitHub API Token

Without a token you're limited to 60 API requests/hour. With a token: 5,000/hour.

  1. Go to github.com/settings/tokens
  2. Generate new token > Tokens (classic)
  3. Select scope: public_repo (only permission needed)
  4. Save the token: echo "ghp_xxx..." > github_token.txt

Troubleshooting

Error Cause Fix
gradle.properties not found Branch lacks Gradle files Try a different branch
Compilation timeout (>10 min) Large mod or slow machine Build manually with ./gradlew build
GitHub API rate limit exceeded No token or too many requests Use --github-token
minecraft_version is X, expected Y Branch targets wrong version Expected -- Modkeel tries the next branch
No JAR file found in build/libs Unusual output path Check build.gradle
JAR declares incompatible MC version Misconfigured mods.toml Try another branch

Contributing

See CONTRIBUTING.md for development setup, testing, and PR guidelines.

License

MIT License -- see LICENSE for details.

Metadata

Release files for modkeel 0.1.5

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for modkeel 0.1.5
File Size Uploaded Provenance Actions
modkeel-0.1.5.tar.gz 662.0 kB With provenance Details for modkeel-0.1.5.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for modkeel 0.1.5
File Interpreter ABI Platform Actions
modkeel-0.1.5-py3-none-any.whl Python 3 none any Details for modkeel-0.1.5-py3-none-any.whl

Total release size: 858.9 kB

Release files / modkeel-0.1.5.tar.gz

Download URL modkeel-0.1.5.tar.gz
Size 662.0 kB
Tags Source
SHA-256 checksum
How to use checksums
83d8a7c9eea6b62a3a823ece75ba1f054a4705b740a9aaf82b181972ab053623
BLAKE2b-256 checksum
How to use checksums
b19ae86765dac28b0935e50258abfc74bdec8f1b9dfc12b58e15ebc41a6a17fe
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.12.8

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 9, 2026.

Transparency log

Release files / modkeel-0.1.5-py3-none-any.whl

Download URL modkeel-0.1.5-py3-none-any.whl
Size 196.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ccb55e8b270aa40c3df497f927fdef307c41415caeef49504077b93f3f087214
BLAKE2b-256 checksum
How to use checksums
97cf0bb507caadf23ae1e7ac2ab605933b851eac01b3fe5a086ef19a5e17da49
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.12.8

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 9, 2026.

Transparency log

Security for modkeel 0.1.5

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

Both files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for modkeel-0.1.5.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 9, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page