A native command-line interface for working with Apple Core ML models on macOS. Inspect, run inference, benchmark, and manage Core ML models without Xcode or Python.
- Inspect - View model structure, inputs/outputs, and metadata
- Predict - Run inference on images, text, or JSON data
- Serve - Expose a model as a local HTTP inference API
- Batch - Process multiple files with concurrent execution
- Benchmark - Measure inference latency and throughput
- Compile - Convert
.mlmodelto optimized.mlmodelcformat - Metadata - View and manage model metadata
brew tap schappim/coreml-cli
brew install coreml-cliDownload the latest release from GitHub Releases:
curl -L https://github.com/schappim/coreml-cli/releases/download/v1.1.0/coreml-1.1.0-macos.tar.gz -o coreml.tar.gz
tar -xzf coreml.tar.gz
sudo mv coreml /usr/local/bin/Requires macOS 13+ and Swift 5.9+
git clone https://github.com/schappim/coreml-cli.git
cd coreml-cli
swift build -c release
sudo cp .build/release/coreml /usr/local/bin/coreml --version
# 1.1.0View model structure, inputs, outputs, and metadata:
coreml inspect MobileNetV2.mlmodelOutput:
Model: MobileNetV2
Size: 24.7 MB
Compiled: No
Inputs:
image: image 224x224 BGRA32
Outputs:
classLabel: string
classLabelProbs: dictionary
Metadata:
Author: Original Paper: Mark Sandler, Andrew Howard...
Description: Detects the dominant objects present in an image...
JSON output for scripting:
coreml inspect MobileNetV2.mlmodel --jsonClassify an image:
coreml predict MobileNetV2.mlmodel --input photo.jpgOutput:
Input: photo.jpg
Inference time: 1.66 ms
Outputs:
classLabel: golden retriever
classLabelProbs: golden retriever: 0.8721, Labrador retriever: 0.0543...
Save results to file:
coreml predict MobileNetV2.mlmodel --input photo.jpg --output results.json --jsonSelect compute device:
coreml predict MobileNetV2.mlmodel --input photo.jpg --device ane # Apple Neural Engine
coreml predict MobileNetV2.mlmodel --input photo.jpg --device gpu # GPU
coreml predict MobileNetV2.mlmodel --input photo.jpg --device cpu # CPU onlyTurn any Core ML model into a local REST endpoint. The model is compiled and
loaded once at startup and stays warm, so requests skip the model-loading cost
that a fresh coreml predict pays every time.
coreml serve MobileNetV2.mlmodelcoreml serve — MobileNetV2
Listening on http://127.0.0.1:8080
Device: all · concurrency: 4 · max body: 32 MB
GET http://127.0.0.1:8080/health
GET http://127.0.0.1:8080/v1/info
POST http://127.0.0.1:8080/v1/predict
curl -X POST -H "Content-Type: image/jpeg" --data-binary @photo.jpg http://127.0.0.1:8080/v1/predict
Press Ctrl-C to stop.
The banner's curl line is generated from the model's own input type, so the
first request is a copy-paste.
| Method | Path | Description |
|---|---|---|
GET |
/ |
Lists the endpoints, input names, and output names |
GET |
/health |
Liveness, uptime, and request/prediction/error counters |
GET |
/v1/info |
Full model description — the JSON coreml inspect --json returns |
POST |
/v1/predict |
Run inference |
Post an image as raw bytes:
curl -X POST -H "Content-Type: image/jpeg" \
--data-binary @photo.jpg \
"http://127.0.0.1:8080/v1/predict?top=3"Or as a file upload:
curl -X POST -F "file=@photo.jpg" http://127.0.0.1:8080/v1/predictResponse:
{
"model": "MobileNetV2",
"inferenceTimeMs": 11.6,
"outputs": {
"classLabel": "golden retriever",
"classLabelProbs": { "golden retriever": 0.8721, "Labrador retriever": 0.0543 }
},
"ranked": {
"classLabelProbs": [
{ "label": "golden retriever", "score": 0.8721 },
{ "label": "Labrador retriever", "score": 0.0543 }
]
}
}?top=N trims classifier dictionaries to the N highest scores. Because JSON
objects carry no ordering, the same results also come back in ranked as an
ordered array.
A tensor model takes a JSON array:
curl -X POST -H "Content-Type: application/json" \
-d '[5.1, 3.5, 1.4, 0.2]' \
http://127.0.0.1:8080/v1/predictcoreml predict feeds one file to the model, so models with several inputs can
only be driven over HTTP. Name each input:
curl -X POST -H "Content-Type: application/json" \
-d '{"inputs": {"sepal_length": 5.1, "sepal_width": 3.5, "petal_length": 1.4, "petal_width": 0.2}}' \
http://127.0.0.1:8080/v1/predict{
"model": "IrisClassifier",
"inferenceTimeMs": 0.13,
"outputs": {
"species": "setosa",
"speciesProbability": { "setosa": 0.9458, "versicolor": 0.0542 }
}
}Values follow each input's declared type: image inputs take a base64 string,
multi-array inputs take a (possibly nested) numeric array, and string, double,
and int64 inputs take their JSON counterparts. A bare {"input": …} works when
the model has exactly one input, and an object already keyed by input name is
accepted as-is.
Errors name what went wrong rather than failing silently:
{ "error": { "status": 422, "message": "Missing value for model input 'sepal_width'. Model inputs: petal_length, petal_width, sepal_length, sepal_width" } }serve binds 127.0.0.1 by default, so a model is never exposed to the network
by accident. To reach it from elsewhere, bind wider and require a key:
coreml serve MobileNetV2.mlmodel --host 0.0.0.0 --api-key "$COREML_API_KEY"curl -X POST -H "X-API-Key: $COREML_API_KEY" \
-H "Content-Type: image/jpeg" --data-binary @photo.jpg \
http://192.168.1.10:8080/v1/predictThe key is accepted as either X-API-Key or Authorization: Bearer. Pass
--cors to allow calls from a browser page.
On a loopback bind the server only answers requests whose Host is a literal IP
address or localhost, so a web page that points a domain it controls at
127.0.0.1 (DNS rebinding) cannot drive your model. If you reach a
loopback-bound server through a name in /etc/hosts, list it:
coreml serve MobileNetV2.mlmodel --allowed-host myapp.local| Option | Default | Description |
|---|---|---|
--port, -p |
8080 |
Port to listen on (0 picks a free one) |
--host |
127.0.0.1 |
Interface to bind |
--device |
all |
Compute device: cpu, gpu, ane, or all |
--concurrency, -c |
4 |
Predictions to run at once |
--max-body-mb |
32 |
Largest request body accepted |
--api-key |
none | Require this key on every request |
--cors |
off | Send CORS headers for browser clients |
--allowed-host |
none | Extra hostname to accept in the Host header (repeatable) |
--quiet, -q |
off | Do not log requests |
Process a directory of images:
coreml batch MobileNetV2.mlmodel --dir ./photos --out ./results --format csvOutput:
Found 100 input files
Results written to: ./results/results.csv
Processed 100 files in 892.45 ms
Average inference time: 2.15 ms
Control concurrency:
coreml batch MobileNetV2.mlmodel --dir ./photos --out ./results --concurrency 8Measure inference latency:
coreml benchmark MobileNetV2.mlmodel --input sample.jpgOutput:
Benchmark Results for: MobileNetV2
==================================================
Configuration:
Device: all
Iterations: 100
Warmup: 10
Latency (ms):
Mean: 1.279
Min: 1.008
Max: 1.602
StdDev: 0.204
Percentiles (ms):
P50: 1.200
P95: 1.523
P99: 1.589
Throughput: 781.86 inferences/sec
Custom iterations:
coreml benchmark MobileNetV2.mlmodel --input sample.jpg -n 500 --warmup 50JSON output for CI/CD:
coreml benchmark MobileNetV2.mlmodel --input sample.jpg --json > benchmark.jsonCompile .mlmodel to optimized .mlmodelc:
coreml compile MobileNetV2.mlmodelOutput:
Compilation successful!
Source: /path/to/MobileNetV2.mlmodel
Output: /path/to/MobileNetV2.mlmodelc
Original size: 24.7 MB
Compiled size: 24.5 MB
With validation:
coreml compile MobileNetV2.mlmodel --validate --output-dir ./compiled/Get model metadata:
coreml meta get MobileNetV2.mlmodelOutput:
Metadata for: MobileNetV2.mlmodel
Author: Original Paper: Mark Sandler, Andrew Howard...
Description: Detects the dominant objects present in an image...
License: Please see https://github.com/tensorflow/tensorflow...
Version: 1.0
Set a metadata field on a .mlmodel or .mlpackage. The model spec is rewritten
in place at the protobuf level — no Python or coremltools required.
coreml meta set MobileNetV2.mlmodel author "Jane Doe"
coreml meta set MobileNetV2.mlmodel description "Image classifier, ImageNet-1k"
coreml meta set MobileNetV2.mlmodel license "MIT"
coreml meta set MobileNetV2.mlmodel version "1.0.1"Pass an empty string to clear a field:
coreml meta set MobileNetV2.mlmodel license ""Write the result to a different file instead of overwriting the source:
coreml meta set MobileNetV2.mlmodel author "Jane" --output MobileNetV2-attributed.mlmodelFor .mlpackage inputs, --output clones the entire package directory and writes
the modified spec inside the clone.
Compiled .mlmodelc models are read-only — modify the source .mlmodel /
.mlpackage and recompile with coreml compile.
| Command | Description |
|---|---|
coreml inspect <model> |
Inspect model structure and metadata |
coreml predict <model> -i <input> |
Run inference on a single input |
coreml serve <model> |
Serve the model as a local HTTP API |
coreml batch <model> --dir <dir> --out <dir> |
Batch process multiple inputs |
coreml benchmark <model> -i <input> |
Benchmark model performance |
coreml compile <model> |
Compile model to optimized format |
coreml meta get <model> |
View model metadata |
coreml meta set <model> <field> <value> |
Set a metadata field (author, description, license, version) |
| Option | Description |
|---|---|
--json, -j |
Output in JSON format |
--device <device> |
Compute device: cpu, gpu, ane, or all |
--help, -h |
Show help information |
--version |
Show version |
| Type | Extensions | Used For |
|---|---|---|
| Images | .jpg, .jpeg, .png, .heic |
Vision models |
| Audio | .wav |
Sound classification |
| Text | .txt |
NLP models |
| Tensors | .json |
Custom models |
#!/bin/bash
# Classify all images in a folder and generate a report
MODEL="MobileNetV2.mlmodel"
INPUT_DIR="./images"
OUTPUT_DIR="./classifications"
# Run batch classification
coreml batch "$MODEL" --dir "$INPUT_DIR" --out "$OUTPUT_DIR" --format csv
# View results
cat "$OUTPUT_DIR/results.csv"#!/bin/bash
# Compare inference speed across compute devices
MODEL="MobileNetV2.mlmodel"
INPUT="test.jpg"
echo "CPU Only:"
coreml benchmark "$MODEL" -i "$INPUT" --device cpu -n 50 --json | jq '.meanLatencyMs'
echo "GPU:"
coreml benchmark "$MODEL" -i "$INPUT" --device gpu -n 50 --json | jq '.meanLatencyMs'
echo "Neural Engine:"
coreml benchmark "$MODEL" -i "$INPUT" --device ane -n 50 --json | jq '.meanLatencyMs'# GitHub Actions example
- name: Benchmark Model
run: |
coreml benchmark model.mlmodel -i test.jpg --json > benchmark.json
- name: Check Performance Regression
run: |
LATENCY=$(jq '.meanLatencyMs' benchmark.json)
if (( $(echo "$LATENCY > 10" | bc -l) )); then
echo "Performance regression detected: ${LATENCY}ms"
exit 1
fiFor models that accept numeric tensor inputs (not images), you can pass JSON arrays:
Create a JSON input file (input.json):
[5.1, 3.5, 1.4, 0.2]Run prediction:
coreml predict MyClassifier.mlmodel --input input.jsonOutput:
Input: input.json
Inference time: 0.12 ms
Outputs:
probabilities: [0.1377, 0.7100, 0.1522]
Batch process multiple JSON files:
# Create a directory with JSON input files
mkdir json_samples
echo '[5.1, 3.5, 1.4, 0.2]' > json_samples/sample1.json
echo '[6.7, 3.1, 4.7, 1.5]' > json_samples/sample2.json
echo '[5.9, 3.0, 5.1, 1.8]' > json_samples/sample3.json
echo '[4.6, 3.4, 1.4, 0.3]' > json_samples/sample4.json
# Run batch prediction
coreml batch MyClassifier.mlmodel --dir json_samples --out json_results --format csvOutput CSV (json_results/results.csv):
input_file,inference_time_ms,probabilities
sample1.json,0.27,"[0.1377, 0.7100, 0.1522]"
sample2.json,0.22,"[0.0613, 0.5931, 0.3456]"
sample3.json,0.29,"[0.0522, 0.5000, 0.4479]"
sample4.json,0.17,"[0.1406, 0.6825, 0.1769]"This is useful for models trained on tabular data, embeddings, or any non-image numeric inputs.
- macOS 13.0 or later
- Apple Silicon or Intel Mac
- Core ML models (
.mlmodel,.mlpackage, or.mlmodelc)
MIT License - see LICENSE for details.
Contributions are welcome! Please open an issue or submit a pull request.
- Built with Swift Argument Parser
- Uses Apple's Core ML framework
CoreML CLI was made by Marcus Schappi. I create software (and even hardware) for real-world businesses, including:
- Little Bird Electronics — Australia's electronics and STEM store, shipping Australia-wide. We sell Arduino, Raspberry Pi, micro:bit, STEM and STEAM education kits, e-textiles, robotics, sensors and electronic components.
- Struth.app — AI runs and grows your trade business. The Struth platform is field service management + CRM + AI.