Model Catalog Architecture
This repository is an append-only historical catalog of facts claimed by model publishers. It describes models, not individual deployments. A serving provider may expose a smaller context window or a different capability set; those deployment constraints are outside this registry.
Catalog scope
A publisher repository is not automatically a model this registry collects. Two independent questions decide what enters the catalog: who published it and what kind of model it is.
Publishers. providers/*.yaml is the reviewed publisher catalog and the
definition of the core. A brand-new record is only added when its publisher
resolves to a reviewed provider file; a discovery from an unlisted long-tail
publisher (community fine-tunes, mirror directories) is skipped instead. Existing
long-tail records are kept as historical facts and are still enriched, but the
unattended feeds no longer extend them. Adding a publisher file is the explicit
way to widen the scope: the tool never invents official URLs on its own.
A reviewed provider file names the publisher's official organizations and, for
publishers that ship weights, enables discovery of that organization. Its
aliases list records the variant developer spellings a publisher has shipped
under, such as bytedance for ByteDance Seed or stepfun-ai for StepFun, so the
same publisher is not split into two catalog entries. Publishers that only serve
a closed API keep strategy: aggregator, which leaves OpenRouter as the
authoritative identity source for them. A publisher with an official
organization declares strategy: publisher and require_corroboration: true,
which holds an OpenRouter-only record as a candidate until the publisher's own
repository, identifier or official link confirms it: the catalog then carries
first-party models and an official model card URL instead of an aggregation
artifact.
Models. The catalog collects callable models that a Go application can route to:
- general-purpose chat, reasoning, coding and agent models;
- multimodal understanding, including image, audio and video input with text output, and computer-use models;
- text embedding and reranking models;
- speech synthesis and recognition models;
- machine translation models.
It does not collect:
- domain-science models, even when a publisher exposes them through a language-model pipeline tag: protein, DNA/RNA, genome, molecule, chemistry, materials, climate and other field-specific research models, including medical-imaging and biomedical-text models;
- non-language backbones: vision classification, detection, segmentation and depth encoders, speech encoders, audio codecs, 3D generation and geometry models, robot policies and graph models;
- packaging of another checkpoint: redistributions in a different runtime
format (ONNX, GGUF, OpenVINO, WebNN, MLX, TFLite, CoreML) and adapter modules
that cannot run on their own. A precision or compression variant (BF16, FP16,
FP8, NVFP4, INT4, GPTQ, AWQ) is the same model as the checkpoint it was derived
from, so it shares that model's card instead of adding a record of its own;
task catalog-doctorlists it as aquantization_variantand it never reachesmodels_gen.go. When a publisher ships a model only as one precision, that repository is the model's card and the record keeps the model ID.
Scope is decided from the publisher's own metadata — repository tags, declared
architecture, identifiers and (only for unambiguous wording) the description —
not from the upstream pipeline tag alone. A publisher tag such as
text-generation describes a tensor signature, not a product category, which is
how protein checkpoints originally reached this catalog.
internal/registry/scope.go implements the decision and
task catalog-doctor reports every affected record with its reason. A record can
overrule the classifier with an explicit kind field, and the automatic intake
policy in cmd/catalogsync is deliberately narrower than the catalog scope:
ranking, speech and translation models are collected when a human adds them, but
the daily sweep does not walk an organization's entire speech and translation
back catalogue.
Trust model
Facts are selected in this order:
- reviewed human-maintained YAML;
- the publisher's structured API or official documentation;
- a repository owned by the publisher's configured Hugging Face or ModelScope organization;
- OpenRouter structured metadata;
- evidence-backed AI suggestions, only after explicit review.
OpenRouter remains the broad default discovery feed. It is not the canonical owner of model names or publisher specifications. Existing model YAML is never removed merely because an upstream feed stops listing it.
OpenRouter serving variants are not model identities. Suffixes such as
:batch, :free, and :thinking are folded into the underlying model and
retained as runtime aliases plus identifiers.openrouter values. Named modes
such as -pro or -fast are folded only when the upstream description
explicitly says they use the same underlying model or have identical
capabilities; independently published models such as o3-pro remain separate.
Two further classes of upstream records are provider or inference packaging
rather than model identities, so they are never compiled into models_gen.go
or the public catalog:
- Routing aliases are OpenRouter's
~namespace. They move between checkpoints and have no stable identity of their own. When the upstream feed names the model an alias currently resolves to, the alias is folded into that model as an alias and anidentifiers.openroutervalue, and the standalone record is removed; otherwise the record is dropped. A model the publisher itself names-latest, such asopenai/gpt-chat-latest, is a real model and is recorded as-is. - Draft heads are speculative-decoding modules attached to another model's
checkpoint, such as DSpark, DFlash, EAGLE-3, and MTP heads. They are not
standalone language models. Their records stay in
models/for provenance, but they are excluded from every compiled artifact. - Quantization variants are serializations of an existing checkpoint at a
different precision or compression (
-BF16,-FP8,-NVFP4,-GPTQ-INT4,-AWQ,-MLX,-GGUF). They are the same model as their base checkpoint, so the variant ID becomes an alias of the model record that cites the original checkpoint. Only the record ID is inspected: a model whose publisher ships it asNVIDIA-Nemotron-3.5-Lightning-30B-A3B-BF16is still recorded once, asnvidia/nemotron-3.5-lightning.
The classification lives in internal/registry/variant.go, and catalog scope in
internal/registry/scope.go. A record can make the decision explicit with the
optional kind field:
kind: model # model | serving-artifact | draft-head | adapter | out-of-scope | quantization
An explicit kind always wins over the ID and description patterns, so a
reviewed record can override a false positive. serving-artifact, draft-head,
adapter, quantization and out-of-scope are excluded from every compiled
artifact; an empty kind means model. The generator, the public catalog,
Hugging Face candidate materialization and the Codex exporter all use
IsCompiledKind, so an excluded kind can never reach models_gen.go,
catalog.json or a runnable Codex entry.
Publisher catalog
providers/*.yaml defines canonical publisher names, official entry points and
organizations that may be queried deterministically. A Hugging Face repository
is treated as official only when its organization is explicitly configured in
the corresponding publisher file.
Each publisher may declare who owns its model identity:
identity:
strategy: publisher # publisher | aggregator (default)
canonical_prefix: deepseek # optional stable ID prefix
require_corroboration: true # optional; holds new discoveries as candidates
publisher means the provider's official API or organization repositories are
authoritative and OpenRouter is only a discovery and fallback feed. It requires
at least one authoritative source (organizations.huggingface,
organizations.modelscope, or official.api). aggregator is the default and
means OpenRouter is authoritative because the provider has no first-party
machine-readable source.
require_corroboration is opt-in and only valid together with publisher. When
set, a brand-new record discovered through OpenRouter is written as
lifecycle: candidate until an official organization repository or official
link confirms it, and task catalog-promote will not activate it before then.
Candidate records still appear on the public catalog page, so a genuinely
published model is never hidden; only its compiled identity waits for a
first-party source. Publishers that also ship closed models leave the flag off
because they have no repository to corroborate against.
The catalog intentionally starts with major publishers. task catalog-audit
lists long-tail publisher strings that still need a reviewed provider record;
the tool never invents official URLs. task catalog-doctor writes a read-only
data/catalog-doctor.json listing every record by kind plus routing aliases,
draft heads, quantization variants with their format, out-of-scope records with
their reason, pretrained -base variants, resolved identity sources, records
whose identity is not yet corroborated, and publisher models that still lack an
organization repository.
Model records
models/**/*.yaml remains the human-readable source of truth. New optional
fields separate model identity and evidence from discovery metadata:
developer: qwen
links:
official: https://qwen.ai/...
model_card: https://huggingface.co/Qwen/...
identifiers:
official: [Qwen3-32B]
huggingface: [Qwen/Qwen3-32B]
openrouter: [qwen/qwen3-32b]
provenance:
context_length:
source: official_model_card
url: https://huggingface.co/Qwen/...
Top-level fields remain convenient compiled values. provenance explains why
a value was selected without turning each value into a deeply nested object.
It is audit metadata, not permission to overwrite the value: once a top-level
field exists in YAML, every automatic source treats it as immutable.
A model may also pin where its identity came from. This is the highest-priority override and is only needed when the automatic resolution is wrong or when a closed model must be accepted without a first-party repository:
identity:
source: manual # manual | official | official_huggingface | official_modelscope | openrouter
verified: true
When the block is absent, internal/identity resolves the origin in this order:
an explicit block, then a repository inside one of the publisher's declared
official organizations, then an official identifier or link (official_* or
official), and finally OpenRouter. OpenRouter is authoritative for aggregator
publishers and is reported unverified for publisher-strategy publishers until a
first-party source corroborates it. Publishers that declare an official
organization use publisher strategy; the five without one (Anthropic, OpenAI,
OpenRouter, Perplexity, xAI) keep the aggregator default. Corroboration gating
is enabled for the 13 publishers whose releases are effectively open-weight:
allenai, arcee-ai, cohere, deepseek, ibm-granite, microsoft, minimax,
moonshotai, nousresearch, nvidia, tencent, thinkingmachines and zai. Publishers
that also ship closed API models (Amazon, ByteDance Seed, Google, Meta, Mistral,
Qwen) leave require_corroboration off until a first-party source for closed
models exists, because they have no repository to corroborate against.
First-party identity APIs
Publishers without open weights get their first-party source from an official model-list API. The shape is declarative because vendors differ in authentication and payload:
identity:
strategy: publisher
require_corroboration: true
official_api:
url: https://api.anthropic.com/v1/models
env: ANTHROPIC_API_KEY # absent value => that publisher is skipped
auth: x-api-key # bearer | x-api-key | query | none
headers:
anthropic-version: "2023-06-01"
items_path: data # response field holding the array
id_field: id # id | name
id_prefix: models/ # stripped from every identifier (Gemini)
link_template: "" # optional {id} template for an official link
OpenAI, Anthropic, Google and xAI are configured this way. task official-identity
queries them and records only the official identifier (and an official link when
a template is configured) in identifiers.official and links.official; it
never overwrites attributes. It is a dry run unless -- -apply is passed, it
writes data/official-identity.json, and a publisher whose key is unset is
reported as skipped_no_credentials instead of failing, so it is safe to run
without secrets.
Matching is exact on a normalized identifier, with a single local key allowed to
prefix a longer official identifier (which covers dated ids such as
claude-sonnet-4-5-20250929). Ambiguous matches are reported and never guessed.
A dated or versioned release is a model of its own: the 2505 and 2512 builds
of one family are separate records, and qwen-vl-max is not the older
Qwen-VL. Only an exact identity, a declared repository or a corroborating link
folds two ids into one model, while a precision variant never does.
Because these publishers now have a first-party source, they enable
require_corroboration: a model discovered by OpenRouter stays a candidate until
its official API or an official link confirms it, while remaining visible on the
public catalog page.
Incremental workflow
OpenRouter discovery ─┐
├─> compare with historical YAML -> enrich -> AI suggestions -> review
official HF orgs ────┘
-> generate artifacts
task generatordiscovers through OpenRouter, merges missing fields, and preserves all local records and explicit overrides. For publishers that require corroboration it writes a new discovery aslifecycle: candidateinstead of active until a first-party source confirms its identity.task catalog-discoverpaginates subscribed official Hugging Face organizations, preserves a durable candidate queue indata/catalog-discovery.json, applies exact identity matches, and materializes at most five eligible official repositories per run aslifecycle: candidateYAML records. A match compares the repository name with the record id case-insensitively and reads_as a version separator, soLlama-3_1matchesllama-3.1, while-and.stay significant andLFM2-2.6Bcan never be matched tolfm-2.2-6b. Repositories that are outside the catalog scope, or that redistribute another checkpoint (ONNX, GGUF, OpenVINO, ...), or that serialize an existing checkpoint at a different precision (-BF16,-FP8,-NVFP4,-GPTQ-INT4), are recorded in the queue with a status and a reason instead of being materialized. A repository that already backs a record in the catalog — a first-party checkpoint an aggregator record already cites, for example — is registered against that record instead of producing a second record for the same model.- Candidate records are excluded from
models_gen.gountil structured enrichment and evidence-backed extraction provide the required facts.task catalog-promoteactivates only ready records, and for a publisher that requires corroboration only after an official organization repository, official model API or official link confirms the identity. task official-identity -- -applyqueries the configured first-party model APIs to corroborate closed-publisher identity. It is a dry run by default.task enrich -- -new-onlymeans source metadata is actually missing; it does not rescan every schema-v2 record.- model-card AI extraction is bounded to a small incremental batch and produces
suggestions.
suggestion auto-applyaccepts only high-confidence claims from a pinned model card owned by a configured official organization, only for fields that are currently empty; existing facts are never overwritten. task catalog-auditwrites deterministic coverage and attribution gaps todata/catalog-audit.json.task catalog-doctorwrites a deterministic record-kind and identity-gap report todata/catalog-doctor.json;task catalog-doctor-checkgates CI on that report being current.
The initial historical backfill uses the same commands with reviewed allowlists. This makes the one-time work resumable and ensures subsequent GitHub Actions runs exercise exactly the same path on a much smaller delta.
Generation is deterministic: network acquisition happens once, and final Go
code generation reads the immutable cache without another upstream request.
CI checks both models_gen.go and the local audit report for drift. Context and
maximum-output corrections are release-worthy model facts.