# Shared Config Cluster Mode
## What It Is
Shared config mode lets multiple Superseedr nodes participate in one cluster by
pointing them at the same mounted shared root.
- Every node is a full Superseedr client.
- Every node can run torrents and seed.
- One node is the leader at any given time.
- The leader is the only node that consumes the shared inbox and writes
cluster-wide desired state.
- Non-leader nodes follow shared desired state and apply it locally.
Shared mode is enabled from the first available source in this order:
1. `SUPERSEEDR_SHARED_CONFIG_DIR`
2. persisted launcher shared-config sidecar
3. normal standalone mode
Host id is resolved from:
1. `SUPERSEEDR_SHARED_HOST_ID`
2. persisted launcher host-id sidecar
3. sanitized hostname fallback
This is mainly useful when:
- multiple machines share the same NAS or mounted volume
- installed browser or OS protocol launches do not inherit shell environment
- you want one shared torrent catalog with automatic leader failover
## Before You Start
Shared mode depends on a real writable shared root.
Before starting any node:
1. Create a dedicated shared folder on the mounted volume.
2. Mount that shared folder on every host.
3. Confirm every host can read and write inside it.
4. Start each client once so it can create its host-local shared files.
Use a dedicated folder inside the mounted volume, not the entire volume root.
Examples:
- Windows: `C:\Users\jagat\Documents\seedbox\test`
- macOS: `/Volumes/seedbox/test`
- Linux: `/mnt/shared-drive/test`
If the shared root is missing, unmounted, or not writable, runtime startup will
fail with a shared-root accessibility error.
## Quick Start
### 1. Pick a Shared Root
Choose one dedicated shared folder per cluster.
Example:
```text
/mnt/shared-drive/test
```
Superseedr stores its cluster files under:
```text
/mnt/shared-drive/test/superseedr-config/
```
Payload data still lives under the shared root itself, not under
`superseedr-config/`.
### 2. Configure Each Host
You can use environment variables:
```bash
export SUPERSEEDR_SHARED_CONFIG_DIR=/mnt/shared-drive/test
superseedr
```
Or persist launcher-side setup once per user account:
```bash
superseedr set-shared-config /mnt/shared-drive/test
superseedr show-shared-config
```
Then start the client normally:
```bash
superseedr
```
Repeat on every host with the same shared root.
### 3. Confirm the Cluster
After startup:
- one node should become leader
- other nodes should run as followers
- each host should have a `hosts/<host-id>/` folder under the shared config root
Useful checks:
```bash
superseedr show-shared-config
superseedr status
superseedr journal
superseedr torrents
```
### 4. Use the Cluster
Once running, use the CLI normally:
```bash
superseedr add /path/to/file.torrent
superseedr pause <INFO_HASH_HEX_OR_PATH>
superseedr resume <INFO_HASH_HEX_OR_PATH>
superseedr remove <INFO_HASH_HEX_OR_PATH>
superseedr purge <INFO_HASH_HEX_OR_PATH>
```
## Environment Variables
### `SUPERSEEDR_SHARED_CONFIG_DIR`
Absolute path to the shared mount root.
Superseedr automatically uses:
```text
<mount-root>/superseedr-config/
```
Example:
```bash
SUPERSEEDR_SHARED_CONFIG_DIR=/mnt/shared-drive/test
```
This has the highest precedence and overrides any persisted launcher config.
### `SUPERSEEDR_SHARED_HOST_ID`
Optional explicit host id for selecting:
```text
hosts/<host-id>/config.toml
```
If unset, Superseedr falls back to a sanitized hostname.
`SUPERSEEDR_HOST_ID` is still accepted as a legacy fallback, but
`SUPERSEEDR_SHARED_HOST_ID` is the canonical name.
Example:
```bash
SUPERSEEDR_SHARED_HOST_ID=seedbox-a
```
## Launcher Commands
These commands persist launcher-side shared mode without editing runtime
`settings.toml`:
```bash
superseedr set-shared-config /mnt/shared-drive/test
superseedr show-shared-config
superseedr clear-shared-config
superseedr set-host-id seedbox-a
superseedr show-host-id
superseedr clear-host-id
```
Rules:
- `set-shared-config` requires an absolute path
- the path may be either the mount root or an explicit `.../superseedr-config`
- Superseedr normalizes and stores the mount root in a launcher sidecar file
- `set-host-id` stores a sanitized host id in a separate launcher sidecar file
- `show-shared-config` reports the effective source and resolved paths
- `show-host-id` reports the effective host id and its source
- `clear-shared-config` disables persisted shared mode unless the env var is set
- `clear-host-id` removes the persisted host id unless the env var is set
## Conversion Commands
You can convert between standalone local config and layered shared config:
```bash
superseedr to-shared /mnt/shared-drive/test
superseedr to-standalone
```
Behavior:
- `to-shared` reads current standalone local config and writes layered shared files
- `to-standalone` reads the currently selected shared config and writes local standalone files
- neither command modifies launcher sidecars by itself
## Shared Root Layout
```text
/mnt/shared-drive/test/
superseedr-config/
settings.toml
catalog.toml
torrent_metadata.toml
cluster.revision
hosts/
seedbox-a/
config.toml
logs/
persistence/
status.json
desktop-a/
config.toml
logs/
persistence/
status.json
torrents/
inbox/
processed/
staged-adds/
status/
leader.json
superseedr.lock
downloads/
library/
```
Different hosts may mount the same shared root at different local paths.
Examples:
- Windows: `C:\Users\jagat\Documents\seedbox\test`
- macOS: `/Volumes/seedbox/test`
- Linux: `/mnt/shared-drive/test`
Each host should point `SUPERSEEDR_SHARED_CONFIG_DIR` or `set-shared-config` at
its own local mount path for the same shared root.
## Layered Files
### `settings.toml`
Cluster-wide shared settings.
Examples:
- shared `client_id` default
- RSS settings
- shared UI and performance settings
- shared default download folder
### `catalog.toml`
Cluster-wide desired torrent state.
Examples:
- torrent list
- pause and resume state
- remove and purge intent
- per-torrent download path
- per-torrent file priorities
All nodes read this file and converge local runtime to it.
### `torrent_metadata.toml`
Leader-written derived torrent metadata, including persisted file lists used by
commands like `files`, `info`, reverse path lookup, and offline purge.
### `hosts/<host-id>/config.toml`
Host-local runtime settings on the shared root.
This file is bootstrapped by runtime startup if it does not exist yet.
CLI shared loads also bootstrap this host file when shared cluster settings
already exist.
Common host-local fields:
- optional `client_id`
- `client_port`
- `watch_folder`
### `hosts/<host-id>/`
Host-local runtime artifacts on the shared root.
Examples:
- `hosts/<host-id>/logs/`
- `hosts/<host-id>/persistence/network_history.bin`
- `hosts/<host-id>/persistence/activity_history.bin`
- `hosts/<host-id>/persistence/rss.toml`
- `hosts/<host-id>/persistence/event_journal.toml`
- `hosts/<host-id>/status.json`
## Leadership
Shared mode still uses the file-lock mechanism.
- Leader: holds `superseedr.lock`
- Follower: does not hold the lock
- If a follower later acquires the lock, it promotes itself to leader without a restart
Leader responsibilities:
- consume `inbox/`
- write shared desired state
- write `settings.toml`, `catalog.toml`, and `torrent_metadata.toml`
- write `cluster.revision`
- update the current leader snapshot
Followers remain active torrent clients. They do not stop running torrents just
because they are not the leader.
## Cluster Convergence
The leader writes `cluster.revision` after shared desired-state changes.
Host-only changes do not bump `cluster.revision`.
Followers:
- watch shared state
- reload layered config when `cluster.revision` changes
- converge local runtime to the shared catalog
Convergence includes:
- starting newly added torrents
- pausing or resuming torrents
- applying file-priority changes
- applying download-path changes
- removing torrents deleted from shared desired state
### Remove vs Purge
`remove` and `purge` are cluster-wide.
- `remove` removes the torrent from desired state but keeps payload data
- `purge` removes the torrent and deletes payload data
## Watch Folder Model
Each host can still define its own local ingress folder:
```toml
client_port = 6681
watch_folder = "/srv/local-watch"
```
Behavior:
- leader watches its own local `watch_folder`
- leader also watches `inbox/`
- followers watch their own local `watch_folder`
- followers relay supported files into `inbox/`
- followers do not write shared desired state directly from local watch ingress
Supported dropped file types:
- `.torrent`
- `.magnet`
- `.path`
- `.control`
### Cross-Host Add Rules
This is the most important ingest rule in a multi-host cluster:
- magnet adds are naturally portable
- `.torrent` adds work across hosts when the torrent file is staged onto the shared root
- shared-mode `.path` adds are encoded relative to the shared root and resolved by the leader against its own local mount path
In practice:
- if you add a `.torrent` from a follower watch folder, Superseedr may stage it into `staged-adds/`
- if you add a path-based torrent source in shared mode, the follower resolves it and stages the actual torrent file for the leader
## Data Path Rules
Shared mode requires all payload data to live under the shared root.
Rules:
- shared-mode download paths must resolve inside the shared root
- shared-mode download paths are stored root-relative in layered config
- host-specific path translation is not supported
Examples:
- `default_download_folder = ""` resolves to the shared mount root itself
- `default_download_folder = "downloads"` resolves to `<mount-root>/downloads`
Example shared catalog entry:
```toml
[[torrents]]
name = "Shared Collection"
download_path = "library/shared-collection"
```
## CLI Behavior in Shared Mode
### Read Commands
Commands like these read shared state:
- `status`
- `journal`
- `torrents`
- `info`
- `files`
`status` in shared mode follows the current leader snapshot rather than a purely
local standalone-style node status view.
### Mutating Commands
Mutating commands include:
- `add`
- `pause`
- `resume`
- `remove`
- `purge`
- `priority`
Behavior:
- if a leader is running, shared mutating commands are queued through `inbox/`
- if no leader is running, offline-capable CLI commands mutate shared config directly using the offline path
That means shared CLI is not queue-only in all cases.
### `stop-client`
`stop-client` in shared mode targets the leader through the shared inbox.
Use it as a cluster-leader stop request, not a guaranteed “stop only this local
follower process” command.
## First-Run and Bootstrap Behavior
Runtime startup bootstraps shared host state.
CLI bootstrap behavior is intentionally narrower:
- in standalone mode, CLI can create first-run local settings when no local client is running
- in shared mode, CLI does not create an entirely new cluster from nothing
- in shared mode, if shared cluster settings already exist, CLI can bootstrap the current host's missing `hosts/<host-id>/config.toml`
Practical implications:
- start the client once on one host to establish the shared cluster files
- start the client once on each additional host if you want all host runtime folders to exist immediately
- if the shared root exists but shared `settings.toml` does not, CLI reports that the client has never started yet instead of silently creating a new cluster
## Status and Journal Semantics
### Status
Shared `status` is cluster-oriented and follows the leader snapshot. During
manual failover or failback, brief lag is expected while watches and snapshots
catch up.
### Journal
Shared journal output is merged:
- host-specific health/runtime events remain host-scoped
- shared command events are shared-scoped
This gives one combined operational view while preserving the difference between
host-local health and cluster-wide actions.
## Troubleshooting
### The shared root is missing or unmounted
Make sure:
- the mount exists on this host
- `SUPERSEEDR_SHARED_CONFIG_DIR` points to the mounted shared root
- the process can read and write that location
### A host cannot start in shared mode
Check:
- unique host id
- write access to `hosts/<host-id>/`
- write access to `hosts/<host-id>/config.toml`
- write access to `hosts/<host-id>/logs/`
### A cross-host add fails
Prefer:
- magnets
- `.torrent` files staged onto the shared root
Avoid relying on host-local absolute paths being valid on another OS.
## Example
Shared root:
```text
/srv/shared-drive/test/
superseedr-config/
settings.toml
catalog.toml
torrent_metadata.toml
cluster.revision
hosts/
seedbox-a/
config.toml
logs/
persistence/
status.json
desktop-a/
config.toml
logs/
persistence/
status.json
inbox/
processed/
staged-adds/
status/
leader.json
superseedr.lock
downloads/
```
Shared settings:
```toml
# settings.toml
client_id = "shared-node"
default_download_folder = "downloads"
global_upload_limit_bps = 8000000
```
Shared catalog:
```toml
# catalog.toml
[[torrents]]
name = "Shared Collection"
torrent_or_magnet = "shared:torrents/0123456789abcdef0123456789abcdef01234567.torrent"
download_path = "downloads/shared-collection"
```
Host config:
```toml
# hosts/seedbox-a/config.toml
client_port = 6681
watch_folder = "/srv/local-watch"
```
## Summary
- Shared mode is opt-in.
- Environment configuration overrides persisted launcher configuration.
- The leader is the single writer for cluster-wide desired state.
- Followers are still active torrent clients.
- Shared mode supports failover and failback.
- Shared payload data must live under the shared root.
- Shared CLI reads cluster state and queues leader mutations when a leader is available.