Skip to main content
~/projects / tocli

tocli

maintained

A terminal BitTorrent client with a process-per-torrent architecture, where every command works as a scriptable one-shot invocation or an interactive TUI.

tech = [Go, Cobra, Bubble Tea]

tocli is a terminal BitTorrent client built around one rule: if a command has everything it needs to act, it just acts, no prompts, safe to script or cron; if it’s missing something, it opens the relevant interactive screen instead of printing a usage error. tocli start ./file.torrent downloads immediately; tocli start with no source opens a screen to type one in. tocli list on a real terminal opens a live, refreshing dashboard; piped or --plain/--json output stays static and scriptable.

One process per torrent, no daemon

There’s no long-running tocli server. start/resume spawn one detached background process per torrent, which owns that torrent’s download for its entire life. pause is just SIGTERM to that process’s pid. There’s no IPC between the CLI and the background processes; they only communicate through files on disk under ~/.tocli/. A crash in one torrent’s process can’t touch any other torrent, and nothing keeps running when nothing is downloading.

Trusting on-disk state after a crash

A background process can die with no chance to update its own bookkeeping: kill -9, an OOM kill, the machine losing power. So tocli never fully trusts a stale status: running. It cross-checks the recorded pid against a real, live process, and compares a recorded boot-session id against the current one, so a pid reused by an unrelated process after a reboot is never mistaken for the original torrent. Each background process also holds an OS advisory lock (flock) on its torrent’s lock file for as long as it’s alive, released automatically the instant its file descriptors close, for any reason. That’s a direct kernel guarantee rather than an inference, so a second process can never start downloading into the same directory while another one already is, even in the narrow window right after a crash.

One engine, two front ends

The interactive TUI never talks to the torrent client or the on-disk state directly. Every screen calls the exact same internal/engine functions (StartTorrent, PauseTorrent, ResumeTorrent, RemoveTorrent) that the plain CLI commands call, so there’s exactly one implementation of what each action does. The CLI and TUI only differ in when they call it and how they render the result.

Built on anacrolix/torrent for the BitTorrent protocol, cobra for the command layer, and bubbletea for the TUI. Tagged releases are cross-compiled for Linux and macOS (amd64/arm64) via GitHub Actions.