Charls ships exactly two transcription models. Both are mirrored from
their upstream sources into Charls-controlled Hugging Face repositories
before being referenced by the app's embedded catalog. This document is the
audit trail: it records where each artifact comes from, under what license,
at which pinned commit, and with what verified file hash.
The machine-readable source of truth is
source-manifest.json, checked by
bun run check:models (scripts/check-model-manifest.ts).
Charls never serves models from handy-computer/* or
blob.handy.computer in a release build. Instead, each artifact above is
copied byte-for-byte into a Charls-controlled Hugging Face organization
(${Organization}/charls-<slug>) via scripts/publish-charls-models.ps1
(see below), and the app's catalog is generated only from the resulting
models/charls-lock.json.
Publishing an artifact to a Charls-controlled repository is forbidden
unless the required upstream license files (LICENSE, attribution/origin
notice) are present in the mirrored repository alongside the model file.
The publish script uploads LICENSE, README.md, and ORIGIN.md together
with the model artifact for exactly this reason — a repository missing any
of these must not be treated as a valid publish target, and the operator
must not point the catalog generator at it.
The publish script is the only supported way to produce
models/charls-lock.json. It never touches handy-computer/* for anything
other than reading the pinned source artifact, and it never uploads
anything until size and SHA-256 have both been verified locally.
1. Dry run (no credentials, no network, no side effects)
Anyone can run this — it only validates the manifest, the lock schema, and
the script's own inputs:
powershell
1# pwsh (PowerShell 7), if installed:2pwsh scripts/publish-charls-models.ps1 -Organization charls-test -VerifyOnly
34# Windows PowerShell 5.1, if pwsh is unavailable:5powershell -File scripts/publish-charls-models.ps1 -Organization charls-test -VerifyOnly
Expected output: 2 model definitions verified, exit code 0. Nothing is
downloaded, nothing is uploaded, and models/charls-lock.json is not
written or modified.
2. Real publish (owner-only, requires credentials)
Real mirroring is a one-way, owner-gated action deferred to whoever
controls the Charls Hugging Face organization. It requires:
The hf CLI (huggingface_hub) installed and on PATH.
hf auth login already run with the Charls owner account (the
script calls hf auth whoami as a strict preflight and aborts if it
fails).
A Hugging Face organization (or namespace) the owner controls, passed as
-Organization. If the desired name is taken, stop and pick the final
organization before running the script or editing the catalog —
destination repo ids are not meant to be renamed after publish.
For each of the two models in source-manifest.json the script will:
Download the pinned file from the source repo at the pinned
source_revision.
Verify its size and SHA-256 against the manifest and abort before any
upload on a mismatch.
Download the upstream LICENSE file from the source repo and refuse to
publish if it is missing.
Create (or reuse) ${Organization}/charls-<slug> and upload the model
file plus LICENSE, README.md, and ORIGIN.md.
Query https://huggingface.co/api/models/<repo_id> for the resulting
commit sha and record it as the pinned destination revision.
The resulting lock is written atomically (models/charls-lock.json.tmp
then renamed to models/charls-lock.json) and must validate against
charls-lock.schema.json: exactly two
entries, each with a repo_id, a 40-character revision, a filename, an
integer size_bytes, and a 64-character sha256.
models/charls-lock.json is the only input the catalog generator
(scripts/gen_catalog.py, Plan 3 Task 3) is allowed to read destination
repo ids and revisions from — it must never read source-manifest.json's
source_repo/source_revision directly.