Registering a base model¶
Registration adds a base model (see Models) to fAIr: it validates a STAC item, publishes it to the base-models collection, and makes the model available for training and prediction.
Registration is admin only and runs asynchronously. Models are contributed to the fAIr-models repository (see Contributing a model); once the pull request is merged, an admin can trigger registration.
What you need¶
- An admin account (
is_staff = true). - A STAC item that describes the model, either inline JSON or a public URL that returns the JSON.
- Optionally, a
categoryslug that already exists in/api/v1/categories/(for examplebuildings); it defaults toother.
The STAC item¶
The item must be a valid MLM (Machine Learning Model) STAC item. At minimum it
needs properties["mlm:name"], which becomes the model id in the catalog, and a
source-code asset whose mlm:entrypoint is a pipeline bundled in the backend
image (see What registration does). In
practice a base model item also carries the MLM fields (framework, architecture,
tasks, input/output, hyperparameters) and the fair:* fields fAIr uses (compute
requests, preview info, metrics spec).
Two rules to keep in mind:
keywordsare validated against an allowed list. Use the standard task and domain terms (for examplebuilding,semantic-segmentation,polygon). Do not put the category slug inkeywords; the category is written separately as thefair:categoryproperty during registration.- Model weight assets (
model,checkpoint) should point to a location the platform can read. Registration mirrors them into the artifact store under a versioned path and publishes the mirrored hrefs.
A complete reference item lives in the fAIr-models repository, for example
models/dinov3s_buildings/stac-item.json.
Register¶
Send exactly one of stac_item (inline JSON) or stac_item_url (a link fetched
once at request time). category is optional and defaults to other.
inference_endpoint is optional; when given it is written as the
mlm:inference-endpoint asset. The Django admin "Add base model" form takes the same
fields.
By URL:
curl -X POST https://<host>/api/v1/base-models/ \
-H "Authorization: Bearer <admin-token>" \
-H "Content-Type: application/json" \
-d '{
"stac_item_url": "https://<host>/collections/base-models/items/<id>",
"category": "buildings",
"inference_endpoint": "https://<id>.predict.<host>/predict"
}'
Inline instead of a URL:
curl -X POST https://<host>/api/v1/base-models/ \
-H "Authorization: Bearer <admin-token>" \
-H "Content-Type: application/json" \
-d '{"stac_item": { ...full STAC item JSON... }, "category": "buildings"}'
The response is 202 Accepted with the DB record and status: "registering".
For a release, first pin a local copy of the item:
Submit that exact file as inline stac_item in staging and, after testing, in
production. Do not fetch or pin it again between environments: mutable tags may
have moved.
What registration does¶
- Writes the chosen category onto the item as
fair:category. - Pins the
mlm:trainingandmlm:inferenceimage tags to digests. - Rejects the item (400) unless
mlm:entrypointismodels.<model>.pipeline:<function>and bundled in the backend image. New models need afair-py-opsrelease, then a backend release. - Adds the
mlm:inference-endpointasset wheninference_endpointis supplied. - Mirrors downloadable model assets into a version-specific artifact path.
- Applies the model's Knative service. With
FAIR_KNATIVE_TAG=staging, the new revision is served athttps://staging-<model>.predict.<domain>and the live route is unchanged. Without it, the live route moves after the new revision's/healthreadiness probe succeeds. - Publishes the item to the
base-modelscollection off-request, where the version metadata lives. - On success sets the DB row
statustoactiveand recordsstac_item_id. On failure setsstatustofailedand records the error.
The request does not block on publishing. Poll the record until it settles.
A reconcile_knative CronJob re-applies services for all active base models.
Releasing services whose model left STAC (--prune) stays off until STAC item
listing handles every result page.
Verify¶
Poll the record:
curl -s "https://<host>/api/v1/base-models/<id>/" \
-H "Authorization: Bearer <admin-token>" | jq '{name, status, category, stac_item_id, error}'
Fetch the full model with the STAC item inlined:
curl -s "https://<host>/api/v1/base-models/<id>/?expand=stac" | jq '.stac.properties["fair:category"], .stac.assets'
Read the published STAC item directly:
Re-registering¶
The "Re-register selected from STAC" admin action re-publishes an already-published
model from its STAC item. A model that never published (no stac_item_id) is
registered again through POST /base-models/ or the Django admin add form. Every registration writes the row's is_pinned to
the new item's fair:pinned. Registering from the fAIr-models item replaces the title,
description and fair:preview set since the last registration.
Optional: feature the model (pin)¶
Pinning marks a model as featured and can attach a sample imagery layer and a preview location.
curl -X PATCH https://<host>/api/v1/base-models/<id>/pin/ \
-H "Authorization: Bearer <admin-token>" \
-H "Content-Type: application/json" \
-d '{
"is_pinned": true,
"preview_imagery": "https://tiles.example/{z}/{x}/{y}.png",
"preview_location": {"type": "Point", "coordinates": [<lon>, <lat>]}
}'
This flips is_pinned in the database and, for a published model, writes
fair:pinned to the STAC item. preview_imagery and preview_location update
the imagery, center and place of the item's fair:preview, which the model
must already have. A new preview_location also clears the preview bbox.
Edit the title, description and preview¶
PATCH /api/v1/base-models/<id>/metadata/ takes any of title, description and
fair_preview, and writes them to the STAC item after validating the merged item. It
returns 409 while the model has no STAC item.
The Django admin change form edits the same three fields, and its "Pin selected" and
"Unpin selected" actions behave like the pin endpoint. Its "STAC patch" field takes the
same body as PATCH /api/v1/base-models/<id>/stac/ and is written together with those
fields after one validation.
Remove a model¶
This removes the database row, the inference service (when the backend has a Kubernetes
configuration), and the STAC item with its archived versions. If removing the STAC item
fails after the service is gone, the row is restored and reconcile_knative redeploys the
service. It returns 409 while the model is registering or
local models are built on it. Deleting from the Django admin does the same.
Check that the database and STAC agree¶
It compares base models, local models and built datasets with their STAC collections. It lists rows without a live STAC item, live STAC items without a row, and model pin flags that differ, and exits non-zero when it finds any.