guest@6admin.io:~$

llmp2p: BitTorrent is back and it ships your LLMs

This is exactly the problem with local LLM models: a GGUF is 1 to 100 GB, served over plain HTTP. Every download starts from zero on the Hugging Face Hub. Your three-machine Ollama homelab? Three complete downloads of the same blob, three times the bandwidth bill.

Before writing anything, I checked the shelf. The Hub CLI resumes but re-hits the origin every time. Ollama pulls re-download the whole blob per machine. Torrent clients would happily distribute the files, but nothing tied a swarm to the hashes the Hub publishes, nothing signed the metadata and nothing fell back to HTTPS when the swarm was empty. Nothing on the shelf did the whole job, so I wrote the whole job.

So I wrote llmp2p : models become what they are, giant immutable blobs that a swarm serves better than a single origin. First pull of a model nobody seeds? Slow, with a clean HTTPS fallback. But as soon as two people have it, things speed up. The more popular a model, the faster it spreads. That has been the swarm contract for twenty years.

llmp2p: a clay 3D ant colony carrying a glowing model brain between tiny servers and the cloud

The protocol: manifest and verification

llmp2p does not download files blindly. The protocol:

  1. The manifest: a JSON describing the model (name, size, SHA-256 of the blob), signed ed25519 by the publisher. The publisher’s public key is in an allowlist.
  2. The torrent: the manifest becomes a torrent whose pieces correspond to chunks of the GGUF blob. The swarm forms around the torrent.
  3. The verification: at the end of the download, the blob’s SHA-256 is recomputed and compared to the manifest. No match, the blob is rejected and re-downloaded from HTTPS.
  4. The HTTPS fallback: if the swarm is empty (nobody seeds), llmp2p downloads directly from the Hugging Face Hub, like any other client. Nobody waits for a swarm that will never arrive.

The HTTPS fallback guarantees the first download works. The swarm guarantees the next ones are faster. And the verification guarantees the downloaded blob is exactly what the publisher signed.

The daemon and the CLI

Two binaries in Go (1.25):

  • llmp2p : the CLI. llmp2p pull <model> downloads, verifies and seeds. llmp2p verify <model> re-verifies integrity. llmp2p keygen generates an ed25519 keypair for signing manifests.
  • llmp2pd : the daemon. Listens on :8347, exposes a REST API to list available models, their download status and swarm stats.

The daemon is designed to run as a service, always active, always seeding downloaded models. Every pull becomes a seed for the next machine.

The container: FROM scratch

The Docker image is built FROM scratch (no base, no shell, no libc): the static Go binary is the only content. Multi-arch (amd64, arm64), cosign-signed and the SBOM is generated at build time. The image weighs a few MB.

The GitLab incident: when your infra remembers your dead

[edit: October 2026] Early October, a file in my GitLab repository triggered an alert: a pipeline from 2022 referenced a runner that no longer exists. The runner had been deleted, but the reference survived in a config file and GitLab sent an error email on every push, two years later.

The problem was not the email. It was the discovery: digging through the orphaned pipelines, I found CI artifacts containing API keys, deployment secrets and access tokens, in jobs that had run two years ago, on branches deleted since. GitLab keeps CI artifacts even after branch deletion and those artifacts were accessible from the project’s API.

The lesson: the secrets you used two years ago are probably still in your CI artifacts and artifact cleanup is as important as secret cleanup in the code. llmp2p cleans its own: the .gitlab-ci.yml expires artifacts after 24h and environment variables are scoped per environment, not global.

Living with it: private swarms, Ollama, deploy units

Three things that turned it from a demo into a tool I run daily:

  • Private swarm mode (pull --swarm-key): discovery goes DHT-only under a shared key. No bootstrap origins, no Hub fallback: your internal model repos stay internal, seeded between your own machines.
  • Ollama integration: after a verified pull, llmp2p registers the GGUF through ollama create with a generated Modelfile. Mutating Ollama’s blob storage directly is version-dependent and unsupported, so the integration goes through the CLI instead of poking the data directory.
  • Deploy units: systemd, launchd and NSSM units ship in the repo, because a seeder you start by hand stops being a seeder the week you forget it.

The repo has been on a release train since the start of September; the tool is young, the swarm contract is old.

The application code is on github.com/log0u7/llmp2p . The container image, FROM scratch, multi-arch and cosign -signed, is built in a dedicated repo and pulled from registry.gitlab.com/6admin.io/docker/llmp2p/llmp2p:v0.3.2.