Modkeel
Minecraft mods for the version you play, checked before you get them
Modkeel gets a Minecraft mod for the version you play, even when its author has not released for it yet: the author's own build, an older build that still runs there, or a community port built from source. Each one is checked before you get it (its declared versions, its bytecode against the game, a real server start), and Modkeel tells you how it knows. It can also move a whole pack to another version, beside the old one.
This is the command-line engine. Most players want the Modkeel app (Windows, macOS, Linux), which runs the same engine. Everything is open source (MIT) and built by GitHub Actions; see how to check a download.
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
Compile mods from a list
Check status
GIFs generated with VHS. See
demo/README.mdto regenerate.
How It Works
For each repository in your list, Modkeel runs:
- Modrinth Check -- Search for a pre-compiled JAR first (skip compilation if found)
- Fork Discovery -- Search GitHub for compatible forks and independent ports
- Branch Scoring -- Rank branches by version match, loader match, and freshness
- Pre-validation -- Check
gradle.propertiesvia GitHub API before cloning - Cross-loader Fallback -- If no NeoForge match, try Fabric forks via Sinytra Connector
- Compile -- Clone, run
gradlew build, validate output JAR - Multi-pass Dependencies -- Retry failed mods with
mavenLocal()after others succeed - Docker Testing (opt-in) -- Boot a headless MC server to verify mods load
Requirements
- Python 3.10+
- Git (in PATH)
- A JDK for Gradle compilation: Modkeel builds each mod with the Java its Minecraft version runs on
(17, 21, or 25 for 26.x), using one already installed or downloading Eclipse Temurin once
into
~/.modkeel/jdks(SHA-256 checked against Adoptium) - 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:
- The mod's official build for that Minecraft version.
- 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). - A community fork compiled for that version (the fork search needs a token).
- 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 carriesMETA-INF/modkeel-relaxed.txt.
It never downloads a different mod with a similar name: addons are listed separately.
To build one specific port, give its GitHub link instead of a name: Modkeel clones that branch and compiles it, with no search and no token.
modkeel get https://github.com/MineInAbyss/voxy/tree/mc_26_3 -m 26.3 -l fabric
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. Usemodkeel compileinstead.
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 |
modkeel search
| 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.7","methods":["get","github","instances","move","sign_in"]}
{"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 sign-in
Searching community forks uses GitHub's API: 60 requests/hour without signing in, 5,000/hour with your own account. The easy way:
modkeel login
Modkeel shows a code and opens github.com/login/device; enter the code there and approve.
The token is saved in ~/.modkeel/config.toml and used by every command (and the desktop
app, which has the same "Sign in with GitHub" button). It asks for no permissions: it reads
public data only. modkeel token --clear removes it here; revoke it on GitHub under
Settings > Applications > Authorized OAuth Apps. When a run needs GitHub and you are not
signed in, it asks: type login there to do the same.
Prefer a token of your own? Make a classic one at
github.com/settings/tokens with no scopes and save it
with modkeel token --set ghp_... (or pass -t once: it is saved).
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 |
Not signed in, or too many requests | modkeel login |
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, and ARCHITECTURE.md for a map of the code.
License
MIT License -- see LICENSE for details.
Metadata
Release files for modkeel 0.1.13
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| modkeel-0.1.13.tar.gz | 714.9 kB | With provenance | Details for modkeel-0.1.13.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| modkeel-0.1.13-py3-none-any.whl | Python 3 | none | any | Details for modkeel-0.1.13-py3-none-any.whl |
Total release size: 945.2 kB
Release files / modkeel-0.1.13.tar.gz
| Download URL | modkeel-0.1.13.tar.gz |
|---|---|
| Size | 714.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
68441245de85dd1c1a793de5ecd8bc9abd1234c5a785cbbd198823d9b148b765
|
|
BLAKE2b-256 checksum How to use checksums |
9c7cf7eb803dac279ca29d682a46275d93575cbf6bfd1c2f10d53548433c78c8
|
| 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 18, 2026.
Transparency logRelease files / modkeel-0.1.13-py3-none-any.whl
| Download URL | modkeel-0.1.13-py3-none-any.whl |
|---|---|
| Size | 230.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
54ffaa053683009d1d8c8a9c16f862c7a9521b94a85f8f890c85b33ee730a8be
|
|
BLAKE2b-256 checksum How to use checksums |
2e9763cd52a91626a8cf4f5ba4ba875b951cf0b34f7b98b93581b566cb0b1798
|
| 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 18, 2026.
Transparency logSecurity for modkeel 0.1.13
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.
Attestation for modkeel-0.1.13.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 18, 2026.
Transparency logA 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.