Skip to main content

llmt — LLM Torrents command-line client

llmt finds LLM models in the LLM Torrents catalog, downloads them over BitTorrent with HTTP webseeds, and — the point of the whole thing — verifies what you got: it fetches the catalog's Ed25519-signed manifest for the torrent, checks the signature against a public key pinned inside this package (not fetched from the network), and then verifies every downloaded file's SHA-256 against that verified manifest. If a byte is wrong — or the manifest cannot be authenticated — llmt tells you and exits non-zero.

Install

pip install llmt-cli      # from PyPI (once published; installs the `llmt` command)
# or, from a checkout:
pip install -e .

Requires Python ≥ 3.9 and aria2c on your PATH for downloading/seeding (apt install aria2, brew install aria2, …). If aria2c is missing, llmt prints a clear message instead of crashing.

Security & supply chain

llmt is high-trust software (it hashes your disk and drives a torrent client), so it is built to be audited, not trusted:

  • Catalog manifests are Ed25519-signed; pull/verify/seed verify the signature against the public key pinned in the package (llmt/data/manifest-pubkey.json) — the trust root ships with the code and is never fetched from the network at runtime. A manifest that cannot be authenticated (unreachable, malformed, bad signature, wrong/rotated key, or disagreeing with the catalog) is never reported as verified: distinct error, exit 15. Key rotation ships as a new llmt release.
  • llmt permissions prints exactly what the tool reads, writes, and sends (no telemetry, no self-update — enforced by unit test). Prose version: docs/PERMISSIONS.md.
  • Dependencies are pinned: pip install llmt-cli -c constraints.txt, or fully hash-verified in two steps (the lock file covers the dependency closure only — llmt itself is not in it, so install it separately): pip install --require-hashes -r requirements.lock && pip install --no-deps .
  • Releases ship a SHA256SUMS file (checksums published on llmtorrents.com); build + signing process: docs/RELEASING.md.
  • Vulnerability reports: SECURITY.md.
  • Docker image (pinned base, non-root) and homelab recipes: docs/recipes/.

Usage

llmt search "llama"                       # readable table of matches
llmt search "qwen" --fit --rig vram_gb=24 # fit verdict for your rig
llmt search "phi" --json                  # machine-readable

llmt pull microsoft-phi-4-mini            # best quant -> download -> verify
llmt pull microsoft-phi-4-mini:Q4_K_M     # a specific quant
llmt pull acme-tiny-1b --dry-run          # show the exact aria2c command

llmt verify ./acme-tiny-1b-Q4_K_M acme-tiny-1b:Q4_K_M   # re-check, no download
llmt seed acme-tiny-1b:Q4_K_M ./acme-tiny-1b-Q4_K_M     # help the swarm

Global flags on every command: --json, --api-base, --api-key, --timeout. Configure via env: LLMT_API_BASE, LLMT_API_KEY (the complete list of every env var llmt reads is in docs/PERMISSIONS.md and llmt permissions). An API key is optional and only raises your rate limits — all reads are public.

The trust story (signed manifest + SHA-256)

A torrent's own piece hashes only prove the bytes match that .torrent. They don't prove the .torrent describes the model the catalog vouched for — and TLS alone only proves who you talked to, not that the file list is the one the catalog signed. llmt closes both gaps:

  1. The Ed25519-signed manifest is the source of truth. For a non-gated model, llmt fetches the torrent's manifest (GET /api/manifests/{info_hash}) and verifies its detached Ed25519 signature against the public key pinned inside this package (llmt/data/manifest-pubkey.json, per the open manifest spec). It also checks that the signed document actually names the torrent being verified, and that the API's download.files[] block agrees with the signed manifest.
  2. After the download, llmt streams each file through SHA-256 (64 KiB chunks, no whole-file buffering) and compares byte-for-byte against the verified manifest's hash. This is a real, independent check — not aria2c's piece check.
  3. Any mismatch, missing file, or wrong size fails the run and llmt exits non-zero (3). A tampered or truncated file cannot pass silently. A file for which no hash was supplied is flagged NO-HASH, never waved through.
  4. An unauthenticatable manifest fails the run before any hashing — unreachable endpoint (e.g. offline), malformed document, invalid signature, unknown/rotated signing key, wrong torrent, or a catalog/manifest disagreement each produce a distinct error and exit 15. llmt never silently falls back to trusting unsigned hashes over TLS. (If the key was rotated, upgrading to the newest llmt release picks up the new pinned key.)
  5. llmt verify re-runs exactly this check on already-downloaded files — including the manifest signature check, so it needs the catalog API to be reachable; there is no offline "verified". llmt seed refuses to seed a torrent whose manifest cannot be authenticated.

