---
name: Core model registry
type: architecture-map-page
slice: 05-core-storage-hotkey-build
last_verified: 2026/05/09
---

# Core model registry

> **Where you are:** [Architecture map](../README.md) → [Core, Storage, Hotkey, Build](README.md) → Core model registry

**Plain English summary.** The static catalogue of every speech-to-text model Lumotia ships or knows how to download. One Parakeet ONNX model and six Whisper GGML variants, each with pinned Hugging Face revisions and SHA256 digests so a downloaded file can be verified bit-for-bit against the registry. Pure data — the recommendation scoring lives in [`core-recommendation.md`](core-recommendation.md).

## At a glance

- File: `crates/core/src/model_registry.rs` (247 LOC).
- External deps: standard library only (`LazyLock`).
- Public surface: `Engine`, `SpeedTier`, `AccuracyTier`, `LanguageSupport`, `ModelFile`, `ModelEntry`, `all_models`, `find_model`.
- Consumers: slice 2 model commands, the model manager, the recommendation engine ([`core-recommendation.md`](core-recommendation.md)), the runtime-capabilities banner, the frontend model picker.

## What's in here

### Enums — `crates/core/src/model_registry.rs:7-36`

```rust
pub enum Engine          { Whisper, Parakeet, Moonshine }
pub enum SpeedTier       { Instant, Fast, Moderate, Slow }
pub enum AccuracyTier    { Excellent, Great, Good }
pub enum LanguageSupport { EnglishOnly, Multilingual(u16) }
```

`Moonshine` is reserved (no live entries today). `LanguageSupport::Multilingual(u16)` carries the count of supported languages but only the variant is used in scoring.

### `ModelFile` — `crates/core/src/model_registry.rs:39`

```rust
pub struct ModelFile {
    pub filename: &'static str,
    pub url: &'static str,
    pub size: Megabytes,
    pub sha256: &'static str,  // hex, length 64
}
```

Every URL pins a specific Hugging Face revision SHA. The registry's test (`model_registry.rs:222-246`) asserts that no URL contains `/resolve/main/` and that every digest is exactly 64 hex characters.

### `ModelEntry` — `crates/core/src/model_registry.rs:50`

```rust
pub struct ModelEntry {
    pub id: ModelId,
    pub engine: Engine,
    pub display_name: &'static str,
    pub disk_size: Megabytes,
    pub ram_required: Megabytes,
    pub speed_tier: SpeedTier,
    pub accuracy_tier: AccuracyTier,
    pub languages: LanguageSupport,
    pub files: Vec<ModelFile>,
    pub description: &'static str,
}
```

### `ALL_MODELS` — `crates/core/src/model_registry.rs:63`

A `LazyLock<Vec<ModelEntry>>`. Seven entries:

| ID | Engine | Disk | RAM | Speed | Accuracy | Notes |
|---|---|---|---|---|---|---|
| `parakeet-ctc-0.6b-int8` | Parakeet | 650 MB | 700 MB | Instant | Great | Four ONNX shards. English only. |
| `whisper-tiny-en` | Whisper | 75 MB | 390 MB | Fast | Good | Bundled with the app. |
| `whisper-base-en` | Whisper | 142 MB | 500 MB | Fast | Good | Sweet spot for low-RAM. |
| `whisper-small-en` | Whisper | 466 MB | 1024 MB | Moderate | Great | Accuracy-first. |
| `whisper-distil-small-en` | Whisper | 336 MB | 900 MB | Fast | Great | Distilled, ~6× faster than `small`. |
| `whisper-medium-en` | Whisper | 1500 MB | 2600 MB | Slow | Excellent | Best Whisper accuracy. |
| `whisper-distil-large-v3` | Whisper | 1550 MB | 2800 MB | Moderate | Excellent | Near `large-v3` accuracy. |

All entries are English-only at present. Multilingual variants would slot into `languages` cleanly.

### Public functions

```rust
pub fn all_models() -> &'static [ModelEntry];           // model_registry.rs:208
pub fn find_model(id: &ModelId) -> Option<&'static ModelEntry>;  // model_registry.rs:213
```

Both return references into the `LazyLock`. No allocation.

## Data flow / contract

- Pure data. Lookups are read-only.
- The Parakeet entry's four files are fetched by the model downloader as a directory of `<model_id>/` siblings (see [`core-paths.md`](core-paths.md)). Whisper entries are single GGML files.
- The `description` field is user-facing copy. British-English spelling enforced.
- SHA256 verification happens in the model downloader (slice 3), not here.

## Tests

`crates/core/src/model_registry.rs:217-246`:

- `every_model_file_has_sha256_and_pinned_url` — guard against accidental drift. SHA must be 64 hex chars; URL must not contain `/resolve/main/`.

## Watch-outs

- **Hugging Face revisions can be force-pushed.** The pinned revision SHAs in the URLs are content addresses on HF's git LFS, but a maintainer with admin rights can in theory rewrite history. The local SHA256 verification at download time catches this. There is no automated CI check that re-fetches and verifies; verification happens lazily on user-facing downloads.
- **`description` is `&'static str`.** No i18n. If we localise the model picker we will need a key plus a separate string table.
- **Adding a new model requires a recompile.** No runtime registry override path. Conscious choice — keeps the surface area small and the SHA256 invariants meaningful.
- **`Moonshine` is in the enum but no entries.** Compiler does not complain because the enum is `non_exhaustive`-shaped via match arms inside scoring (see [`core-recommendation.md`](core-recommendation.md)). When a Moonshine entry lands, the scoring path needs an explicit accelerator branch.

## See also

- [Public types and enums (Megabytes, ModelId)](core-types-and-enums.md)
- [Recommendation scoring](core-recommendation.md)
- [App paths (`speech_model_dir`)](core-paths.md)
- [Slice 3 model manager](../03-audio-transcription/README.md)
