A small Python client for the Transmission daemon's RPC API, with a command-line tool, a local web page and an importable library. This post runs it against a local mock server, so no real torrents are involved.
Open-Source Tools · How-To · Dev & ops tools
How to use transmission-client: control a Transmission daemon from a CLI, a web page or Python
Revised
· v1.0.0 · what changed
Code: github.com/herrrickshaw/transmission-client
Watch the walkthrough
Watch on YouTube: youtu.be/kkx1vkb9kHo
Why it is useful
- Home-lab and NAS owners who run transmission-daemon headless get a scriptable list/add/start/stop/remove tool without installing a desktop client.
- It replaces hand-written curl calls that must juggle Transmission's X-Transmission-Session-Id CSRF header: the client catches the 409 reply, stores the id and retries automatically.
- Developers get one TransmissionClient class shared by the CLI and the web page, which is a short, readable example of a session-token-protected JSON-RPC client.
- Evidence from the run: against a mock daemon, list, info, add and a guarded remove all worked, and the mock log showed each call as an unauthenticated POST answered 409 followed by a retry carrying the session id.
What it is for
transmission-client talks to a transmission-daemon over its documented RPC interface. You can list torrents, show details, add a magnet link or .torrent file, start, stop and remove torrents from a terminal, a web page on 127.0.0.1:5000, or from your own Python code.
Use it only with content you have the right to download and share. The examples here use a local mock with two Linux ISO names.
Who it is for
- People who run transmission-daemon on a server, Raspberry Pi or NAS
- Python developers who want a compact RPC-client example
- Scripters who want to automate adding and cleaning up torrents of legitimately shareable files
- Downloading or sharing copyrighted material you have no right to
- Exposing the daemon to the internet: the README's --allowed "" setting is marked dev only
- Replacing the official Transmission clients for day-to-day use; this client has no automated tests and a minimal feature set
What you need
| Requirement | Why | How to get it |
|---|---|---|
| Python 3.9 or newer | Declared in pyproject.toml | python.org or your package manager |
| Python packages: requests, click, flask | HTTP calls, the CLI, and the web GUI | Installed automatically by pip install |
| A running transmission-daemon (to use it for real) | The client is only a front end for the daemon's RPC port (default 9091) | Your OS package manager; this post used a local mock instead |
| RPC credentials (if your daemon has auth) | Passed as TRANSMISSION_USER and TRANSMISSION_PASS | From your daemon's settings; keep them in environment variables, not in files you commit |
Get the code and an AI assistant
You do not have to be a programmer. Get the repository, give it to an AI assistant, and ask in plain language. Any of these routes works:
| Tool | What you need | Best for |
|---|---|---|
| GitHub | Free account to fork or star; git to clone, or the green Code button, then Download ZIP, or open in Codespaces | Getting the code and keeping up with updates |
| Claude Code | Claude subscription or API key; run claude inside the cloned folder | Letting the AI read and run the whole repo |
| Gemini CLI | Google account; run gemini inside the cloned folder | The same hands-on workflow with Gemini |
| Claude.ai, Gemini or ChatGPT in the browser | A chat account; upload README.md and the files you care about (or paste the output of git ls-files) | Understanding the project and asking questions without installing anything |
| Other tools (Copilot Chat, Cursor, Codex CLI) | Open the cloned folder in the tool and point it at README.md first | Editing and extending the code |
git clone https://github.com/herrrickshaw/transmission-client.git
cd transmission-client
claude # or: gemini
Install
- Clone the repository
git clone https://github.com/herrrickshaw/transmission-client.git cd transmission-client - Create a virtual environment and install
python3 -m venv .venv source .venv/bin/activate pip install -e . - Point it at your daemon
export TRANSMISSION_HOST=localhost export TRANSMISSION_PORT=9091
Quick start: commands and what you should see
List torrents
transmission-cli list
A table with ID, STATUS, DONE, SIZE, DOWN, UP and NAME columns (see sample output).
Show details for one torrent
transmission-cli info 1
Name, ID, hash, status, progress, size, speeds, ratio, peers and download directory.
Add a magnet link
transmission-cli add 'magnet:?xt=urn:btih:...'
A line like: Added: <name> (id=N).
Remove a torrent (asks first)
transmission-cli remove 3 [--delete-data] [--yes]
A prompt 'Remove the selected torrent(s)? [y/N]'. Answering anything else aborts. --yes skips the prompt.
Start the web GUI
python3 -m transmission_client.web
Serves on http://127.0.0.1:5000 with the torrent list auto-refreshing every 3 seconds. Not run in the demo; README only.
Sample outputs
Real output from a run on the date shown in the sources line; trimmed to fit.
transmission-cli list against a local mock daemon (run 19 October 2026)
transmission-cli list
ID STATUS DONE SIZE DOWN UP NAME
1 downloading 42.0% 5.6GB 2.4MB/s 117.2KB/s ubuntu-24.04-desktop-amd64.iso
2 seeding 100.0% 619.9MB 0.0B/s 48.8KB/s debian-12-netinst.iso
The daemon here was a 40-line mock written for this demo (not part of the repo); the torrent data is invented.
transmission-cli info 1 (mock daemon)
transmission-cli info 1
Name: ubuntu-24.04-desktop-amd64.iso
ID: 1
Hash: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Status: downloading
Progress: 42.0%
Size: 5.6GB
Down/Up: 2.4MB/s / 117.2KB/s
Ratio: 0.03
Peers: 14
Dir: /downloads
Hash is a placeholder from the mock.
Library call and the mock's request log, showing the 409 session handshake
python -c "from transmission_client import TransmissionClient as C; print(C().session_stats())"
{'torrentCount': 4, 'activeTorrentCount': 1, 'downloadSpeed': 2500000, 'uploadSpeed': 170000}
mock log (session id column):
POST /transmission/rpc None (first try -> mock answers 409)
POST /transmission/rpc mock-session-123 (retry -> success)
Every new process pays one extra round trip because the session id is not cached between runs.
Guarded remove with no confirmation
transmission-cli remove 3
Remove the selected torrent(s)? [y/N]: Aborted!
With no terminal input the prompt aborts, which is the safe default.
Ways to use it
| Method | How it works |
|---|---|
| Command line | transmission-cli list/info/add/start/stop/remove, with --host, --port, --user and --password flags on every subcommand. |
| Web GUI | python3 -m transmission_client.web, then open 127.0.0.1:5000. Override the port with TRANSMISSION_WEB_PORT. |
| Python library | Import TransmissionClient and call torrent_get, torrent_add, session_stats and friends from your own scripts. |
| Through an AI assistant | Ask an assistant to write a script that, for example, removes finished torrents that reached a set ratio. |
Sample prompts for your AI assistant
Copy, paste and edit the parts in [brackets].
- Read this repo and explain how the X-Transmission-Session-Id 409 retry works in rpc.py, in plain English.
- Write a Python script using TransmissionClient that lists seeding torrents with an upload ratio above 2 and prints their names.
- Add a small pytest suite for transmission_client/rpc.py using a mocked requests session; cover the 409 retry and the error path.
- Review cli.py for anything that could delete data by accident and suggest safer defaults.
- Show me how to cache the session id between CLI runs so each command needs only one request.
Limits and honest caveats
- Demonstrated against a mock daemon only. No real Transmission daemon, real torrent or network transfer was involved, so real-daemon behaviour (auth failures, large lists, RPC version differences) is untested here.
- The web GUI was not run; only the README describes it.
- The repo has no tests directory; the README lists no test command.
- The session id is not cached between processes, so every CLI invocation makes two requests (visible in the mock log).
- The remove subcommand accepts --yes but not -y.
- The README suggests transmission-daemon --allowed "" for dev; that opens the RPC port to every host, so do not use it on an exposed machine.
- Use only for content you are legally allowed to download and share. Not legal advice.
Sources: the transmission-client README, pyproject.toml and rpc.py; CLI commands list, info, add and remove run on 19 October 2026 from a fresh clone in a throwaway virtualenv against a local mock RPC server written for the demo.
- v1.0.0 — 28 October 2026 — first published.
About this article: Researched, written and edited by Umashankar Triplicane Dwarakanathan, with AI research assistance; every figure is meant to trace to the primary source cited. See the Editorial Policy for how sourcing, AI use and corrections work.