IronTide — a BitTorrent client in Rust: native Slint desktop GUI, web UI, CLI/daemon, and a qBittorrent-compatible API for the *arr ecosystem. Built on the irontide engine.
Find a file
Alan Gaudet de4e356853
Some checks are pending
CI / Test & Clippy (push) Waiting to run
docs: state §8's next milestone in the form the loop reads
The bold '**Next milestone**' heading sat above a numbered list, so the parser
read the list ordinal 2 as the milestone tag — a milestone that does not exist.
The client roadmap is complete, so state that instead.

milestone-cycle v1.12.0 writes one canonical marker and re-parses it before
committing, so this file is now round-trip clean against the loop's own parser.
2026-07-25 13:49:42 -04:00
.github/workflows ci: install Rust 1.97.0 to match rust-toolchain.toml 2026-07-25 03:09:12 -04:00
benchmarks chore: pin Rust 1.97.0 and record the 1.7.0 real-world campaign 2026-07-18 20:55:31 -04:00
crates chore: pin Rust 1.97.0 and record the 1.7.0 real-world campaign 2026-07-18 20:55:31 -04:00
data chore(packaging): import desktop packaging + data from the engine repo — PNG-only icons 2026-06-11 20:05:35 -04:00
docs docs: state §8's next milestone in the form the loop reads 2026-07-25 13:49:42 -04:00
packaging docs: correct stale GTK3 build prerequisites (dropped at M41 for ksni) 2026-06-29 13:56:49 -04:00
.gitignore M24 — Portable builds + Linux packaging (audit & revive) (#26) 2026-06-15 01:24:09 -04:00
AGENTS.md docs: make AGENTS.md the real context file, symlink CLAUDE.md and GEMINI.md 2026-07-25 03:09:12 -04:00
Cargo.lock chore(deps): adopt engine 1.7.0 — all 17 crates --precise (Phase V release publish, engine M291); refresh parallel7 fixture to current ISOs (2026-07-18) 2026-07-18 16:12:06 -04:00
Cargo.toml chore(deps): adopt engine 1.7.0 — all 17 crates --precise (Phase V release publish, engine M291); refresh parallel7 fixture to current ISOs (2026-07-18) 2026-07-18 16:12:06 -04:00
CHANGELOG.md chore: pin Rust 1.97.0 and record the 1.7.0 real-world campaign 2026-07-18 20:55:31 -04:00
CLAUDE.md docs: make AGENTS.md the real context file, symlink CLAUDE.md and GEMINI.md 2026-07-25 03:09:12 -04:00
GEMINI.md docs: make AGENTS.md the real context file, symlink CLAUDE.md and GEMINI.md 2026-07-25 03:09:12 -04:00
LICENSE Add GPL-3.0 license 2026-02-27 08:39:43 -05:00
README.md docs: rewrite README in plain language 2026-07-13 13:40:04 -04:00
ROADMAP.md docs: author Phase 9 — poll-loop optimization (M59–M63 → 1.2.2) 2026-07-13 13:40:04 -04:00
rust-toolchain.toml chore: pin Rust 1.97.0 and record the 1.7.0 real-world campaign 2026-07-18 20:55:31 -04:00

IronTide

CI License Rust engine: irontide

A BitTorrent client with three front ends over one engine: a desktop app, a browser interface, and a command-line tool that can also run headless as a daemon.

The engine underneath it, irontide, is a separate project published to crates.io. This repository is the client — the windows, the web server, the CLI, and the code that turns engine state into something you can act on. The two began as one codebase and were later split, so the client now depends on the released engine like any other crate; there is no local link back to its source.

Linux is the platform that ships as packages and gets daily use. The packaging tree carries Windows and macOS build scripts too, but there are no prebuilt downloads for those yet — you build them on the host in question.

The client is five crates:

Crate Role
irontide-gui Slint desktop app — the main way in
irontide-cli the irontide command-line tool and its daemon
irontide-api qBittorrent-v2-compatible REST API and web UI
irontide-config the TOML/env/CLI configuration pipeline
irontide-webui-assets the web UI's static assets (HTMX + Pico CSS)

Table of Contents

Features

Desktop app

  • Add torrents from a .torrent file, a magnet link, or a URL. Pause, resume, recheck, or remove them, and move them up, down, or to either end of the queue.
  • A torrent list whose columns you can sort, show, hide, reorder, and resize: name, size, progress, status, seeds and peers, up and down rates, ratio, ETA, category, tags, save path, info hash, and more.
  • Sidebar filters by status, category, tag, or tracker, each with a live count.
  • Categories (one per torrent, and they can set a default save path) and tags (as many as you like) for keeping things organized.
  • A detail pane for the selected torrent: transfer stats, the file list with per-file priorities and a piece map, the trackers, and the peers — with country flags and per-peer bans.
  • Preferences covering behaviour, connection, bandwidth, downloads, the web UI, RSS, dynamic DNS, and peer-country lookup (bring your own MaxMind database).
  • Odds and ends: an RSS reader that can auto-download, a bandwidth scheduler, an IP filter and ban list, a command palette on Ctrl+K, statistics and log views, and a first-run wizard.
  • A browse button on every folder field, and .torrent export from the File menu.

Web UI and qBittorrent API

  • A web dashboard (HTMX and Pico CSS) that mirrors the desktop app, for running IronTide headless or reaching it from another machine.
  • A qBittorrent v2-compatible API, so Sonarr, Radarr, Lidarr, and anything else that already talks to qBittorrent can use IronTide without noticing the swap.
  • A first-party REST API and a WebSocket event stream for building against directly.
  • Argon2 password hashing, brute-force lockout, CSRF protection, and optional HTTPS with your own certificate and key.

Command line and daemon

irontide daemon                  # run the API host + web UI (default port 9080)
irontide download <magnet|file>  # download once, then exit (--seed keeps seeding)
irontide create <path>           # build a .torrent file
irontide add|list|info|pause|resume|rm <…>   # drive a running daemon
irontide shell                   # interactive prompt
irontide tui                     # full-screen dashboard
irontide --help                  # the rest

Point the CLI at a daemon on another host by setting IRONTIDE_API_URL.

What the engine does

The heavy lifting happens in irontide: BitTorrent v1, v2, and hybrid torrents; peer discovery over DHT, peer exchange, and local service discovery; magnet metadata exchange; web seeds; TCP and uTP; MSE/PE encryption; per-torrent and global rate limits; peer caps; and fast resume. The engine repository has the protocol details.

Install

The full per-platform walkthrough — source builds, packaged downloads, running each surface, config locations, and how to send feedback — is in docs/INSTALL.md. The short version for Linux:

Build CPU-generic (x86-64-v2) packages with the bundled script:

./packaging/build-linux.sh all    # → dist/  (AppImage + .deb; .rpm on an rpm host)

Then pick whatever suits the machine:

# Debian / Ubuntu
sudo apt install ./dist/irontide_*_amd64.deb

# Any distro, nothing installed
chmod +x dist/IronTide-*-x86_64.AppImage
./dist/IronTide-*-x86_64.AppImage

# From source into a prefix you own (no sudo for ~/.local)
cargo build --release -p irontide-cli -p irontide-gui
./packaging/install.sh --prefix="$HOME/.local"

Windows (.msi / portable zip) and macOS (.app / DMG / Homebrew) build on their own host OS — the GUI links native windowing and font libraries (Slint and winit), which rules out cross-compiling from Linux. See packaging/README.md and the scripts under packaging/windows/ and packaging/macos/.

Usage

Three ways to run it — pick one:

irontide-gui        # the desktop app
irontide daemon     # the API host; open the address it prints in a browser
irontide --help     # the full command reference

Running the daemon or web UI for an *arr setup? Point the other app (or any qBittorrent client) at the host's /api/v2/ endpoint.

Configuration

Settings are merged from four places, each overriding the one before it: built-in defaults, then the TOML file, then IRONTIDE_* environment variables, then CLI flags. The file lives at $XDG_CONFIG_HOME/irontide/config.toml (usually ~/.config/irontide/config.toml), or wherever --config points.

[session]
download_dir = "~/Downloads"
listen_port  = 42020
enable_dht   = true

[api]
bind = "127.0.0.1"
port = 9080                 # 0 turns the HTTP API off

[limits]
max_download_rate_bps = 0   # 0 means unlimited
max_peers_per_torrent = 100

[gui]
density = "compact"

The file exposes a curated slice of the engine's settings under [session], [api], [limits], and [gui], plus watched folders, RSS, dynamic DNS, and web UI TLS. irontide config init writes a documented default file; config path, config show, and config validate cover the rest.

Design

The GUI follows one settled look, Tidemark (v1.1): dark, dense, and KDE-native, keyed to the app icon's tide-blue and iron-navy, with the data columns set in a monospaced face so figures line up. The specification is in docs/design/DESIGN.md (the GUI) and docs/design/DESIGN-SYSTEM.md (tokens, components, and motion).

Building from source

cargo build --workspace
cargo test --workspace
cargo clippy --workspace --all-targets -- -D warnings   # zero warnings

The GUI needs Slint's system libraries — fontconfig, xkbcommon, and X11/XCB, no GTK. On Debian or Ubuntu:

sudo apt install cmake libfontconfig-dev libxkbcommon-dev libxcb1-dev

docs/INSTALL.md has the per-distro list.

One rule worth knowing before you touch the manifest: the client builds against the published irontide from crates.io, pinned in Cargo.toml. There is no [patch.crates-io] and no local path override, on purpose — every build, yours and CI's and a fresh clone's, resolves the same released engine. To try the client against an unpublished engine change, publish that engine first (a real or pre-release version) and bump the irontide* pins. The engine has its own repository at https://codeberg.org/alan090/irontide.

Contributing

This is a personal project, maintained by Alan, with best-effort support. Issues and pull requests are welcome; a quick reply is not promised.

  • Codeberg (codeberg.org/alan090/irontide-client) is the primary repository; GitHub (github.com/alan09086/irontide-client) is a mirror.
  • Report a problem by opening an issue on Codeberg.
  • Commits are authored as Alan Gaudet <alan.c.gaudet@gmail.com>.

License

GPL-3.0-or-later