File organisers all sort by type. Images here, PDFs there, spreadsheets in the third drawer. That is not how anyone thinks about their own documents. Nobody has ever needed "all my PDFs". They need the six things about the car, which happen to be two photos, a PDF and three screenshots, scattered across four folders and three years.
I make a Mac app that already reads the text inside files, so I have an index of what my documents actually say sitting on disk as a side effect. Grouping by subject instead of by type looked like it was two afternoons away.
It was not. Here is what happened, with the numbers, because I have not seen anyone publish theirs.
My own machine, not a benchmark: 377 PDFs and 1,807 images. Roughly 99% of the PDFs gave up text, either from the text layer or from OCR.
Out of that I extracted hard identifiers only — no topic modelling, no embeddings, nothing fuzzy. Just things that are either right or wrong: national tax IDs, company names, domains, licence plates, insurance policy numbers.
1,837 identifiers
648 files that contained at least one
24 folders
1,041 distinct identifier values
750 company names
726 tax IDs
344 domains
13 policy numbers
4 licence plates
The signal is unmistakably there. One domain shows up in 64 documents spread over 9 different folders. One tax ID appears in 51 documents across 8 folders and a two-year span. Those are real relationships that no folder structure on my disk expresses, and that is the entire premise: the connection exists, the filesystem just cannot see it.
Obvious first move. Rank the identifiers, take the top ones, each becomes a group.
It produced three groups, and the largest, by a wide margin, was me.
Which is completely correct and completely useless. I am the tax ID on my own invoices. I am the company name on my own letterhead. My domain is in the footer of every document I have ever sent. If you rank entities by frequency across someone's document collection, the person themselves wins, and the runners-up are their accountant and their bank.
The single most common thing in your documents is you, and that is exactly the one entity that carries no information at all.
Obvious in hindsight. It was not obvious to me until I saw the output, which I think is the useful part of saying it out loud.
So: filter out my own identifiers and group by whoever is on the other side of the document. This is the right idea and it went from 3 groups to 23.
Most of them were wrong, in two specific ways.
Free email domains. When the strongest identifier in a document is a Gmail address, the "entity" becomes gmail.com, and a group forms containing a quote from a plumber, a school form and a used-car listing, whose only relationship is that all three people have Gmail. Easy to fix once you see it, invisible until you do.
Industry words, which are not easy to fix. Spanish company names very often contain the trade: Constructora this, Ingeniería that, Comercializadora the other. Forty unrelated companies share a word, so a rule that matches on the company name merges forty strangers into one confident group. English has the same disease in a milder form — every third startup is "something Labs".
A human separates a category word from a brand name instantly. I did not find a rule that does. Frequency does not help: the category word is common precisely because it is a category.
Tightening the rules moved the count to 26, then to 15 "strong" groups. Fifteen looked like progress until I read them. The tightening had killed the two groups that were unambiguously real — the 64-document one and the 51-document one — because those two were held together partly by generic terms that the stricter rule now discarded.
Four passes: 3, 23, 26, 15. Each one fixed the previous failure and introduced a new one. That is usually a sign you are optimising a metric instead of solving the problem, and it is where I stopped and went to look at the distribution instead.
781 of the 1,041 distinct identifiers
appear exactly once.
That is 75%.
Three quarters of everything extracted is a singleton. It appears in one document, once, and never again.
So the shape of the problem is not "find the clusters". The shape is a very short head of five or six entities that genuinely organise a large part of my life, and then a tail of hundreds of names that will never connect to anything, ever. Any algorithm that treats those two populations the same will either miss the head or invent structure in the tail, and mine kept doing both in alternation.
And in a product this matters more than usual, because the cost is asymmetric. A missed group is invisible: nobody knows the app could have shown it. A false group — "Tidy found 11 documents about your car" and four of them are about someone else's car — is the app confidently lying to you about your own files. One of those is a shrug and the other loses the user permanently.
I have not shipped this. What I have is a corpus, an extractor, four failed groupers and one decision I am fairly confident about: it does not go out until there are zero false groups on the first screen.
The obvious escape hatch is to stop writing rules and let a model read the whole corpus and tell me what belongs together. It would probably work. It would also mean the app can no longer explain why two documents are in the same group, and "here is the evidence" is the only reason anyone should trust a thing like this with their private files. So I keep not doing it.
What I would genuinely like to know from anyone who has been here: is there a deterministic way to tell a category word from a brand name inside a company name, without a list of every industry term in every language? That single problem accounts for most of my false groups, and I have run out of ideas that do not involve giving up on being able to explain the answer.
The extraction runs inside Tidy, a Mac menu bar app I make on my own in Santiago, Chile. All of it happens on the machine — the numbers above never left my disk, and the identifiers in this piece are deliberately unnamed for the same reason. $9 once, macOS 14 and up. I answer every email myself.