modelshelf 0.1.0

A shared local LLM model registry: discover, deduplicate, download, and update models across desktop apps.
Documentation
# Model catalog

`catalog.json` is the curated list behind `modelshelf recommend`: for each
major local-AI use case (`task`), a small ladder of models so that every
machine, from an 8 GB laptop to a 24 GB GPU workstation, gets one sensible
recommendation per task.

| task | covers | runtime the picks target |
|---|---|---|
| `chat` | general assistant/chat | llama.cpp and any GGUF runtime |
| `code` | coding assistants | llama.cpp |
| `reasoning` | math/logic thinking models | llama.cpp |
| `embedding` | RAG / semantic search | llama.cpp (`--embedding`) |
| `stt` | speech-to-text | whisper.cpp (`ggml-*.bin`) |
| `tts` | text-to-speech | llama.cpp `tts` example (LM + WavTokenizer decoder as `extra_files`) |
| `vision` | image understanding | llama.cpp multimodal (mmproj as `extra_files`) |

The catalog is **data, not code**. Clients embed a snapshot at build time and
refresh from this file on `main` (raw URL) at most once every 7 days, so a
catalog-only commit reaches users without a binary release — including
whole new `task` values.

**Trust model**: the refresh is plain HTTPS from this repository; the
document itself is not separately signed. Entries pin an exact
repo + filename and downloads are verified against the sha256 the
Hugging Face API reports — but a malicious catalog edit could still point
users at a *different, valid* model. Review catalog changes with the same
rigor as code changes; that review is the security boundary.

## Entry format

| field | meaning |
|---|---|
| `name` | stable unique key (kebab-case). Never renamed or reused |
| `task` | use case (see above); defaults to `chat` |
| `repo` / `filename` | Hugging Face repo and exact model file |
| `format` | `gguf` (default), `ggml` (whisper.cpp `.bin`), `onnx` |
| `quant` | quantization label as spelled in the model metadata (`Q4_K_M`, `Q4_0`, `Q8_0`, `MXFP4`, `F16`) |
| `file_bytes` | exact download size, verified against the HF API |
| `params_b` | total parameters in billions (matching hint, not a fit input) |
| `japanese` | `true` when Japanese quality is strong |
| `notes` | one-line description shown to users |
| `deprecated` | optional; superseded entries keep resolving but are never recommended |
| `extra_files` | companion files fetched at provision time (`repo` optional = same repo, `filename`, `file_bytes`); memory fit uses main + extras |

Top-level `catalog_version` is a monotonically increasing integer. Clients
pick whichever of {embedded, cached} catalog has the higher version.

## Curation policy

- **Sources**: first-party repos (Qwen, Google, Mistral, ggml-org, OuteAI,
  ggerganov) or long-established quantizers (bartowski, unsloth,
  lmstudio-community). No anonymous merges or "uncensored" finetunes.
- **No gated repos**: every entry must download without an HF token.
- **Coverage**: per task, keep the size ladder gap-free for that task's
  realistic range (`chat` ~0.5–20 GB; `stt`/`tts`/`embedding` are naturally
  small); flag Japanese-capable entries. Every task must have at least one
  entry a 16 GB machine can run (enforced by tests).
- **Runnable as shipped**: an entry must be usable with the stated runtime
  using only its files — a TTS model without its decoder or a vision model
  without its projector does not qualify; list companions in `extra_files`.
- **Single-file models only**: split GGUF repos
  (`…-00001-of-00004.gguf`) are not supported by the download pipeline
  yet — pick a quantization published as one file (this is why e.g.
  Qwen3-Coder-Next is absent).
- **When to change the list**: a new model family generation clearly beats an
  existing entry on general benchmarks (and Japanese quality for
  `japanese: true` slots), or a rung of a task ladder is empty. Model
  rankings shift irregularly — review on releases, not on a schedule.

## How to update

1. Edit `entries`. **Never delete or rename** an entry that shipped; set
   `"deprecated": true` instead (installed-model matching must keep working).
2. Verify `repo`, `filename`, gating, and `file_bytes` against the API:
   `curl -s 'https://huggingface.co/api/models/<org>/<repo>?blobs=true'`.
3. Increment `catalog_version` and set `updated` (RFC 3339).
4. `cargo test -p modelshelf` — catalog sanity tests parse this exact file.
5. Commit (`docs: catalog v<N> — <summary>`). That is the release.