llm-librarian
A command-line tool that files a pile of ebooks (PDF, EPUB, MOBI, AZW3) into an existing directory tree, using a local model through Ollama. No API costs, and nothing gets copied anywhere without your approval.
I built this because I tried letting Claude Code organize a few ebooks, and it destroyed my entire system. I didn’t lose any data, but I had to reinstall Linux. Somewhere in the process I’d given Claude permission to `mv` files into the parent directory, and after letting it run a while I realized it had backed out a few times too many and moved my entire `home/` directory to some other directory in root. At that point it’s not really safe to simply move things back. But at least all my data was still there, I just saved what I needed and reinstalled.
So then, the design is deliberately not an agent wandering around your filesystem. It’s a fixed pipeline, and most of the work went into giving the model as little room as possible to be creative. First it gathers metadata - from the filename, from whatever is embedded in the file, and from an Open Library lookup, which usually supplies subjects and a Dewey number - so the model rarely has to fall back on its own knowledge of a book. Then it classifies, in two small multiple-choice steps: pick a top-level section, then pick a leaf directory inside it. The options are enums built from your actual directory tree and enforced by the structured output grammar, so the model can’t invent a category or a path. Dewey numbers map to a section hint in plain code, not by asking the model. And since my ebooks directory is constructed using my drewy-decimal script, DDC numbers are actually very helpful in this organization.
Every decision is sent to a JSON manifest with a confidence score, and
nothing touches the library until you’ve been through them. The
confidence number is really just the model’s own self-report,
uncalibrated. So it’s a more of a key for review, not a guarantee. You
approve, reject, or edit each proposal (or bulk-approve above a
confidence threshold) and only then does execute copy the approved
books in, renamed Title - Author (Year).ext.
It copies, never moves; the tree is treated as read-only, so
directories are never created. If a book fits nowhere, that’s a
needs_review outcome and it’s your call whether to add a directory
and run it again. Re-runs are idempotent and classify is resumable,
so you can interrupt a long run without losing work.
And the runs are… long. Speed is entirely about prompt prefill - the
model reading a long list of candidate directories - which on a CPU
means minutes per book. A GPU is worth 10-50x here and needs no
configuration, so classify prints the model placement at startup to
tell you whether you’re actually getting one. If your machine is
CPU-only you can point --ollama-url at Ollama running on a rented
GPU box over an SSH tunnel; only metadata and directory names go over
the wire, so the ebooks themselves never leave your machine.
The code is here on GitHub.