Model Registry
The Model Registry versions and deploys trained models. Use this resource to register models, manage versions, and promote them to deployment.
Access it as client.model_registry on a Strongly client, or the same path on AsyncStrongly with await. All methods exist on both with identical signatures.
Quick start
from strongly import Strongly
client = Strongly()
# List (auto-paginates as you iterate) # filters: search, framework, source, deployment_status, tag, workspace_id
for model in client.model_registry.list():
print(model.id)
Methods
Core
list
list(*, search: str | None = None, framework: str | None = None, source: str | None = None, deployment_status: str | None = None, tag: str | None = None, workspace_id: str | None = None, limit: int | None = None) -> SyncPaginator[RegisteredModel]
List registered models with pagination and filtering.
Parameters
search(str | None, optional): Search by name, description, or framework.framework(str | None, optional): Filter by framework (e.g."pytorch","tensorflow").source(str | None, optional): Filter by source.deployment_status(str | None, optional): Filter by deployment status.tag(str | None, optional): Filter by tag.workspace_id(str | None, optional): Filter by workspace ID.limit(int | None, optional): Maximum number of items to return (default: all matching items).
create
create(*, name: str, framework: str, source: str | None = None, description: str | None = None, framework_version: str | None = None, python_version: str | None = None, tags: Sequence[str] | None = None, workspace_id: str | None = None, artifact: Mapping[str, Any] | None = None, manifest: Mapping[str, Any] | None = None, manifest_raw: str | None = None, problem_type: str | None = None, feature_names: Sequence[str] | None = None, input_fields: Sequence[Mapping[str, str]] | None = None, requirements: Sequence[str] | None = None, environment_variables: Mapping[str, str] | None = None) -> RegisteredModel
Register a new model.
Parameters
name(str): Human-readable model name.framework(str): Model framework (e.g.sklearn,pytorch).source(str | None, optional): Model source (e.g.external,upload,fine-tuning).description(str | None, optional): Optional description.framework_version(str | None, optional): The library version the model file was saved with (sklearn.__version__etc.).python_version(str | None, optional): The Python the model file was saved with.tags(Sequence[str] | None, optional): Optional tags.workspace_id(str | None, optional): Workspace to register the model in.artifact(Mapping[str, Any] | None, optional): An uploaded artifact reference dict, e.g. {s3Key, sizeMb?, s3Bucket?}.manifest(Mapping[str, Any] | None, optional): Parsed bundle manifest (free-form, fromupload_artifact).manifest_raw(str | None, optional): Raw manifest YAML text.problem_type(str | None, optional): The model's task,"classification"or"regression". Stored attraining.problemType; required by drift detection to compare the right distributions (set it if you plan to run :doc:drift-detectionon the model).input_fields(Sequence[Mapping[str, str]] | None, optional): A single model file's inputs in the order it takes them, e.g.[{"name": "tenure", "type": "int"}, {"name": "plan", "type": "string"}](typefloat,int,stringorbool). Required for a single.joblib/.pkl/.pt/.onnxfile: its inputs are fed in this order. Passfeature_nameswith the same names.requirements(Sequence[str] | None, optional): pip requirements a single file's pickle imports beyond its framework (e.g."category-encoders==2.6.3"), installed in its serving image.environment_variables(Mapping[str, str] | None, optional): The model's own environment variables, set on its serving pod. Names the platform sets (MODEL_*,STRONGLY_*,AWS_*,FRAMEWORK, ...) are refused.- `A single model file is registered only with ``framework_version```
(scikit-learn, xgboost, lightgbm, torch), ``python_version`` (apickle) and ``input_fields``: it is served with exactly that libraryand Python, and fed its inputs in that order.
retrieve
retrieve(model_id: str) -> RegisteredModel
Get a single registered model by ID.
update
update(model_id: str, *, name: str | None = None, description: str | None = None, framework: str | None = None, tags: Sequence[str] | None = None, problem_type: str | None = None) -> RegisteredModel
Update a registered model; only the fields given change.
Parameters
model_id(str): The model.name(str | None, optional): A new name (unique among your models).description(str | None, optional): A new description.framework(str | None, optional): The model's framework.tags(Sequence[str] | None, optional): Its tags.problem_type(str | None, optional): The model's task:classification,regression,multiclass,multilabel,timeseriesorother. Setstraining.problemTypeand keeps the rest of its training record. Drift detection needsclassificationorregression: set it on a model registered without one (e.g. a run's model whose tasklog_modelcould not tell).
delete
delete(model_id: str) -> None
Delete a registered model.
Lifecycle & actions
start
start(model_id: str) -> RegisteredModel
Start a previously-stopped registered model.
stop
stop(model_id: str) -> RegisteredModel
Stop a deployed registered model (tears down its serving pod).
The platform deploys from a non-running state, so stop a running model
before deploying a different version of it (see deploy_version).
deploy
deploy(model_id: str, **kwargs) -> RegisteredModel
Deploy a registered model.
Parameters
model_id(str): The model ID.**kwargs(Any): How it runs, snake_case:resources{cpu, memory, gpu, gpu_type, replicas}`, `auto_shutdown_minutes(above 0 deploys on demand),scheduling_mode("always_on","on_demand"or"scheduled"),schedule_rules(API shape:[{"id", "action", "dayOfWeek", "time", "timezone"}]),scaling_mode,min_replicas,max_replicas,target_concurrency,autoscaling,use_spotandspot_fallback.update_servingchanges them without deploying.
Other
activate_baseline
activate_baseline(model_id: str, baseline_id: str) -> dict[str, Any]
Make an earlier baseline its version's active one again.
Drift compares the version with it from the next analysis on.
activate_version
activate_version(model_id: str, version: int) -> RegisteredModel
Set the active version (served artifact/metrics) without deploying.
actuals_upload_url
actuals_upload_url(model_id: str, filename: str) -> UploadLink
Return a link to upload a CSV of actuals of any size.
(predictionId or entityId, actual, optionally actualAt).
import_actuals_file uploads and imports in one call.
analytics
analytics(model_id: str, *, period: str | None = None) -> dict[str, Any]
Get who calls a model, how often, and how fast and well it answers.
Parameters
model_id(str): The model's ID.period(str | None, optional): 7d, 30d (the default) or 90d.
baseline_upload_url
baseline_upload_url(model_id: str, filename: str) -> UploadLink
Return a link to upload a CSV of a version's reference rows of any size.
build_baseline_from_file uploads and builds in one call.
build_baseline
build_baseline(model_id: str, *, upload_id: str | None = None, filename: str | None = None, volume_id: str | None = None, path: str | None = None, version: int | None = None, analyze_daily: bool = False) -> BaselineJob
Build a version's drift baseline from its reference rows.
(the data it was trained or validated on): a CSV with a column per input feature and,
optionally, actual, prediction and confidence.
Parameters
upload_id, filename(str | None, optional): An upload frombaseline_upload_url.volume_id, path(str | None, optional): Or a file on a shared volume.version(int | None, optional): The version the rows describe (default: the active version).analyze_daily(bool, optional): Turn on the model's daily drift analysis once the baseline is kept (the first analysis counts as that day's run).
Returns
BaselineJob: The job. Its baseline becomes the version's active one, and the version's first drift analysis starts when it has production predictions from the last 7 days. Follow it withlist_baseline_jobs.
build_baseline_from_file
build_baseline_from_file(model_id: str, file: str | Path | BinaryIO, *, version: int | None = None, analyze_daily: bool = False) -> BaselineJob
Upload a local CSV of reference rows (streamed, any size) and build the baseline from it.
See build_baseline.
create_version
create_version(model_id: str, *, artifact: Mapping[str, Any], description: str | None = None, manifest: Mapping[str, Any] | None = None, manifest_raw: str | None = None, metrics: Mapping[str, Any] | None = None, framework_version: str | None = None, python_version: str | None = None, requirements: Sequence[str] | None = None, input_fields: Sequence[Mapping[str, str]] | None = None) -> dict[str, Any]
Add a new version to a registered model from an uploaded artifact.
Upload the new artifact first with upload_artifact and pass its
reference ({"s3Key": ...}) as artifact - or use
create_version_with_upload, which does both.
Parameters
model_id(str): The registered model's id.artifact(Mapping[str, Any]): Artifact reference{"s3Key", "s3Bucket"?, "sizeMb"?}.description(str | None, optional): Version description / changelog.manifest(Mapping[str, Any] | None, optional): Parsed manifest (for.zipbundles).manifest_raw(str | None, optional): Raw manifest text.metrics(Mapping[str, Any] | None, optional): Evaluation metrics for this version.framework_version, python_version, requirements(optional): For a single model file: the library and Python it was saved with and the pip requirements its pickle imports (seecreate).input_fields(Sequence[Mapping[str, str]] | None, optional): This version's inputs in order, when they differ from the model's.
Returns
dict[str, Any]:{"version": <int>, "modelId": <id>}- the new version number.
create_version_with_upload
create_version_with_upload(file: str | Path | BinaryIO, model_id: str, *, description: str | None = None, metrics: Mapping[str, Any] | None = None, framework_version: str | None = None, python_version: str | None = None, requirements: Sequence[str] | None = None, input_fields: Sequence[Mapping[str, str]] | None = None) -> dict[str, Any]
Upload a new artifact and add it as a new version, in one call.
The registry-level analogue of create_with_upload, but for a
model that already exists: it streams the new bundle up and appends a
version pointing at it. Deploy it with deploy_version.
Returns
dict[str, Any]:{"version": <int>, "modelId": <id>}.
create_with_upload
create_with_upload(file: str | Path | BinaryIO, *, name: str, framework: str, description: str | None = None, tags: list[str] | None = None, workspace_id: str | None = None, problem_type: str | None = None, feature_names: Sequence[str] | None = None, framework_version: str | None = None, python_version: str | None = None, input_fields: Sequence[Mapping[str, str]] | None = None, requirements: Sequence[str] | None = None, environment_variables: Mapping[str, str] | None = None) -> RegisteredModel
Upload a model artifact and register it in one call.
Combines upload_artifact (the bundle streamed to object storage and validated)
and create (the registry entry), attaching the uploaded artifact
and any parsed manifest so the model is immediately deployable.
Parameters
file(str | Path | BinaryIO): Path or open binary file - a.zipbundle with astrongly.manifest.yamlor a single.pkl/.joblib/.pt/.onnxartifact.name(str): Human-readable model name.framework(str): Model framework (sklearn,xgboost,pytorch,tensorflow,onnx,custom). A bundle manifest's framework, when present, takes precedence server-side.description(str | None, optional): Optional description.tags(list[str] | None, optional): Optional tags.workspace_id(str | None, optional): Optional workspace to register the model in.problem_type(str | None, optional): The model's task,"classification"or"regression". Set it if you plan to run drift detection on the model (drift requirestraining.problemType).feature_names(Sequence[str] | None, optional): The model's input names in order (tabular frameworks require them).framework_version(str | None, optional): The library version a single model file was saved with (required for scikit-learn, xgboost, lightgbm and torch files).python_version(str | None, optional): The Python a single.joblib/.pklfile was saved with (required for a pickle).input_fields(Sequence[Mapping[str, str]] | None, optional): A single model file's inputs in the order it takes them, e.g.[{"name": "tenure", "type": "int"}, {"name": "plan", "type": "string"}](typefloat,int,stringorbool). Required for a single.joblib/.pkl/.pt/.onnxfile: its inputs are fed in this order. Passfeature_nameswith the same names.requirements(Sequence[str] | None, optional): pip requirements a single file's pickle imports beyond its framework (e.g."category-encoders==2.6.3"), installed in its serving image.environment_variables(Mapping[str, str] | None, optional): The model's own environment variables, set on its serving pod. Names the platform sets (MODEL_*,STRONGLY_*,AWS_*,FRAMEWORK, ...) are refused.
Returns
RegisteredModel: The registeredRegisteredModel, ready todeploy.
Examples
import sys, sklearn
model = client.model_registry.create_with_upload(
"model.joblib",
name="churn-rf",
framework="sklearn",
framework_version=sklearn.__version__,
python_version=sys.version.split()[0],
problem_type="classification",
feature_names=["tenure", "monthly_spend"],
input_fields=[
{"name": "tenure", "type": "int"},
{"name": "monthly_spend", "type": "float"},
],
)
client.model_registry.deploy(model.id)
deploy_version
deploy_version(model_id: str, version: int, **kwargs) -> RegisteredModel
Deploy a specific version: set it active and (re)deploy the pod.
Parameters
model_id(str): The model ID.version(int): The version to deploy.**kwargs(Any): The deploy's size and scaling, asdeploytakes them.
import_actuals
import_actuals(model_id: str, *, upload_id: str | None = None, filename: str | None = None, volume_id: str | None = None, path: str | None = None) -> ActualsImport
Import a CSV of actuals.
An upload (upload_id from actuals_upload_url and its filename) or a file on
a shared volume (volume_id and path). A job reads it; follow it with
list_actuals_imports.
import_actuals_file
import_actuals_file(model_id: str, file: str | Path | BinaryIO) -> ActualsImport
Upload a local CSV of actuals (streamed, any size) and import it.
list_actuals_import_rejections
list_actuals_import_rejections(model_id: str, import_id: str, *, search: str | None = None, limit: int | None = None) -> SyncPaginator[ActualsImportRejection]
Return the rows an actuals import could not record, each with its line and why.
list_actuals_imports
list_actuals_imports(model_id: str, *, search: str | None = None, sort: str | None = None, limit: int | None = None) -> SyncPaginator[ActualsImport]
Return the model's actuals imports (newest first): status and counts.
Parameters
sort(str | None, optional):-createdAt(default),status,rowsRead,recorded,rejected.
list_baseline_jobs
list_baseline_jobs(model_id: str, *, search: str | None = None, sort: str | None = None, limit: int | None = None) -> SyncPaginator[BaselineJob]
Return the model's baseline jobs (newest first).
Parameters
sort(str | None, optional):-createdAt(default),status,modelVersion.
list_callers
list_callers(model_id: str, *, period: str | None = None, search: str | None = None, sort: str | None = None, limit: int | None = None) -> SyncPaginator[ModelCaller]
List a model's callers over a period, with their predictions and failures.
Parameters
model_id(str): The model's ID.period(str | None, optional): 7d, 30d (the default) or 90d.search(str | None, optional): Only callers whose name, email, app or workflow contains this.sort(str | None, optional): predictions, errors, lastSeen or name; prefix - for descending. -predictions when omitted.limit(int | None, optional): The most callers to return; all of them when omitted.
list_versions
list_versions(model_id: str) -> list[ModelVersion]
List a registered model's versions, in registration order.
Version 1 is created when the model is first registered; each call to
create_version (or create_version_with_upload) appends a
new one. Use RegisteredModel.active_version (or the model's
activeVersion) to see which one is currently served.
logs
logs(model_id: str, *, log_type: str | None = None) -> dict[str, Any]
Get a registered model's build or runtime logs.
Parameters
model_id(str): The model's ID.log_type(str | None, optional): build (the default) or runtime.
predict
predict(model_id: str, input_data: Any, *, entity_id: str | None = None, source: str | None = None, path: str | None = None) -> dict[str, Any]
Run inference on a deployed registered model.
The model must be deployed (deployment status running). The request
is proxied to the model's pod through the AI Gateway, since model pods
are internal to the cluster.
Every prediction is recorded with its model version.
Parameters
model_id(str): The registered model's id.input_data(Any): The prediction input, forwarded to the model's serving endpoint. For the built-in tabular server pass a list/array of feature rows (e.g.X[:3]), a{"instances": rows}dict, or a single{feature: value}row dict. numpy arrays and pandas DataFrames/Series are accepted directly (converted to lists). A model that resolves its features from a feature store takes just the entity keys ({"driver_id": 1002}); an entity the store has no current value for fails withUnprocessableEntityError(422).entity_id(str | None, optional): Your id for what is predicted; actuals can join on it.source(str | None, optional):"production"(default) or"test"; test predictions are kept out of production results (drift, A/B tests).path(str | None, optional): The route on the model to call when it serves more than one (e.g."parse_text"); omit it for the model's default.
Returns
dict[str, Any]: A dict withprediction/predictions,probabilities,latency_ms,prediction_id(prediction_idsfor several rows) andentity_id. Record actuals againstprediction_id(or yourentity_id) withrecord_actuals.
record_actuals
record_actuals(model_id: str, actuals: Sequence[Mapping[str, Any]]) -> ActualsRecordResult
Record actuals (true outcomes) for the model's predictions.
Parameters
actuals(Sequence[Mapping[str, Any]]): Each{"predictionId" or "entityId", "actual", "actualAt"?}(snake_case keys accepted). An entity id actual labels that entity's predictions made within the model's actuals window beforeactualAt(else now); either may arrive first. A second actual for the same key replaces the first.
Returns
ActualsRecordResult: How many were recorded or replaced, and the rows refused with why.
status
status(model_id: str) -> dict[str, Any]
Get a registered model's serving status.
Parameters
model_id(str): The model's ID.
Returns
dict[str, Any]: model_id, status, can_serve (whether it answers a prediction now, waking it if it is idle), active_version, version_count and updated_at.
update_monitoring
update_monitoring(model_id: str, *, record_inputs: bool | None = None, label_window_days: int | None = None) -> dict[str, Any]
Change the model's monitoring settings; they apply from its next prediction.
Parameters
record_inputs(bool | None, optional): Keep each prediction's inputs and whole output (default on). Turn it off for models whose inputs are sensitive: predictions are still recorded, but input drift cannot be measured.label_window_days(int | None, optional): How long an actual keyed by entity id may take to arrive and still label that entity's predictions (1 to 90 days; default 14).
update_serving
update_serving(model_id: str, *, environment_id: str | None = None, resources: Mapping[str, Any] | None = None, autoscaling: Mapping[str, Any] | None = None, scheduling_mode: str | None = None, auto_shutdown_minutes: int | None = None, schedule_rules: Sequence[Mapping[str, Any]] | None = None, scaling_mode: str | None = None, min_replicas: int | None = None, max_replicas: int | None = None, target_concurrency: int | None = None, use_spot: bool | None = None, spot_fallback: bool | None = None) -> dict[str, Any]
Change how the model is served (its Environment tab), without deploying.
A registry model has the scaling strategies a self-hosted model has:
always on (scheduling_mode="always_on", optionally with the
autoscaling HPA), on demand (auto_shutdown_minutes of at least
1, scaling_mode "fixed" or "auto" with min/max/target),
or scheduled (scheduling_mode="scheduled" with
schedule_rules), and optionally spot capacity. Scheduling and
demand scaling apply to a deployed model at once; resources and spot
from its next deploy.
Parameters
environment_id(str | None, optional): An environment to size the model by, or"custom"forresources.resources(Mapping[str, Any] | None, optional):{cpu, memory, gpu, gpu_type, disk, replicas}.autoscaling(Mapping[str, Any] | None, optional): The always-on HPA:{enabled, min_replicas, max_replicas, cpu_threshold, memory_threshold}.scheduling_mode(str | None, optional):"always_on","on_demand"or"scheduled".auto_shutdown_minutes(int | None, optional): Idle minutes before an on-demand model scales to zero; 0 means always on.schedule_rules(Sequence[Mapping[str, Any]] | None, optional): A scheduled model's start and stop times, each{id, action: "start" | "stop", day_of_week: [0-6] (0 = Sunday), time: "HH:MM", timezone: IANA name}; at least one start and one stop.scaling_mode(str | None, optional):"fixed"or"auto"(on-demand demand scaling).min_replicas, max_replicas(int | None, optional): The awake replica bounds forscaling_mode="auto".target_concurrency(int | None, optional): In-flight predictions per replica"auto"sizes for.use_spot(bool | None, optional): Run on spot capacity.spot_fallback(bool | None, optional): Withuse_spot, fall back to on-demand capacity when spot is unavailable (defaultTrue).
Returns
dict[str, Any]: The model.
upload_artifact
upload_artifact(file: str | Path | BinaryIO) -> dict[str, Any]
Upload a model artifact bundle to the registry's object store.
Parameters
file(str | Path | BinaryIO): A path or open binary file. Either a.zipbundle that contains astrongly.manifest.yaml(at its root or one level nested), or a single serialized model file (.pkl/.joblib/.pt/.onnx), up to 5 GB. It is streamed straight to object storage through a presigned link, then validated.
Returns
dict[str, Any]: The upload result:s3Key,sizeMb,bucketand, for manifest bundles,manifest/manifestRaw. Pass these tocreateto register the artifact - or just callcreate_with_upload, which does both.