candding
Concepts

Model files and cache

Where candding looks for weights, which files it downloads and reads, how gated repositories work and how to use a local directory.

Cache layout

candding reads the Hugging Face cache that the hf CLI and the Python libraries write, so a model you already pulled for another tool is a model candding can load. The root is $HF_HUB_CACHE when it is set, otherwise $HF_HOME/hub, otherwise ~/.cache/huggingface/hub.

~/.cache/huggingface/hub/
  models--BAAI--bge-small-en-v1.5/
    refs/main                 one line: the commit hash the branch points at
    snapshots/<hash>/         config.json, tokenizer.json, model.safetensors
    blobs/                    the file contents the snapshot entries link to

A repository id becomes a directory name by replacing every slash with a double dash, so BAAI/bge-small-en-v1.5 is models--BAAI--bge-small-en-v1.5. The revision defaults to main and the builder's revision method takes a branch, a tag or a commit hash. Resolution reads refs/<revision> to get the hash and then looks for snapshots/<hash>/; when there is no such ref file, the revision is treated as a commit hash and looked up under snapshots/ directly, which is what makes a pinned hash work without a ref.

What gets downloaded

When the snapshot is missing and the default hf-cli feature is on, the builder shells out to the CLI and takes the snapshot path from the last non-empty line of its output. The include patterns are *.json, *.safetensors, 1_Pooling/* and *_Dense/*, which is the smallest set the loader needs; ONNX exports, PyTorch .bin checkpoints, GGUF quantizations and OpenVINO directories are never fetched, and on a large repository those are most of the bytes.

hf download BAAI/bge-small-en-v1.5 --include "*.json" --include "*.safetensors" --include "1_Pooling/*" --include "*_Dense/*"

That is also the command the library prints when it cannot fetch for you. Without the hf-cli feature a missing model is CanddingError::ModelNotFound, whose message carries the exact invocation above, with --revision appended when you asked for something other than main. With the feature on but no hf binary on the path, CanddingError::HfCliMissing says to install it with pip install huggingface_hub or uv tool install huggingface_hub and then repeats the same command.

What the loader reads

FileRequiredWhat it decides
config.jsonyesmodel_type selects the family; pad_token_id sets the padding token, defaulting to zero
tokenizer.jsonyesthe tokenizer, replayed as published
model.safetensorsyes, or an indexthe weights, memory-mapped in the requested dtype
model.safetensors.index.jsonwhen the weights are shardedthe shard file names, deduplicated and loaded in name order
1_Pooling/config.jsonnopooling for a repository with no registry entry and no descriptor
modules.jsonnowhether such a repository normalizes, from its Normalize entry

A registry model, or one you pass a descriptor for, takes pooling, normalization, templates and dimension from the descriptor and ignores the two sentence-transformers files. Either way a missing config.json, tokenizer.json or weights file is CanddingError::MissingFile naming the path that was expected, before any tensor is touched.

Gated models

A gated repository needs its license accepted on huggingface.co and a token in place, either from hf auth login or from HF_TOKEN in the environment. When the CLI comes back with a 401 or a 403, candding maps it to CanddingError::GatedModel and says to accept the license and log in, because a retry cannot fix it. EmbeddingGemma is the first gated model on the roadmap, so nothing in today's catalog needs a token.

Local directories

Anywhere a model id is accepted, an existing directory path is accepted instead, and it is preferred: a spec that names a real directory is treated as a local model and the cache is never consulted. The directory needs config.json, tokenizer.json and safetensors weights, exactly what a snapshot holds, which makes a downloaded snapshot, a converted checkpoint and a fine-tune of your own interchangeable. A path that does not exist is not treated as a directory at all: ModelSource::parse only picks the local branch for an existing directory, so a typo falls through to the hub and surfaces as a failed download (HfCliFailed with the default hf-cli feature, ModelNotFound without it) rather than a missing-directory error.

On this page