Seed Limits
Auto-pause torrents once they hit a ratio or seed-time target. Global defaults plus per-torrent overrides.
Seed limits stop torrents from seeding forever. Set a global default in Settings → Seeding; override it per-torrent from the inspector. A background ticker checks every 30 seconds and pauses any completed torrent that has exceeded its effective limit.
Global defaults
Settings → Seeding holds two independent stop conditions, either or both of which can be enabled:
- Ratio limit — pause when
bytes_uploaded / bytes_done ≥ value. A ratio of2.0means “seed back twice what you downloaded, then stop.” - Time limit — pause after the torrent has been seeding for N minutes. Counted from the first tick that observed the torrent as completed-and-unpaused, not from when the torrent originally finished.
Either limit being unset means “no global limit on that axis.” With neither set, the engine seeds completed torrents indefinitely (BitTorrent’s normal behavior).
// SeedingDefaultsDTO — nil means no limit on that axis
{ "ratio_limit": 2.0, "time_min_limit": 4320 } // 2.0 ratio OR 3 days seeding
{ "ratio_limit": null, "time_min_limit": 1440 } // 24 hours seeding, no ratio cap
{ "ratio_limit": null, "time_min_limit": null } // no global limits
Per-torrent override
The Overview tab on a completed torrent shows a Seeding limits section with three radio modes:
| Mode | What it does |
|---|---|
| Use global | Falls back to the Settings → Seeding defaults. The starting state. |
| No limit | Seed this one forever, even if the global defaults would have stopped it. |
| Custom | Set per-torrent ratio_limit and/or time_min_limit. Either can be left off. |
The override is per-torrent and persisted to the seed_policy column of the torrents table as a small JSON blob. Clearing the override (radio back to Use global) deletes the row’s JSON so the torrent reverts to defaults — there’s no leftover “no-limit” state.
What happens at the limit
When the 30-second ticker sees a completed, unpaused torrent that exceeded its effective limit (per-torrent override beats global default), it calls the same Pause the UI’s pause button uses. The torrent goes paused; the swarm sees the connections drop; the row in the SPA picks up the paused state on the next torrents:tick. The data on disk is untouched — resuming the torrent will start seeding again from where it left off.
Mosaic does not currently surface a “limit reached” notification or an audit trail of which torrents were auto-paused; check the journald/zerolog output for seed policy: paused torrent — limit reached log lines if you need to know.
Ratio math gotcha
The ratio is computed against bytes_done, not total_bytes. For a partial-completion torrent (one where the user marked some files skip), bytes_done is the size of the selected files, so a ratio of 2.0 on a half-selected torrent means “upload twice the size of the selected files,” which usually arrives faster than you’d expect from a glance at the total size.
API
GET /api/settings/seeding_defaults → SeedingDefaultsDTO
PUT /api/settings/seeding_defaults body: SeedingDefaultsDTO
GET /api/torrents/{infohash}/seed_policy → SeedPolicyDTO
PUT /api/torrents/{infohash}/seed_policy body: SeedPolicyDTO
SeedPolicyDTO.use_global = true resets the override; use_global = false with both fields null is the explicit “no limit, ignore globals” state.
See REST Endpoints → Settings: seeding.
See also
- Scheduling — orthogonal: schedule rules cap bandwidth during a window, seed limits stop the torrent entirely
- Per-torrent rate limits — cap seeding speed without stopping the torrent