Download GGUF models from HuggingFace Hub.
Requires the optional req dependency. Add it to your mix.exs:
{:req, "~> 0.5"}Examples
# Search for GGUF models
{:ok, results} = LlamaCppEx.Hub.search("qwen3 gguf", limit: 5)
# List GGUF files in a repository
{:ok, files} = LlamaCppEx.Hub.list_gguf_files("Qwen/Qwen3-4B-GGUF")
# Download a model (cached locally)
{:ok, path} = LlamaCppEx.Hub.download(
"Qwen/Qwen3-4B-GGUF",
"qwen3-4b-q4_k_m.gguf"
)Authentication
For private or gated repositories, set the HF_TOKEN environment variable
or pass the :token option:
LlamaCppEx.Hub.download("org/private-model", "model.gguf", token: "hf_...")Caching
Downloaded files are cached in ~/.cache/llama_cpp_ex/models/ by default.
Override with the :cache_dir option or LLAMA_CACHE_DIR environment variable.
The cache directory is created with mode 0o700 and cached files with 0o600
— gated-repository content is credential-adjacent.
A cached file is returned as-is: download/3 makes no request to the Hub
when the file is already present. The upstream ETag is recorded in a
<file>.etag sidecar, but nothing reads it back yet, so a file that changed
upstream is not detected — pass force: true to refresh it.
Integrity
A fresh download is verified against the SHA-256 that HuggingFace publishes for
the file, and a file whose digest does not match is deleted rather than cached.
See download/3 for the limits of that guarantee.
Offline Mode
Set LLAMA_OFFLINE=1 to use only cached files without network access.
Proxies
Requests honor the standard proxy environment variables automatically:
HTTPS_PROXY/HTTP_PROXY (and their lowercase forms), falling back to
ALL_PROXY, with NO_PROXY respected for host bypass. Because HuggingFace is
served over HTTPS, the HTTPS_PROXY value is the one that applies; an HTTP
proxy tunnels HTTPS via the CONNECT method.
# honored automatically
export HTTPS_PROXY=http://127.0.0.1:8118Override or disable proxying per call with the :proxy (a URL string, a Mint
{scheme, address, port, opts} tuple, or false) and :no_proxy options:
LlamaCppEx.Hub.search("qwen3 gguf", proxy: "http://user:pass@127.0.0.1:8118")
LlamaCppEx.Hub.download("org/model", "model.gguf", proxy: false)SOCKS is not supported
The underlying HTTP client (Req → Finch → Mint) supports HTTP/1 proxies only —
plain forwarding and HTTPS-over-CONNECT tunneling. It has no SOCKS
support, so a socks5:// value (e.g. from ALL_PROXY) is ignored with a
warning. To use a SOCKS upstream, run a local HTTP-to-SOCKS bridge such as
Privoxy or gost
and point HTTPS_PROXY at the bridge's HTTP port.
Summary
Functions
Build authentication headers from options or environment.
Build the download URL for a file in a HuggingFace repository.
Build the local cache path for a model file.
Download a GGUF file from HuggingFace Hub, returning the local path.
Filter a list of HuggingFace siblings entries to only GGUF files.
Get model repository metadata from HuggingFace Hub API.
List GGUF files available in a HuggingFace repository.
Search HuggingFace Hub for GGUF models.
Functions
Build authentication headers from options or environment.
Checks for tokens in order: :token option, HF_TOKEN env var,
HUGGING_FACE_HUB_TOKEN env var (legacy).
Build the download URL for a file in a HuggingFace repository.
Build the local cache path for a model file.
The path is <cache_dir>/<repo_id>/<revision>/<filename>. revision is part of
the key because otherwise pinning revision: "<sha>" returned whatever had been
cached for main — the pin bought nothing, silently. It defaults to "main".
All three components are caller-supplied and become path components, so each is
validated first: one that is absolute, empty, ".", "..", ~-prefixed, or
contains a null byte would escape the cache and is rejected with an
ArgumentError. download/3 performs the same validation but surfaces it as
{:error, reason}.
Download a GGUF file from HuggingFace Hub, returning the local path.
An already-cached file is returned immediately, without contacting the Hub.
There is no upstream revalidation — the ETag written to the <file>.etag
sidecar is never read back — so pass force: true to refresh a cached file.
The cache key includes :revision, so two revisions of the same file cache
separately.
A fresh download is streamed into a randomly named temporary file opened with
O_EXCL, verified against the SHA-256 HuggingFace publishes for the file, and
only then renamed into place with mode 0o600. A missing published digest is a
failure, not a warning — see :verify_checksum.
Integrity is not authenticity
The digest comes from the same origin as the bytes, so it detects corruption
or tampering between HuggingFace and you — not a malicious file published by
the repository owner. GGUF parsing happens in C++, so for repositories you do
not trust, also pass check_tensors: true to LlamaCppEx.Model.load/2.
Options
:cache_dir- Local cache directory. Defaults to~/.cache/llama_cpp_ex/models/or theLLAMA_CACHE_DIRenvironment variable.:token- HuggingFace API token. Defaults toHF_TOKENenvironment variable.:revision- Git revision (branch, tag, or commit). Defaults to"main". Part of the cache key.:force- Force re-download even if cached. Defaults tofalse.:verify_checksum- Integrity policy. Defaults totrue.true— fail closed. The download is checked against the SHA-256 HuggingFace publishes, and a file the Hub lists without one is refused. Verification used to be downgradable by the metadata response itself: it fell back to a warning whensiblings[].lfs.sha256was absent, so stripping one JSON key was enough to have the bytes cached unverified.:best_effort— warn and proceed when the Hub publishes no digest. For the rare non-LFS blob that is genuinely small enough to have none.false— skip the check and the metadata request entirely. Logged as a warning.
:proxy,:no_proxy- Proxy overrides. See the "Proxies" section above.
Filter a list of HuggingFace siblings entries to only GGUF files.
Returns maps with :filename and :size.
Get model repository metadata from HuggingFace Hub API.
Options
:token- HuggingFace API token.
@spec list_gguf_files( String.t(), keyword() ) :: {:ok, [%{filename: String.t(), size: integer()}]} | {:error, String.t()}
List GGUF files available in a HuggingFace repository.
Returns a list of maps with :filename and :size (bytes).
Options
:token- HuggingFace API token.
Examples
{:ok, files} = LlamaCppEx.Hub.list_gguf_files("Qwen/Qwen3-4B-GGUF")
Enum.each(files, fn f ->
size_mb = Float.round(f.size / 1_000_000, 1)
IO.puts("#{f.filename} (#{size_mb} MB)")
end)
Search HuggingFace Hub for GGUF models.
Returns a list of model info maps with :id, :downloads, :likes,
:last_modified, and :tags.
Options
:limit- Maximum results. Defaults to10.:sort- Sort by"downloads","likes", or"lastModified". Defaults to"downloads".:direction- Sort direction,-1for descending. Defaults to-1.:token- HuggingFace API token.:proxy,:no_proxy- Proxy overrides. See the "Proxies" section above.
Examples
{:ok, models} = LlamaCppEx.Hub.search("llama gguf q4")
Enum.each(models, fn m -> IO.puts("#{m.id} (#{m.downloads} downloads)") end)