Your trained model, in one verifiable file.

MLbundle packs a scikit-learn, XGBoost, CatBoost or ONNX model with its manifest and input schema. Loading recomputes what the file claims about the model from the model itself. No pickle anywhere.

pip install "mlbundle[sklearn,schema]"
train.pyexcerpt
export(
    model,
    "trained.mlbundle",
    training_data=training,
    target_names=["target"],
)

bundle = load("trained.mlbundle")
record = {"temperature": 0.0, "humidity": 1.0}
prediction = bundle.predict_record(record)[0]
print(prediction.predicted_label, prediction.probabilities)
python train.py
cold (1.0, 0.0)
trained.mlbundle9.2 KB
  • manifest.jsonWhat the model claims to be
  • model.skopsThe fitted model, in skops format15.0 KB
  • schema.jsonInputs and outputs, inferred locally388 B
  • structure.jsonThe decision tree, for review511 B
mlbundle verify trained.mlbundle
Valid bundle: sklearn "DecisionTreeClassifier"
Real output of examples/train.py with MLbundle 0.2.1.

One file, three parts.

A .mlbundle is a ZIP with a closed list of files. Anything else inside it is rejected before the model is read.

  • The model, in its own format

    Each library keeps its native serialization. The model is stored as it is, never converted and never pickled.

  • A manifest of what it claims

    Class, hyperparameters, feature names and order, class labels, the Python and package versions it was trained with, and a SHA-256 hash for each of the other files.

  • A schema made on your machine

    MLschema describes each input from the training DataFrame locally. The DataFrame itself is not written to the bundle.

Models with readable internals, such as trees and linear coefficients, also carry that structure for review, checked against the loaded model. Training rows are added only when you ask for them with sample_rows=N.Format specification

Inspect reads it. Load checks it.

inspect validates the archive, manifest and hashes without importing a model library. load also deserializes the model, recomputes the claims derived from it, such as hyperparameters, counts, class labels and tree structure, and rejects the file when they differ.

inspectexit 0
mlbundle inspect edited.mlbundle
Metadata and integrity validated; model claims NOT verified.
verifyexit 1
mlbundle verify edited.mlbundle
mlbundle: ClaimMismatchError: bundle rejected.
The example bundle with one edit: max_depth changed from null to 3 in the manifest.

Hashes catch corrupted files, not deliberate edits, and bundles are not signed. The training environment, schema and samples are validated but not authenticated. Treat a bundle from someone else as untrusted input.What MLbundle checks

Four libraries, each in its own format.

A closed adapter inside MLbundle loads each format. Nothing is imported from names written in the bundle, and there is no pickle fallback. A model MLbundle cannot load safely is rejected when you export it, on your machine, not after you share the file.

Supported models
Supported libraries, stored file and install extra
LibraryStored asExtra
scikit-learnmodel.skopsskops, with types allowed by MLbundlesklearn
XGBoostmodel.ubjNative UBJSONxgboost
CatBoostmodel.cbmNative CBMcatboost
ONNXmodel.onnxYour file, byte for byteonnx

Training data stays on your machine.

Export infers the input schema where the data already is, and keeps only the description. Want example rows in the bundle? Pass sample_rows=N: they are real data, so they are never added by default.

Schema and samples

In the bundle

  • Feature names, order and dtypes
  • Each input's kind and whether it may be missing
  • Categories and class labels
  • The fitted model, and what it learned

Left behind

  • The training DataFrame and its rows
  • Ranges, means and counts
  • Example rows, unless you ask for them

Start with one model.

Export a model you already have, then load it the way your application will.

  1. PackageMLbundle
  2. DescribeMLschema
  3. RenderMLform
  4. Run & reviewMLsuite