Local AI Registry

System and schema

Five minutes. The registry is plain JSON on Git. There is no database. Every file under registry/ is a record; every record carries schema_version: "local-ai-registry/v1" and validates against registry/schema/<collection>.schema.json.

Collections

Collection One record is Key fields
hardware/ One accelerator or Apple chip at one memory capacity. rtx-3090-24gb, apple-m5-max-128gb. vendor, memory, compute, accelerator_backend, aliases, products
model/ One canonical base model. qwen3-8-27b. params, active_params, architecture, huggingface
model-instance/ One downloadable artifact of a model: a quantization at a pinned revision. model_id, repository, revision, weights, huggingface
recipe/ One artifact × hardware × engine launch. The unit of the registry. model_instance_id, hardware_id, hardware_count, engine, launch, serving, capabilities, status, recommended, speed_sweep_ids
speed-sweep/ Measured evidence for one recipe. recipe_id, accepted_at, source, metrics, rows
benchmark/ Scraped public leaderboard scores, keyed by model variant. category, rows[].model_id, rows[].score
price/<product>/<region> Retailer observations for one product in one region. product, region, observations, hardware[]
asset/ An engine config or patch a recipe mounts. Manifest plus blob. file, sha256, purpose
recipe/<id>.json
  model_instance_id ─▶ model-instance/<id>.json
                          model_id ─▶ model/<id>.json
  hardware_id       ─▶ hardware/<id>.json
                          products[] ◀─ price/<product>/<region>.json
  speed_sweep_ids[] ─▶ speed-sweep/<id>.json
  launch.asset_ids[]─▶ asset/<id>.json

Underscores in a field name become hyphens in the directory: model_instance_id resolves under model-instance/.

The recipe launch

launch.kind is docker, compose, script, or reference. Only the first three are executable. A docker launch states image (digest-pinned when validated), entrypoint or arguments, environment, mounts, host_port, container_port, accelerator_backend, network_mode, and provenance for the image. reference launches keep an observed command in metadata and are never run.

Trust: the two statuses

status is one of two values and is computed, not typed in.

validated requires all of:

  1. launch.kind is executable.
  2. The model instance revision is a full commit hash.
  3. The image is @sha256-pinned (docker/compose) or the script path contains a 40-hex commit.
  4. At least one attached speed sweep is acceptance evidence: source.kind == "acceptance-run", or a commit-pinned campaign sweep from a repository under github.com/0xSero/.
  5. The launch never disables CUDA graphs or forces eager mode.
  6. A docker launch is materializable: entrypoint or arguments, both ports, backend, and serving.max_context_tokens.

candidate is everything else. Candidates stay visible with the reason they are not validated.

The definition lives in one file, scripts/trust.py. validate_registry.py imports it and CI fails if any stored status disagrees.

Recommendations: the consumer contract

registry/index/recommendations.json maps each hardware id to exactly one recipe. An entry must be validated, single-GPU, docker, bridge networking, no host IPC. scripts/recommend.py picks it (model tier by VRAM, then engine rank, then largest context, then newest acceptance); the validator refuses more than one per hardware. Served at GET /api/v1/recommendations.

Indexes

registry/index/ holds discovery shards so a client fetches only what its question needs: collections.json (ids and counts), recipes.json (compact filter rows), recipes-by-hardware.json, instances-by-model.json, benchmarks-by-model.json, prices-by-hardware.json, hardware-speed-evidence.json, recommendations.json. All are regenerated by make index and CI refuses a stale index.

Read API

Everything under /api/v1 is GET-only and reads registry/ directly: index, recommendations, facets, models, model-instances, hardware, prices, recipes, compatibility, speed-sweep, benchmarks, each with /:id. Filters mirror record fields. There is no write path.