Small MLflow Model Registry utility for versioning arbitrary model payloads.
Project description
modelctl-mlflow
modelctl is a small CLI wrapper around MLflow Model Registry for storing, verifying, promoting and pulling arbitrary model payloads.
The tool does not try to interpret a payload as a specific ML framework. A registered version is always:
small metadata package + opaque payload directory
MLflow backend storage keeps metadata: runs, versions, aliases, tags and source URIs. MLflow artifact storage keeps the actual payload bytes.
Installation
Install as a CLI tool with uv:
uv tool install modelctl-mlflow
Run once without installing the tool globally:
uvx --from modelctl-mlflow modelctl --help
Install with pip:
pip install modelctl-mlflow
For local development from a checkout:
pip install -e .
or:
uv pip install -e .
After installation, the CLI command is:
modelctl --help
The PyPI package name is modelctl-mlflow; the installed command is modelctl.
Quick start
modelctl register ./model my-model
modelctl list my-model
modelctl info my-model@champion
modelctl pull my-model@champion ./downloaded-model
modelctl verify my-model@champion ./downloaded-model
modelctl promote my-model 3 champion
Commands print machine-readable JSON to stdout. Pass --json <path> to also write the JSON result to a file. Human-readable progress and errors are printed to stderr.
MLflow connection
Default tracking URI:
http://localhost:5000
Override host and port:
modelctl list <model_name> --host <host> --port <port>
Or pass a full tracking URI:
modelctl list <model_name> --tracking-uri <tracking_uri>
MLflow authentication is handled by MLflow itself through its usual environment variables, for example MLFLOW_TRACKING_USERNAME and MLFLOW_TRACKING_PASSWORD.
Register
modelctl register <payload_dir> <model_name>
With explicit aliases:
modelctl register <payload_dir> <model_name> --alias <alias_a> --alias <alias_b>
Default alias behavior:
first version -> baseline + champion
later versions -> candidate
During registration, modelctl:
1. connects to MLflow
2. computes a stable SHA256 payload hash
3. starts a short technical MLflow run
4. writes metadata files
5. logs payload bytes to the artifact store under model/payload
6. creates a Model Registry version
7. writes modelctl.payload_hash to Model Version tags
8. attaches aliases
The registration result is printed as JSON. Human-readable progress is printed to stderr.
Metadata tags
Two optional metadata namespaces are supported:
general - stable descriptive metadata
training - training, dataset, evaluation or build metadata
Full metadata dictionaries are stored as JSON artifacts. A flattened searchable projection is also written to MLflow Model Version tags.
Register with JSON metadata:
modelctl register <payload_dir> <model_name> --general-tags-json <general.json> --training-tags-json <training.json>
Register with inline metadata:
modelctl register <payload_dir> <model_name> --general-tag <key>=<value> --training-tag <key>=<value>
Inline values are parsed as JSON when possible, so numbers, booleans, objects and lists are supported.
Artifact layout
Every registered version stores this package in the artifact store:
model/
├── MLmodel
├── manifest.json
├── payload.sha256.json
├── metadata/
│ ├── general_tags.json
│ └── training_tags.json
└── payload/
└── ... payload contents ...
model/payload/ contains the actual registered payload.
model/payload.sha256.json contains the hash contract:
{
"created_by": "modelctl",
"hash_algorithm": "sha256",
"hash_scope": "payload_tree_v1",
"payload_hash": "sha256:...",
"schema_version": "1.0"
}
The same hash is always written to Model Version tags as:
modelctl.payload_hash=sha256:...
modelctl.source_uri=runs:/<run_id>/model
That tag is the fast path for hash-only verification because it can be read from the registry without downloading the payload.
Pull
Download payload only:
modelctl pull <model_ref> <output_dir>
Download the full package:
modelctl pull <model_ref> <output_dir> --full-package
Supported refs:
<model_name>@<alias>
<model_name>:<version>
models:/<model_name>@<alias>
models:/<model_name>/<version>
By default, pull verifies the downloaded payload hash against modelctl.payload_hash. To skip this verification:
modelctl pull <model_ref> <output_dir> --no-verify
For runs:/... artifacts, pull tries to estimate total bytes with MLflow artifact listing before download. When the backend reports file sizes, stderr progress includes downloaded bytes, percent complete and hash verification percent. If a backend does not expose artifact sizes, progress falls back to observed downloaded bytes without a percent.
If the destination already exists, pass --overwrite:
modelctl pull <model_ref> <output_dir> --overwrite
pull --overwrite is intentionally safe: the existing destination is not removed before download. The new artifact is downloaded into a staging directory next to the destination, verified, and only then swapped into place. If download or verification fails, the previous destination is kept.
Verify
Compare an existing directory with the payload hash stored in the registry:
modelctl verify <model_ref> <path>
Both payload-only directories and full modelctl packages are accepted. If <path> is a full package, modelctl verifies <path>/payload.
Exit codes:
0 - hash matches
1 - command failed
2 - hash mismatch
Example JSON shape:
{
"actual_payload_hash": "sha256:...",
"expected_payload_hash": "sha256:...",
"matches": true,
"model_uri": "models:/<model_name>@<alias>",
"path": "<path>",
"ref": "<model_ref>"
}
List
modelctl list <model_name>
Shows versions, aliases, registry source URI, status, creation time and payload hash.
Info
modelctl info <model_ref>
Shows one resolved registry version with all Model Version tags.
Promote
modelctl promote <model_name> <version> <alias>
Promotion only moves an alias. It does not copy or modify artifacts.
Hash semantics
The payload hash includes:
relative file paths
file bytes
The payload hash ignores:
absolute paths
file mtimes
owners
groups
permissions
This makes the digest stable across machines, mount points and container environments.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file modelctl_mlflow-1.2.1.tar.gz.
File metadata
- Download URL: modelctl_mlflow-1.2.1.tar.gz
- Upload date:
- Size: 19.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.4 {"installer":{"name":"uv","version":"0.10.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3cb409072b98e915ce2450551dc4a383799c610755fa5851352278c60769ae33
|
|
| MD5 |
4cd746b27786afe535f9e292195d4d59
|
|
| BLAKE2b-256 |
fd0770c61d2f81c1689cef22b7dd68a8af0d11649ab1744ec4d7d51a328bc206
|
File details
Details for the file modelctl_mlflow-1.2.1-py3-none-any.whl.
File metadata
- Download URL: modelctl_mlflow-1.2.1-py3-none-any.whl
- Upload date:
- Size: 19.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.4 {"installer":{"name":"uv","version":"0.10.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b463362f0bc13115fe7e29a8669b63c3eb58c646fcff9b9f2279400e252e0b60
|
|
| MD5 |
1e1e8a2c1434b77fb8254d17309069f2
|
|
| BLAKE2b-256 |
f2fc1eecfeac7193e1d8e70825c8e9b84b749f45187179df6b9df6f21f17eb84
|