Skip to content

feat(models): let models.json add models safely without a release - #86

Merged
xycld merged 1 commit into
mainfrom
feat/catalog-rails
Nov 10, 2026
Merged

xycld merged 1 commit into
mainfrom
feat/catalog-rails

Conversation

@xycld

@xycld xycld commented Nov 10, 2026

Copy link
Copy Markdown
Collaborator

What and why

A model should reach released apps by merging a change to apps/desktop/resources/models.json, with no app release.

The bug this fixes. Released apps never read the catalog on main. A packaged app ships models.json next to app.asar, and contentDir() points there. getCatalog treated that copy as a development override, so it never fetched the remote file. Now the override applies in development only (catalogOverrideDir). A packaged app fetches main's file and keeps its own copy as the fallback.

Safety rails (shared/modelCatalog.ts):

  • min_app_version: a model, bundle (either list) or adapter can set this to hide itself from older apps. A bundle with a hidden part is hidden too. A prerelease counts as its release, so a nightly of 2.1.0 meets 2.1.0, unless the minimum names a prerelease itself.
  • catalogProblems checks a remote file before the app uses it:
    • zod shape (unknown fields pass);
    • unique ids;
    • every bundle part exists with the right role;
    • revision is a 40-hex commit or main;
    • min_app_version is valid semver;
    • sizes are positive;
    • schema_version is at most CATALOG_SCHEMA_VERSION (3).
  • Offline: the last good remote file is saved as <data root>/cache/models.json (source: 'cache', already in the Catalog type). A model added after a release stays listed offline. A saved copy older than the packaged catalog (by updated_at) loses to it.
  • CI: test/shared/modelCatalog.test.ts checks the shipped models.json with the same rules, so every PR that edits it is checked.
  • jsDelivr: .github/workflows/catalog.yml purges jsDelivr's copy after a push to main that changes the file. It has contents: read, a 30 s timeout per attempt and 5 retries.

Docs:

  • New docs/how-to/add-a-model.md, added to the docs/README.md index.
  • docs/reference/models.md §1: where the catalog comes from, and the two rules. Its last-verified is not bumped, because I compared only §1.

How it was verified

  • pnpm lint (0 errors, the same 12 warnings as main), pnpm format:check, pnpm typecheck, pnpm test:unit (3566 passed)
  • pnpm test:e2e: not run, because there is no UI change
  • pnpm test:install: not run, because no launcher, install, update or release paths changed
  • Docs updated: docs/how-to/add-a-model.md (new), docs/reference/models.md §1, docs/README.md

New tests:

  • test/shared/modelCatalog.test.ts:
    • the shipped file passes;
    • each rule names its problem;
    • the meetsMinimumVersion table;
    • entriesForApp drops a bundle with a hidden part.
  • test/main/models/models.catalog.test.ts:
    • the remote file is saved and used offline;
    • an old saved copy loses to the packaged one;
    • a newer-schema or broken remote file falls back to the saved copy;
    • min_app_version hides entries and their bundles on a nightly.
  • test/main/lib/content.test.ts: a packaged app has no catalog override.

Platforms affected

  • Windows
  • Linux
  • macOS
  • Platform-independent

Notes for the reviewer

  • Startup fetch: released apps now fetch models.json from GitHub or jsDelivr on catalog refresh, including at startup (8 s timeout, then the saved or packaged copy). Before this, only the network probe touched those hosts.
  • The catalog is not signed. It comes over HTTPS from GitHub or jsDelivr, and it can only name Hugging Face repositories and files. Signing it was considered and left out.
  • Engine support is not checked: min_app_version says nothing about the engine. A model the engine cannot load still needs an engine release first, as the how-to says.
  • The purge workflow's throttle check: it treats "throttled":true in jsDelivr's response as a failed purge. I could not confirm that field against jsDelivr's docs. If the field is absent, the step just succeeds after one call.

@xycld
xycld added this pull request to the merge queue Nov 10, 2026
Merged via the queue into main with commit a9a8703 Nov 10, 2026
5 checks passed
@xycld
xycld deleted the feat/catalog-rails branch November 10, 2026 11:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant