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.gpu says 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.