Storage backends
Repo pool & rotation
A single repository on any platform fills up. zcrypt sidesteps that by treating your storage as a pool of repositories that grows on demand, so your usable space climbs transparently while you just keep uploading.
Why a pool
Every backend caps how much one repository can comfortably hold: about 850 MB on GitHub, 9 GB on GitLab, 90 GiB on a Hugging Face dataset. If a vault were tied to one repo, that cap would be your ceiling. Instead, zcrypt keeps a pool of repositories per account and adds to it as needed.
The pool is scoped to a unique combination of (you, platform, account). Connect two GitHub accounts and each gets its own independent pool; they never share or contend.
How rotation works
At any moment, each pool has exactly one active repo that new chunks go to. The cycle is simple:
- zcrypt uploads chunks to the active repo.
- Before each upload it checks the active repo's tracked usage against the platform threshold.
- When the active repo reaches its threshold, zcrypt deactivates it and auto-creates a new repository to become the active one.
- New chunks flow into the new repo; the cycle repeats.
New repositories are created private and given a plausible, developer-looking name such as fast-cache-v3 or core-worker-v7, with a description like "Internal build artifacts and cache storage." Nothing in the repo hints that it belongs to an encrypted drive. On Telegram, which has no repos, the same logic spreads files across virtual storage locations in your channel instead.
Old repos stay readable
Deactivating a full repo only stops new writes to it. Its chunks are still tracked and downloaded normally, so files you stored months ago keep working as the pool grows around them.Per-platform thresholds
Thresholds are deliberately conservative, sitting under each platform's real limits so uploads never bump into a hard wall mid-transfer.
| Platform | Rotation threshold |
|---|---|
| GitHub | ~850 MB per repo |
| GitLab | ~9 GB per repo |
| Hugging Face | ~90 GiB per repo (Git LFS) |
| Telegram | Virtual: spreads files across the channel |
Hugging Face doesn't grow by rotating
Hugging Face's free tier is 100 GB for the entire account, not per repo, so spinning up another Hugging Face repo adds no real space. The per-repo threshold is kept under that account-wide ceiling, and when zcrypt picks a backend automatically it prefers Telegram (no ceiling) and lists Hugging Face last. To grow Hugging Face capacity, connect another account.Push throttling
Some platforms limit how fast you can push, not just how much you can store. GitHub, for instance, throttles sustained pushes at roughly 7 GB per hour. To avoid tripping that ceiling mid-transfer, zcrypt paces its own writes to each platform rather than hammering the API and getting rate-limited.
Before sending each chunk, the background sync worker checks a per-platform budget over a trailing one-hour window. If pushing the chunk would exceed the limit, the worker holds it just long enough for earlier bytes to age out of the window, then sends, so short bursts go straight through and only sustained, over-cap volume is slowed.
- •Only GitHub is throttled by default (~7 GB/hour); Telegram, GitLab, and Hugging Face are not rate-limited by zcrypt.
- •Budgets are tracked per platform, so saturating GitHub never slows a push to GitLab or Telegram.
- •The wait happens before a chunk claims a repo upload slot, so a throttled push never holds a slot idle or blocks other repos from making progress.
Usage tracking
zcrypt records the encrypted bytes written to each repo as uploads complete, so the "is this repo full?" check is a fast database lookup rather than a live API call on every chunk. Usage is tracked per repo, which is what lets a pool know precisely when to rotate and lets your total capacity add up across all of them.
Resume & chunk cleanup
Server-side resume
Chunks are staged on the server and pushed to your backend by a background worker, so a transfer doesn't depend on your browser staying open for every byte. If the server restarts, the worker re-drains any chunks still waiting and finishes pushing them.
Resume is server-authoritative. zcrypt keys each upload to (you, the file's hash, its size), so restarting the same file: even from another device or after clearing local storage, hands back the original session instead of starting over. Chunks already pushed aren't re-sent or orphaned, and the transfer continues on the same platform it began on.
Cleaning chunks off the platform
Deleting a file (or cancelling an upload) queues its chunks for removal from the backend. A deletion worker drains that queue and calls each platform's delete API to erase the encrypted blobs; chunks that were staged but never pushed are simply removed from the server's staging area.
Failed deletions are retried with backoff. If a chunk still can't be removed after repeated attempts it's flagged in the logs as an orphan needing manual cleanup, rather than being silently forgotten, and a startup sweep clears staging files whose database rows are gone.