The first half of the llama.cpp work Bryan asked for: browse HuggingFace,
fetch a model, and see how far it has got from any device.
The design is dev-updater's build-progress shape with the four changes its
author recommended after living with it, since a model download is an hour
where a build is two minutes:
- **A run has an id.** Without one "not downloading" means three different
things -- finished, never started, or someone else's run ended while you
were away -- and over an hour that ambiguity is certain rather than
theoretical. A device compares the run it was watching to the run
reported now.
- **Outcomes outlive their run**, so a phone that was asleep at the moment
of completion can still find out what happened.
- **Cancel exists.** Retrofitting cancellation into a blocking loop is
miserable, and several gigabytes over someone's data plan is not
something to have no answer for.
- **Progress is bytes, not a parsed marker.** We own the loop, so it counts
directly; `total` is whatever Content-Length said and nothing else, and
stays absent when the server sends none rather than becoming a bar drawn
from a guess.
The download owns its own thread rather than the blocking pool, which
exists for short work. It resumes through HTTP Range, and trusts the 206
rather than the request -- a server that ignores Range answers 200 with the
whole file, and appending to that would corrupt it. `truncate(false)` on
the open is load-bearing for the same reason and says so.
Searching is proxied through the server rather than done from the phone,
because the app trusts exactly one certificate -- this one -- and the
machine that must do the downloading is also the one whose view of what
exists matters.
Verified against the real HuggingFace, not a mock: searched, listed a
repository's GGUFs, downloaded 234 MB with live byte progress, cancelled
mid-flight, confirmed the partial survived, restarted and watched it resume
at 162 MB rather than 0, and let it finish. The result's sha256 matches the
one HuggingFace publishes for that file, so the resume is byte-correct and
not merely the right length. llama.cpp then loaded it and ran inference.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017xn8nHw1tw1R6PtiY1eEtw