🧯 qbit-ops
🧯 A tiny qBittorrent CLI and TUI for people who don't want to nuke their seedbox by accident.
Inspect, diagnose and automate qBittorrent at scale - with composable filters, bulk operations, and dry-run safeguards.
✨ Featured in Self-Host Weekly by selfh.st.
🚀 Get started
Requires Python 3.12+ and a qBittorrent instance with the Web UI enabled.
Recommended, with uv:
uv tool install qbit-ops
Or with pipx:
pipx install qbit-ops
With the optional TUI:
uv tool install "qbit-ops[tui]"
pipx install "qbit-ops[tui]"
To upgrade later:
uv tool upgrade qbit-ops
pipx upgrade qbit-ops
Create ~/.config/qbit-ops/.env:
QBIT_HOST=http://localhost:8080
QBIT_USER=admin
QBIT_PASSWORD=change-me
Then:
qbit-ops status
qbit-ops doctor
qbit-ops tui
🔍 Inspect your instance
qbit-ops torrents list --category sonarr --state stalled
qbit-ops trackers status
qbit-ops explain torrent --hash abc123
qbit-ops status --watch
Read commands support machine-friendly output where it makes sense:
qbit-ops torrents list --format json
qbit-ops status --format jsonl
🎯 Target exactly what you mean
Filters compose - repeat one for or, mix different ones for and,
exclude with --exclude-*:
qbit-ops torrents list --ratio-min 2 --seeded-for 90d --exclude-tag keep
Category, tag, save path, name, state, size, ratio, progress, age, tracker and more - the same selector everywhere, listing or mutating. Full grammar in docs/COMMANDS.md.
🛠️ Make changes safely
Mutations are dry-run by default:
qbit-ops torrents pause --category sonarr
Review the plan, then apply it explicitly:
qbit-ops torrents pause --category sonarr --no-dry-run
🛡️ Safety by default
- 🧪 Dry-run first. Nothing changes unless
--no-dry-runis explicit. - 🎯 Hash-based targeting. Mutations never guess from a fuzzy torrent name.
- 🧊 Frozen plans. The previewed selection is the selection that gets applied.
- 🚫 No silent “all”. Bulk actions require a hash,
--all, or an explicit filter. - ❔ Unknown is never a match. A value qBittorrent didn't report never widens a selection.
- 🔒 Secret-safe output. Tracker passkeys and announce URLs stay redacted in normal output.
- ✅ Honest results. qbit-ops reports what was submitted or observed, not what it cannot prove.
🧭 How is qbit-ops different?
| qbit-ops | qbittorrent-cli | qbit_manage | qbittools | |
|---|---|---|---|---|
| Model | Safe operational toolkit | General-purpose qBittorrent CLI | Rules / background management | Task-oriented utilities |
| Interface | CLI + TUI | CLI | Config + scheduler + Web UI | CLI |
| Targeting | Composable selectors | Command / torrent specific | Rule / workflow specific | Command specific |
| Execution | SELECT → INSPECT → PLAN → APPLY | Direct qBittorrent operations | Apply configured rules | Run specialized commands |
| Safety | Dry-run-first, explicit apply | Command-dependent | Rule-driven automation | Command-dependent |
| Automation | Structured JSON + stable exit behavior | CLI / scripting | Scheduled workflows | CLI / scripting |
| Best fit | Safe bulk ops, inspection & scripting | General qBittorrent control from a terminal | Continuous library management | Specialized maintenance tasks |
qbit-opsis deliberately not a daemon or background rules engine: select precisely, inspect the scope, preview the plan, then apply it.
See PHILOSOPHY.md for the reasoning behind that design.
🖥️ TUI
The optional Textual interface provides a branded overview, torrent browsing, filters, details, explanations, and previewed low-risk bulk actions.
qbit-ops tui
| Overview | Torrents |
|---|---|
| Search | Preview before Apply |
|---|---|
Press ? inside the TUI to see the available controls.
🧩 Compatibility
Container integration is tested against these exact qBittorrent releases:
| qBittorrent | Web API |
|---|---|
| 4.6.7 | 2.9.3 |
| 5.0.0 | 2.11.2 |
| 5.1.4 | 2.11.4 |
| 5.2.3 | 2.15.1 |
This is evidence for those exact versions, not a claim for the whole 4.6–5.2 range. Run qbit-ops doctor to compare your instance with the packaged evidence.
🧰 Commands
qbit-ops --help
qbit-ops --version
qbit-ops version
qbit-ops torrents --help
qbit-ops trackers --help
A compact command overview is available in docs/COMMANDS.md.
🗺️ Roadmap
See ROADMAP.md for where the project is heading.
🧑💻 Development
git clone https://github.com/LECOQQ/qbit-ops.git
cd qbit-ops
make install
make check-fast
make check
See CONTRIBUTING.md.
📄 License
MIT - see LICENSE.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file qbit_ops-0.4.0.tar.gz.
File metadata
- Download URL: qbit_ops-0.4.0.tar.gz
- Upload date:
- Size: 177.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4ffd3bd3a6e9c952c6a0a3ecc773e70368e9c1a88e94144b95b2e3d7fccc1472
|
|
| MD5 |
cb04863b99f8729370fec549d3e5876c
|
|
| BLAKE2b-256 |
b722d095b670bc36c0dfb78011b738e7a0d4b418b815629e4690c4d7d25d83bb
|
Provenance
The following attestation bundles were made for qbit_ops-0.4.0.tar.gz:
Publisher:
publish.yml on LECOQQ/qbit-ops
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
qbit_ops-0.4.0.tar.gz -
Subject digest:
4ffd3bd3a6e9c952c6a0a3ecc773e70368e9c1a88e94144b95b2e3d7fccc1472 - Sigstore transparency entry: 2455032567
- Sigstore integration time:
-
Permalink:
LECOQQ/qbit-ops@8fbb04cecf49009ddf452ee69999478349b69c01 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/LECOQQ
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@8fbb04cecf49009ddf452ee69999478349b69c01 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file qbit_ops-0.4.0-py3-none-any.whl.
File metadata
- Download URL: qbit_ops-0.4.0-py3-none-any.whl
- Upload date:
- Size: 211.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8b020b23e798b387b163378b5f9401f726be440339f026a468a0ca169d166f8b
|
|
| MD5 |
2552a3038803061a9313b49626ad102f
|
|
| BLAKE2b-256 |
39f3041036efe423f154f02d5a7eb0363cb2cc7c2af6dbc0a252b60d654822dc
|
Provenance
The following attestation bundles were made for qbit_ops-0.4.0-py3-none-any.whl:
Publisher:
publish.yml on LECOQQ/qbit-ops
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
qbit_ops-0.4.0-py3-none-any.whl -
Subject digest:
8b020b23e798b387b163378b5f9401f726be440339f026a468a0ca169d166f8b - Sigstore transparency entry: 2455034127
- Sigstore integration time:
-
Permalink:
LECOQQ/qbit-ops@8fbb04cecf49009ddf452ee69999478349b69c01 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/LECOQQ
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@8fbb04cecf49009ddf452ee69999478349b69c01 -
Trigger Event:
workflow_dispatch
-
Statement type: