Downloads that finish.
Bit Rebuttal is a resilient downloader for huge AI model files, for people who pull multi-gigabyte models from HuggingFace and want to start a download, walk away, reboot the machine, and still find it finished and hash-verified. It wraps aria2c under a supervision layer that survives stalls, expired signed URLs, process death, and full reboots. It runs on Windows, macOS, and Linux from the same codebase.
Three failure modes kill long downloads:
- Signed CDN URL expiry. HuggingFace URLs redirect to CDN links whose signatures die in 1-3 hours. A downloader that retries the redirected URL hammers a dead signature forever. Bit Rebuttal restarts with the original URL, which re-resolves and issues a fresh signed redirect.
- Silent stalls. Connections stay open, throughput goes to zero, nothing errors. Bit Rebuttal's watchdog polls aria2's aggregate throughput and kills and relaunches aria2c when it stalls.
- Host reboot / process death. Progress is lost, or the download simply never restarts. Bit Rebuttal runs as an OS service (systemd on Linux, Task Scheduler on Windows) that resumes byte-exact from aria2's
.aria2control files with no user action.
The design is not theoretical: the prototype that proved it downloaded 169.17 GB over ~3 days with 13 unattended recoveries, 0 manual interventions, and 0 bytes lost.
Three layers, each catching what the one below it misses. The outermost layer is an OS service: it keeps the whole thing alive across crashes and reboots, and on startup it finds unfinished jobs and resumes them automatically. Inside it, the supervisor owns exactly one aria2c child process and makes every restart decision. A watchdog polls aria2's RPC every 60 seconds and watches aggregate throughput, never per-connection speed. If the aggregate stays below an adaptive threshold (a fraction of the trailing median, floored at 10 KB/s) for 12 consecutive polls, the watchdog kills aria2c and the supervisor relaunches it. The watchdog also detects when the queue has drained, because aria2 in RPC mode never exits on its own. When aria2c exits for any reason, the supervisor verifies what finished, waits 15 seconds, and relaunches it with the original URLs so signed CDNs re-resolve fresh. That restart-to-re-resolve is why repeated restarts cost zero progress. aria2c itself does the transfer work: multiple connections per file, infinite retries, and .aria2 control files that make every resume byte-exact. When every file is done, Bit Rebuttal checks size and SHA256 before the job is marked complete.
Grab the binary for your OS from the GitHub releases page. No installer:
- Windows: run
BitRebuttal-windows-x64.exe— it opens its own app window (WebView2, preinstalled on Windows 11; on Windows 10 install the "WebView2 Runtime" from Microsoft if the window fails). - macOS: unzip
BitRebuttal-macos-*.zip, then right-click the app and choose Open on first run — the app is unsigned, so Gatekeeper asks the first time. - Linux:
chmod +xthe binary and run it.
The -cli binaries (BitRebuttal-cli-*) are the full console CLI. bitrebuttal serve (or the CLI's serve) still gives the plain browser UI.
The Windows and macOS apps ship with aria2c bundled (v1.1.0+) — nothing else to install. The Linux binary still needs aria2c on your PATH: sudo apt install aria2. (aria2 is GPLv2 with the OpenSSL linking exception; its license ships inside the bundles as aria2-COPYING.)
Requirements:
- Python 3.10+
aria2con your PATH:- Windows:
winget install aria2 - macOS:
brew install aria2 - Linux:
sudo apt install aria2
- Windows:
Then from a clone of this repository:
pip install .
Use the console binary for terminal commands: BitRebuttal-cli-windows-x64.exe add <url>, BitRebuttal-cli-macos-arm64 status, or BitRebuttal-linux-x64 status. Apple Silicon Macs (M1 through M4 and later) use the macOS arm64 download; Intel Macs use x64.
Start the local web UI:
bitrebuttal serve
Then open http://127.0.0.1:7451. Paste a HuggingFace repo link or any direct URL, pick the files you want, and watch live progress.
Add a job and check on it from the command line:
bitrebuttal add <url>
bitrebuttal status
Install the OS service so downloads survive reboots and start-on-boot:
bitrebuttal service install
Every file is checked against its manifest before a job is marked complete. Size is always checked, and when the source publishes a hash (HuggingFace does for LFS files), the SHA256 is checked too, streamed over the whole file.
A mismatch is not a warning: the file is marked CORRUPT and the job FAILED, loudly, in the UI and the exit code. Bit Rebuttal never deletes, never skips-and-continues, and never silently reports a bad file as done.
Rules inherited from the prototype:
- Never treat per-connection speed as a health signal. A slow-but-alive link must not cause connections to be killed or shards to be abandoned.
- Stall detection runs only on aggregate throughput from aria2's global stats, never per-file, never file size on disk.
- Every restart re-requests the original URL so signed CDNs re-resolve with a fresh redirect. Never retry a cached redirect.
- Pause means stopping the supervisor and aria2c cleanly so control files flush. Never use aria2's RPC pause while the watchdog is running.
- Fail loudly, never skip. A file that can't complete or verify marks the whole job FAILED.
The release workflow tests the actual packaged GUI executable on Windows and macOS (in headless server mode), plus the console builds on all three platforms. Each check downloads a 24 MiB local fixture, pauses until the transfer stops and its control file settles, resumes with a nonzero HTTP range, and verifies the final SHA256. A separate small HTTPS download checks the engine's certificate configuration. This does not replace a native window test or a long download on a physical Mac.
On macOS, the bundle includes OpenSSL's dynamically loaded legacy provider and uses bundled CA certificates. CI temporarily hides Homebrew's provider directory so the builder cannot silently supply a dependency missing from the app.
Run a local candidate check with:
python packaging/smoke_download.py /path/to/BitRebuttal --httpsFor a macOS app, point it at BitRebuttal.app/Contents/MacOS/BitRebuttal.
The script uses a fresh temporary data directory and prints its evidence path.
Manual release workflow runs upload candidate artifacts without creating a release.
If the event log says aria2 failed to start, newer builds include the engine's
underlying error in that event. Its ordinary log is aria2.log in the data folder:
~/Library/Application Support/bitrebuttal on macOS,
%LOCALAPPDATA%\bitrebuttal on Windows, or ~/.local/share/bitrebuttal on Linux.
Errors before aria2 initializes its file logger may appear only in the job event.
MIT