The AI Adapter Model
How OpenNVR runs AI: every model is an adapter behind one open contract, advertising the tasks it serves, routed and audited by KAI-C, and never named by the apps that use it.
On this page
OpenNVR does not have an AI engine. It has an adapter contract, and every model — the ones that ship, the one you fine-tuned, a cloud endpoint you explicitly allowed — sits behind it as its own container. This page is the model in one read; the pages it links to are the detail.
The three ideas
An adapter serves tasks. It advertises them in tasks_advertised
on GET /capabilities: object_detection, pose_estimation,
license_plate_recognition, scene_caption, and so on. The curated
taxonomy lives in server/config/tasks.yml, and folds common spellings
in as aliases — an adapter may advertise any string it likes and still
register.
An app asks for a task, never for an adapter. requires_tasks: [license_plate_recognition] is satisfied by any adapter advertising
it. That is why replacing a plate reader with a better one touches no
app code, and why an app written today works with a model published
next year. Invent a task nobody asks for and your adapter installs,
reports healthy and receives no work — the one silent failure the
convention exists to make visible, and the thing the catalog validator
fails CI over.
KAI-C sits between them. The backend never calls a model directly.
KAI-C holds the registry, enforces the sovereignty
policy, threads a correlation ID through every call and writes the
audit log. Under the default local_only policy, an adapter declaring
network egress is refused registration — and de-registered if it starts
declaring it later.
What this buys you
- Sovereignty by default. Frames never leave the host unless an administrator opens a route, and the audit log shows every refusal.
- Any licence at the edge. The SDK is Apache-2.0, so an adapter can be open, proprietary or classified. Only the platform core is AGPL.
- Scale by container. One adapter on an edge CPU, or many across a
GPU host — the contract is the same, and
permissions.gpusays which. - Swap without a restart. Register a new adapter, de-register the old one; the apps asking for the task never notice.
Where the compute goes
Running a heavy model on every frame of every camera does not fit modest hardware. The always-on Tier-0 pipeline watches every camera cheaply — motion, a light detector, a tracker, best-frame selection — and publishes tracks to the event bus. The expensive adapters run on the best frame of a real event, once, not continuously. Recording is never gated by any of it.
What ships, and what runs it
- Adapters that ship — the nine in the registry, the tasks each advertises, and the response shapes on the wire.
- The adapter registry — the same list with the experimental adapters in the repo and the ones open for contribution.
- The YOLOv8 adapter is enabled in the stock
docker-compose.yml, so object detection works with nothing configured. The rest enable from the in-product catalog or the compose overlays described in Installation.
Publish your own
The Adapter SDK reference is generated from the SDK’s
docstrings and starts with a whole adapter in a dozen lines. For a model
that takes an image, four names are the entire API. A conformance kit
checks your adapter against the contract before anyone else does, and
getting listed is one entry in server/config/adapters_index.yml.