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 of 2.0 means “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