Because a wrong file trips a non-zero exit, llmt pull / llmt verify drop straight into a pipeline: if it exits 0, every file matched the Ed25519-verified manifest.

License-gated models (why some models won't download)

Some models are distributed under a click-through license. For those, the catalog API serves no download artifacts at all — no magnet, no hashes, no file list. llmt detects this and tells you to accept the license on the model's page first:

$ llmt pull meta-llama-llama-3-3-70b-instruct
'meta-llama-llama-3-3-70b-instruct' is license-gated. The catalog API does not
serve download artifacts for gated models.
Accept the license here, then retry: https://llmtorrents.com/models/meta-llama-llama-3-3-70b-instruct

llmt will never fabricate a magnet or hash to work around a gate.

How the download works (aria2c + webseeds)

llmt delegates the transfer to aria2c, passing the catalog's magnet URI plus every webseed URL as trailing HTTP URIs, so aria2c uses the project's HTTP mirrors as web-seeds alongside the BitTorrent swarm. Roughly:

aria2c --dir <out> --enable-dht=true --bt-enable-lpd=true \
       --check-integrity=true --max-connection-per-server=8 --seed-time=0 \
       [--bt-tracker <tracker> ...] \
       <magnet> <webseed-url-1> <webseed-url-2> ...

Use llmt pull ... --dry-run to print the exact command for your model.

Known webseed quirks (why aria2c may exit non-zero on a good download)

Both HTTP origins serve the model files but 403 the bare base URL (directory listings are disabled by design), and hybrid v1+v2 torrents contain BEP-47 .pad entries that 404 on the HTTP mirrors (often seen as a "stall" at 98-99% in aria2c's progress summary). Either can make aria2c exit non-zero (e.g. code 22) even though every payload byte arrived.

llmt pull handles this: when aria2c exits non-zero it checks that every expected file is present on disk at its expected size. If so, it notes the quirk on stderr and proceeds straight to the full SHA-256 verification — the hash check against the signed manifest, not aria2c's exit code, is the trust signal. If files are missing or the wrong size, the download really did fail and llmt exits 10 loudly.

llmt verify <dir> <ref> accepts either the outer download directory (the one pull created) or the inner payload directory the torrent unpacked inside it — it detects which you passed. If it can't find the files at all, it tells you exactly which directory to pass.

Seeding your existing models (the layout mapper)

SHA-256 tells you a file is the right bytes, but a BitTorrent client won't seed those bytes unless they appear at the exact path the torrent expects, under the torrent's root folder. Your model lives at /models/qwen3-30b/model.gguf; the torrent wants qwen3-30b-a3b-q4-k-m/Qwen3-30B-A3B-Q4_K_M.gguf. The layout mapper plans how to present your existing file to the client without moving or copying it.

  • Direct-use: if your file already sits at the expected relative path, the plan is just "add the torrent with this save path" — no links at all.
  • Link farm (default for mismatched layouts): the mapper builds a tiny tree under ~/.llmt/seeding-layouts/<torrent-root>/… whose entries are hard/sym links back to your real file. Your model folder stays your model folder; the farm is just a set of pointers the client can follow. Save path is the layouts dir; the client rechecks, sees 100%, and seeds. Model weights are never re-downloaded and nothing is duplicated on disk. One honest caveat for multi-file torrents you hold only partially: small companion files (license/README-class, at most 10 MiB total per torrent) may be fetched by your client, and llmt scan prints a notice naming them and where they land first; any larger missing file is marked "do not download" in your client before the torrent can resume, with a warning that it will seed only what you have and show as incomplete.

Hardlinks are preferred whenever the file and the farm are on the same filesystem/volume — they need no privileges and every client follows them. A symlink is the labelled cross-volume fallback.

Platform Same volume Cross volume
Linux / macOS hardlink symlink
Windows hardlink (same drive, no admin) symlink — needs Administrator or Developer Mode (NTFS junctions redirect directories only, not files)

The client must force-recheck after adding so it verifies the linked bytes and reaches 100%. The mapper refuses any path that would escape the layouts dir (.., absolute/drive-letter/UNC tricks, reserved names, null bytes) and never silently replaces an existing link that points somewhere else.

Dockerized or remote clients (seedbox / unRAID): a qBittorrent or Transmission running in a container only sees its own mounted volumes, not host paths like ~/.llmt/seeding-layouts. If the link farm lives on a path the client cannot see, its force-recheck reads 0% and llmt scan fails closed (it never resumes an unverified torrent). Point the farm at a directory the client has mounted with --layout-base, e.g. llmt scan --layout-base /mnt/user/appdata/qbittorrent/llmt-layouts. llmt scan also prints an early advisory when it detects the client's own default save path does not exist on the machine llmt is running on (a sign the two are on different filesystems), and llmt doctor reports a layout-base-visible check that WARNs in the same situation.

Opt-in seeding telemetry (off by default)

Telemetry lets the LLM Torrents site credit you for the artifacts you seed. It is a separate, explicit, off-by-default, revocable opt-in — it never runs until you turn it on, and it never sends file paths or scan data.

llmt telemetry enable            # prints the exact consent statement, then
                                 # prompts for your token (from the website)
llmt telemetry enable --yes --token llmta_xx…   # non-interactive (scripts)
llmt telemetry status            # consent state, token presence, last beat
llmt telemetry whoami            # who the stored token belongs to (GET /me)
llmt telemetry beat --qb-url http://localhost:8080   # send one heartbeat
llmt telemetry beat --loop       # keep beating every 15 min (or --interval N)
llmt telemetry disable           # stop sending AND delete the stored token

beat reads the torrents from your client (--qb-url/--tr-url or LLMT_QB_URL/LLMT_TR_URL, same flags as scan/doctor), reports each torrent's infohashes (v1 and v2 for hybrid torrents), name, state and progress plus the SHA-256s of the artifacts you hold, and answers any possession challenges the server issues by hashing a server-chosen byte range of the local file. Run it from cron (the primary mode) or with --loop.

What is sent: torrent infohashes/names/states/progress, artifact SHA-256s, and challenge byte-range hashes — nothing else. What is never sent: file paths, filenames, scan data, or machine info. The token is stored at ~/.llmt/agent-token (mode 0600) and is never printed after it is saved. View or delete your server-side data on the website (Account -> Telemetry). See docs/PERMISSIONS.md and llmt permissions for the full statement.

Config keys (in ~/.llmt/config.json, all under telemetry): enabled (default false), endpoint (default https://llmtorrents.com), interval_minutes (15), max_torrents_per_heartbeat (500), report_artifacts (true), token_path, challenge_chunk_size. Override the endpoint per-run with --endpoint or LLMT_TELEMETRY_ENDPOINT.

Exit codes

code meaning
0 success / all files verified
2 generic API error (incl. 403)
3 SHA-256 verification failed
4 not found (404)
5 rate limited (429; respects Retry-After)
6 request timed out
7 model is license-gated (D7)
8 no gate-passed torrent available
9 aria2c not installed
10 aria2c failed and the download is incomplete
14 torrent-client add/connection failed
15 manifest unverifiable (fetch failed/offline, malformed, bad signature, wrong/rotated key, wrong torrent, or catalog/manifest mismatch) — nothing was verified
20 telemetry error (generic / disabled)
21 telemetry token missing/unknown/revoked (401)
22 telemetry token lacks telemetry:write scope (403)
23 telemetry config error (no token / bad endpoint)

Development

pip install -e ".[dev]"
pytest -m "not live"   # offline unit suite (mocked API)
pytest -m live         # read-only smoke calls to the real API

License

MIT — see LICENSE.

Metadata

Release files for llmt-cli 0.2.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for llmt-cli 0.2.1
File Size Uploaded Provenance Actions
llmt_cli-0.2.1.tar.gz 172.3 kB Without provenance Details for llmt_cli-0.2.1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for llmt-cli 0.2.1
File Interpreter ABI Platform Actions
llmt_cli-0.2.1-py3-none-any.whl Python 3 none any Details for llmt_cli-0.2.1-py3-none-any.whl

Total release size: 291.1 kB

Release files / llmt_cli-0.2.1.tar.gz

Download URL llmt_cli-0.2.1.tar.gz
Size 172.3 kB
Tags Source
SHA-256 checksum
How to use checksums
f930ca4b5f17d7489f9dca54768a8fcf16f90e335295068373fbae8b418a0884
BLAKE2b-256 checksum
How to use checksums
7c1df7673f89dd16f58734fb6ec571b1a69953b59ea487f9f60a14c5881a9dd6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.11.9

Release files / llmt_cli-0.2.1-py3-none-any.whl

Download URL llmt_cli-0.2.1-py3-none-any.whl
Size 118.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
953d8c52d54e7cc88a2e94090abade53a61150a332c3246516673afe78cebee3
BLAKE2b-256 checksum
How to use checksums
a4907ff4c9d252fbd08d9cbd5abbd79fb91eced3f9a63d1feb0baf9a5c840b1b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.11.9

Security for llmt-cli 0.2.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.2.1 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page