Making a Better Board Game Recommender
It started harmless enough, with asking ChatGPT what board game to play. Then I decided to spend a weekend to improve the results a bit. Seven months later, we're emerging from a very deep rabbit hole on what it means to recommend something.
TLDR: We just launched a board game recommender, you can try it here. You tell it who is playing and what you’re in the mood for, and it’ll suggest twelve games from our shelves, along with reasoning about why those are good picks for you and your group.
A few years ago, someone like me could never have built this. And more likely, a place like Tabletop Library would never even try. These recommenders are generally the domain of a team of PHDs at Netflix and Spotify with a billion data points. We, on the other hand, are a local board game club that hasn't even opened yet, with a few hundred members, a few thousand games, and some weekend free time.
So consider this a peek behind the curtain at what building software looks like right now, from an amateur feeling his way through a field real experts spend their careers on. (If you are one of those experts, I'd love your feedback)
It all started with a reasonable question to ask an AI in our current age:
- Four of us want a visually beautiful game driven by cards that we can finish in under 60 minutes. What should we play?
The first time I did this it kind of worked. It's was even a little magical. But I found that like a lot of AI stuff, repeated usage really shows the difference between something that quickly kinda works, and a really useful tool.
If you ask this same question a couple dozen times, as I did late last year of Claude and ChatGPT, you notice some things:
- Claude recommends Wingspan virtually every time it was asked. This makes sense. Wingspan is beautiful, full of cards, and one of the most acclaimed board games of the last decade. Claude said it would take 40 minutes. Stats from BGG say 70 mins, my experience says it's more like 90 if you are teaching it.
- It often recommended Azul, a game with no meaningful card play, because it offered a “card-adjacent drafting experience.” This is an excellent phrase to write when you know Azul is a lovely game and would prefer not to dwell on the cards question.
- One run included Lost Ruins of Arnak, listed in the same answer at 120 minutes. The request said 60.
- It also recommended Jaipur twice. And yes it is full of cards, though I'm not sure I'd call it beautiful. But the kicker for this four player recommendation was this description, "a great 2-player classic, so it’s not ideal for all four of you at once, but it’s a strong “beautiful and fast” option if you split into pairs."
I'm not cherry picking failures, they are indicative of the trend. But still, if you typed that into Chatgpt or Perplexity or Claude you could easily read the list, pick Wingspan, and move on with your life.
However the answer still left out a few things for us at Tabletop Library:
- Do we own the game?
- Is it actually best with four people, or just kinda playable at four people?
- Does anyone in the group know how to teach it?
- Does one person in our group hate this type of game?
- Is “under 60 minutes” a preference, or does someone need to catch a train?
- Are we recommending Wingspan because it is right for this group, or because the internet has written a lot of sentences about Wingspan?
That last question is more complicated than it looks. Research on zero-shot LLM rankers has found sensitivity to both item popularity and to things as subtle as where a name appears in a prompt.
To research further I gave Claude Sonnet and GPT twelve prompts 50 times each (stuff like "games where we negotiate a lot" and "best co-op games for beginners and advanced players together). Across 600 recommendations, it returned only 61 unique titles. Blockbuster popular games like Azul and Pandemic appeared constantly.
Repeated prompts overlapped by 58% on average. For the opening question listed here, the overlap was 37%. That means answers were both repetitive and unstable, which is an efficient way to acquire two problems at once.
So I decided it could be fun little side project to try and build a better board game recommender. After all, it would be a nice way to test out some frontier LLM stuff, maybe do some custom model building, explore vector databases, and so on for a few weeks.
I mean, how hard could it be?
Oh boy.
The first recommender was basically an AI agent
I should own the ridiculousness of this up front. I spent seven months deep-diving a subject I don’t know much about, to build an esoteric tool whose best-case outcome is a few hundred board game club fans being mildly happier on a Tuesday night. It is perhaps a good example of of what can happen with vibe coding though. It's not so much that this is replacing what in the past a software engineer would have built, it's that this just would never have been built at all.
I drafted the first version of our `/play` recommender in December 2025, and it was relatively typical for what you would imagine of the time.
First, an LLM (GPT 4-o back then) was given the search term, and separated things that sounded like firm constraints ("four players") from things that sounded subjective (like “beautiful” or “cozy”)
Then I built a vector database of all of Tabletop Library’s catalog with TurboPuffer, using a mix of semantic and keyword search. It fetched up to 30 plausible games from the database with player counts, durations, complexity, descriptions, our classification data, and anything we knew about the players.
Then we handed the whole packet to GPT-4o again and said, more or less: pick the best 12 based on the prompt you were handed.
It also wrote a reason for every recommendation. Stuff like: "David can teach this one." "Molly has been wanting to learn that one." "This game has the same auction mechanic as a game you liked."
This was a sensible architecture. It was also essentially the first architecture many people build for an AI agent:
1. Retrieve the available context.
2. Put it in a prompt.
3. Ask a capable model to figure out the rest.
And the results were familiar to anyone with a pattern of working with LLMs. As a first shot, it worked better than it had any right to, which felt great. But the gap between "okay as a first attempt" and "actually great" did not seem to be improving at all as I was adjusting LLM prompts over and over.
The issue was the model still owned nearly every important decision after retrieval: constraint adherence, ranking, group compromise, novelty, and the final explanation. One opaque LLM call decided whether a 70-minute game was close enough to a 60-minute request and whether one player’s enthusiasm outweighed another’s dislike.
From here I decided to do a little research. Recommendation systems are not new after all, so this has got to be a solved problem we just need to find the right approach?
Board games are a tricky little recommendation problem
There are three core issues that made most recommender systems that you see in the world not a great fit for this little cardboard hobby.
1) Most of the best recommender systems were built for abundance.
Music services have tens of millions of tracks and enormous listening histories. Netflix built its recommender around a vast catalog and an even larger stream of views, searches, ratings, and browsing behavior. There's a long line of academic literature, and the vast majority of the innovations in machine learning on recommenders are leaning into the amount of data available.
But there are relatively fewer board games in the world than songs. Even more acute, Tabletop Library has a couple thousand games and a membership measured in hundreds. Many members have rated fewer than ten games. Some have rated none. A new member may know that they enjoy “card games” or that Catan was pretty fun eight years ago. But that is not enough data to train a small regional Netflix.
2) Board games are also consumed differently.
If Spotify recommends a bad song, you skip it. Four minutes have passed, assuming you were very patient. If a board game recommender makes a bad choice, four people may spend 20 minutes learning rules, another 90 minutes playing, and the drive home discussing why nobody stopped David from choosing it.
3) Then there is the group itself.
Most recommenders answer a personal question: what will this person click, watch, or buy? But a game-night recommender answers a temporary social question: what will these particular people enjoy together, tonight?
The last thing you want here is the highest average rating. If three players are delighted and one player will be miserable, the averaging rating may still look respectable. But faces of players at the table will not be.
Other people have been working on this for a while
So I started digging into the academic literature for stuff we could use.
Recommenders began as far back as Xerox PARC’s Tapestry, but the first time they really entered my awareness was the early Internet era with music services.
In these pre-Spotify days, the three early major services were Last.Fm, Pandora, and Yahoo! Music, and each took a different approach to recommendation that still loosely defines the paths used today.
- Pandora invested in knowing the content, basically data as the key. Its Music Genome Project employed trained musicologists to describe hundreds of details about songs like the tone, instruments used, etc.
- Last.fm invested in social behavior: its “scrobbling” system recorded what people actually listened to, producing taste histories that could be compared with other listeners.
- Yahoo! Music combined explicit ratings with a hierarchy spanning tracks, albums, artists, and genres. The Yahoo! Music dataset used in the 2011 KDD Cup contained hundreds of millions of ratings from more than a million anonymized users.
As an avid collector of MP3s in those days and I remember being fascinated by the inherent contrasts in style. Content-based systems can understand a new item before anyone has listened to it, but they need good descriptions. Collaborative systems can discover relationships nobody thought to label, but they need enough overlapping behavior. Explicit ratings are clear, but most people do not want a second job rating everything they encounter.
These three basic architectures actually still define the major approaches today. But now they are implemented as hybrid systems. Robin Burke’s survey of hybrid recommenders described several ways to combine systems so that one could cover another’s weaknesses. Netflix eventually made the same point at production scale: its recommender system was not one algorithm. It was a collection of ranking systems, rows, search behavior, contextual signals, offline tests, and online experiments.
So I started weighing the various recommender systems in the academic literature against each other and applying them to our problem.
For example, the earlier issue of not using the average happiness rating of all the players because one person might be miserable for 90 minutes? That's called least misery scoring.
There are other approaches: average preference, multiplicative scoring, fairness rules, taking turns serving different people. Judith Masthoff’s work on group recommenders found that people use several of these strategies.
So many papers! And there's no specific formula handed down on a stone tablet for our problem. However, this is the kind of complex, academic research that is well suiting for Claude to spend a day doing deep research on.
Asking Claude "hey what's the academic literature on this subject" ended up yielding pretty surface level answers without much insight. But as things got more agentic, it became possible to ask Claude Code (in Conductor) to spin up a bunch of sub agents to read every single article and paper on Recommender systems, then write a text summary of each article analyzing how it could potentially help our particular problem.
That, combined with using academic AI research tools like Elicit, yielded directories full of architectural comparisons: the systems we could build, judged against the published literature for our exact problem: a couple thousand games, a few hundred members, sparse ratings, group play.

Armed with this, it turned into a wonderful enjoyable rabbit hole just before bed each night reading, researching, and rapid prototyping.
The five stages of the recommenders

Five different recommender approaches made the cut, systems that combined the various recommender styles: some leaned on LLMs like ChatGPT and Claude, some on deterministic scoring formulas out of the search-engine literature, some on the old social, people-like-you recommenders. The permutations did get quite complex, but in the end we ended up with a relatively simple approach that beat them all.

The five, in order:
(1) The Simple LLM Ranker
You have already met the Simple LLM Ranker. Retrieve candidates from our database, hand everything to the AI model. This is the first system we built. The story of the other four is which responsibility moved out of the model at each step.
(2) The Multi-Source Ranker and Retriever
Let basic code decide what games are in the pool to decide from
The first major change — and the one that survived into every version after — was a deterministic hard-filter gate. Even if we were going to use an LLM, it needed to be given a very clear sandbox to play in.
If someone asks for a four-player game, we should write code to make sure the game actually is 1-4 players. The same applies to complexity, excluded games, required mechanics, explicit categories, stock, and other constraints.
Using multiple approaches to generate potential games
The original system also got candidates from one place: search. This meant the ranker could only choose games the search system happened to retrieve.
We added three more channels:
- games on the seated players’ lists;
- games liked by members with similar rating histories;
- games related to a title named in the request.
Two of these channels are the music-service ideas at club scale. “Members with similar rating histories” is Last.fm’s move: find people whose history overlaps yours and borrow their enthusiasm. “Games related to a title” is the item-based variant of the same trick: two games are similar if the same people like them both.

These methods are not there to rank anything, it just decides which games are allowed into the conversation.
(3) The Deterministic Scorer
Then we tried a recommender that is more akin to what you would have found prior to this AI craze, with no LLMs at all. We built a Deterministic Scorer with a weighted score. Retrieval rank, collaborative evidence, list affinity, semantic fit, quality, novelty, group support, and duration fit each contributed a visible amount.
The recipe came from search engines, where it is called reciprocal rank fusion: trust no single list; a game earns points for ranking high on several lists at once.

This was fast, reproducible, and inspectable. The downside it that is it a bunch of inscrutable weights - something is a .12 on novelty and .10 on player match and just moving them around all day felt fruitless.

If we had hundreds of thousands of perfectly taste aligned rankings, then we could automatically tune these values and maybe it could help. But remember, we've got a sparse data problem here. We don't have the kind of users that Netflix has.
Additionally, hand-tuned math weights doesn't really help solve subjective board game requests like “something pretty where I use cards.”
(4) The Specialized Reranker
I had heard about a startup called ZeroEntropy that was supposed to have an excellent reranker, and it seemed like it could perhaps help with the problem we were having with the Deterministic Scorer. It's a model built specifically to rank documents against a query. A reranker does exactly one thing: given a request and a description, it produces a match score. The goal here was to combine the Deterministic Ranker from the prior step, while still allowing some natural language like "i don't want a mean game."
It cannot chat, cannot explain itself, and does not know what a board game is, but it's way cheaper and more tunable than an LLM like Claude. It was a good system, however, it was not the best system in our comparison.
This is an important category of engineering result, in that it was fine, but I just found better things through iteration. Although we did move from this as the primary judge, we found this approach was quite good at doing group support so we use do use the signal still.
But in the end, we got better results just handing that signal to an LLM to make final calls.
(5) The Librarian: A Hard-Gated, Taste-filled, LLM Judge
The winner started from a different question. The day Anthropic's Fable came out everyone was talking about giving it big nebulous problems because the new model was great at exploring problems. So, I gave it access to all the academic research we had done and asked it a simple question, "why do AI models have bad taste when it comes to this problem?"
It didn't exactly spit out the answer, but from that discussion it was clear that maybe the problem wasn't lack of taste or judgement, but that we lack the vocabulary to describe something as nuanced as playing a game.
So instead of building a large scoring formula around every available signal, the challenge pivoted to figuring out how to generate better data, and handing it to the LLM in the right format. That took two forms:
- A structured taste profile for each member - think of it like a private player dosier that says "Jamie likes games that teach quickly, their favorite games are Jaipur and Mahjong." and so on.
- A private dosier of each game describing not the ratings, or hard constraints like number of players, but how the game feels to play. How luck based is it? Is it highly interactive with other players or like playing solitaire?
This handled our actual data sparseness much better. It also let us encode negative evidence. A one-star “Not For Me” rating is an absolute veto. Strong, well-supported opposition is so important for us: if a member’s history says they consistently dislike direct conflict, the table does not get a knife-fight negotiation game no matter how enthusiastically the other three would vote for it.
The group score then uses a geometric mean across members with confident profiles. This is related to the multiplicative strategies in the group-recommendation literature: one low fit pulls the result down more strongly than it would in a simple average. Three members at 0.9 and one at 0.2 average to a respectable 0.73; the geometric mean says 0.62, which is the arithmetic version of glancing at the fourth player’s face. We retain explicit vetoes for cases where “pulls the score down” is not strong enough.

So the Judge is misery-aware, but it is not literally least misery.
For our problem (a couple thousand games, a few hundred members, sparse ratings, and groups instead of individuals) I think a hard-gated LLM judge is the right shape: code owns feasibility and group math, a hand-built taxonomy supplies signal the internet does not have, and the LLM judges a bounded slate it cannot smuggle anything into.
It is still a system just a beta, if you will, but the results have been very promising and the best we've tested.
What the current system lets the LLM decide
The "Librarian" (a Hard-Gated, Taste Filled LLM Judge) is still an LLM system. We just gave the LLM a narrower job.

Here is what happens when someone makes a request.
1. Separate hard constraints from subjective mood
“Four players” and “under 60 minutes” become structured constraints. “Beautiful” and “driven by cards” become semantic intent. If the member uses the visible filters, those values are authoritative. The query-understanding model can interpret natural language, but deterministic parsing handles recognizable phrases and provides a fallback.
There is a real difference between “I generally like shorter games” and “the babysitter leaves at nine.” The database cannot infer the babysitter, but it can stop treating every number as a mood.
2. Gather game ideas from multiple sources
TurboPuffer searches the catalog. Player lists contribute games someone can teach, wants to learn, or enjoyed before. Collaborative filtering contributes games liked by people with similar ratings, when enough rating data exists. Reference expansion contributes games related to a title in the request.
3. Throw out games that don't match
The merged pool passes through deterministic constraint checks to form a "perfect" pool of games to pick from. If that pool is too thin, say it generates less than 40 games, then we have a "near-match" policy that can add a small number of close games that were close but not quite.
The LLM does not get to declare Lost Ruins of Arnak a 60-minute game through force of personality.
4. Compute fit for each person individually
Every member profile contains a distribution across our game classification, preferences across five gameplay dimensions, complexity and duration ranges, negative signals, and a confidence score.
For each candidate, code calculates how well it fits each member. It applies list and rating evidence, detects vetoes, finds teacher/learner pairs, and checks whether a difficult game has someone capable of teaching it. Stationfall is a great recommendation at a table where someone knows it, and a hostage situation at a table where nobody does.
Then it combines the per-member scores into a group score.
5. Reason on what people asked for
Stable taste is not the same as current intent. Someone who generally enjoys three-hour spreadsheet simulator may currently want “something light because I am tired.”
This was obvious to see after the Hard-Gated LLM Judge produced candidate pools that barely changed when you typed in different text. The profile signal was doing its job too enthusiastically.
Now, when the request includes text, the system blends group taste with query relevance before selecting the games for the LLM to judge. If you leave out mood text, it remains purely profile-led.
6. Ask Claude to rank a specific slate of games
Claude receives at most 40 eligible candidates, the member profiles, per-member fit, the request, and supporting evidence. It returns candidate indices rather than repeating long database IDs, ranks up to 12 games, and writes one short reason for each.
This is where LLMs are useful. They can compare several kinds of soft evidence at once and understand that “pretty cards” may refer to illustration, physical production, tableau building, or simply wanting to hold a hand of cards. They can also turn structured signals into a sentence a person might want to read.
7. Check its own work
Code then maps each returned index back to a real candidate. Invalid indices disappear. Duplicates disappear. Anything that failed the deterministic gate disappears. If the model returns too few games, deterministic ordering fills the remaining slots.
We also scan the reasons for internal vocabulary and incorrect product language. If Claude tells a member about their “aggregate fit,” “z-score,” or `teacher_gate`, that game gets deterministic copy instead. After all, members came to choose a game, not attend the recommender’s sprint review.
Finally, the system sorts perfect matches ahead of close matches again. Defense in depth is what you call doing the same sensible thing in several places because you have met software.
The useful data is the data we made ourselves
The largest general model does not know Tabletop Library’s collection as well as Tabletop Library does. More importantly, it lacks the vocabulary we need.
BoardGameGeek has an enormous amount of useful data: categories, mechanisms, ratings, complexity, player ranges, and descriptions. But categories such as “strategy” and “family” are broad. “Card game” tells you what components are present, but not what playing feels like.
BGG has also wrestled with sparse ratings, and its fix is worth knowing. Bayesian averaging is a popular technique—BGG’s Geek Rating uses it—because when a game has only a handful of votes, one person’s subjective opinion swings everything. So BGG seeds every game with about 1,500 imaginary ratings of 5.5, and real votes have to beat the ghosts. It is a good trick. It also felt like it didn’t get to the root of the issue: smoothing tells you how good a game is on average, not whether it is right for these four people tonight.
So we started to wrestle how to describe a games taste and feel. Thankfully, we'd already been working on Tabletop Library Classification System, or TLCS, to organize games by their primary form. It is our board game version of a library call-number system. A drafting game, a campaign game, a social deduction game, and a heavy negotiation game live in meaningfully different neighborhoods.
We also classify every game across five gameplay dimensions:
- Thematic depth: abstract, themed, or immersive
- Randomness: luck-driven, tactical, or skill-driven
- Player interaction: minimal, indirect, or direct
- Learning: intuitive, moderate, or heavy
- Tempo: light, thoughtful, or intense
These describe play rather than mechanics or marketing. A member may not know the phrase “multiplayer solitaire,” but they know they dislike spending 90 minutes building a private collection of cards while three other people do the same thing nearby never interacting.
So our member taste profiles now could turn each member’s ratings and lists into distributions across this vocabulary. A five-star rating or “can teach” signal carries more weight than merely having played something. Low ratings become negative evidence. The profile also records how much evidence it has.
This is our most important advantage. It is not really the prompt or even a model. It is a small, opinionated body of domain knowledge that does not exist anywhere else in quite the same form.
What is still wrong
The new recommender is better. But, it's also built on several suspicious facts.
- Balance between games we know you love, and new games. Yes, you may really love playing Mahjong, but that does not mean you want Mahjong recommended every single time. In fact, you might be in the mood for a new game. Right now we're still tweaking with how repetitive vs novel it is, how much it should use the Play List of games you are interested in vs find a discovery pick.
- How long does a game really take? Our catalog has a duration for each game, usually derived from publisher or BoardGameGeek data. This is useful but plainly very inaccurate. Eventually, duration should be a distribution conditioned on player count, how familiar the group is with the game, and whether someone can teach—not one integer printed on a box.
- What's the right player count? 1-4 players on the box can often mean playable at 1, but amazing at 3 players. BGG already collects community votes for whether a game is Best, Recommended, or Not Recommended at each player count. We'd love to integrate that into the rankings so you finding the best 3 player game for your 3 player game night.
- Did the recommendation work? Our evaluation mostly measures whether a recommendation looks relevant. The real outcome happens at the table when the game is picked. We have no doubt once we can actually connect this to real members picking the games, and then how they rate them afterwards, we can get better quickly.
- Does the list contain twelve versions of the same idea? Relevance tends to cluster. Ask for a medium-weight nature game and a recommender can return a tasteful wall of green boxes. Information retrieval has long used methods such as maximal marginal relevance to trade a small amount of pure relevance for diversity, and there is a related line of work on re-ranking away popularity bias. We do not yet apply either to the current system. We probably should. The nature of a library is a little bit of exploration, after all.
Did we make a recommender harness?
It would be satisfying to end by saying we replaced the LLM with good old-fashioned software engineering. We did not.

If we were trying to raise seed funding from our friends I'd probably call what we ended up with a harness. But since we are just a local board game store looking to break even, I'll put it in plainer language. The current system very much uses an LLM to understand loose requests, compare nuanced candidates, and write useful reasons. LLMs are just much better at weighing the kind of subjective choices inherent in board games than older ML recommendation systems.
What changed was the boundaries it operates in.
The model does not decide whether four is between one and three. It does not get to override a member’s “Not For Me” rating, or silently put close game matches above perfect ones. It chooses among candidates that we've decided it is great to choose from, using domain knowledge that the general internet does not contain, and then code checks the answer.
This was also the lesson for building software with AI agents that we'll likely take forward in other systems. Chatgpt can make a first recommender surprisingly quickly. It can wire up vector search, write the prompt, return a nice grid of cards, and add a tasteful loading state while it is there.
That is real progress. It is just not the same as knowing what a recommendation should optimize, and it's definitely not the same as knowing the difference between good and great.
The longer work was deciding which facts mattered, creating a vocabulary for taste, building comparisons that could themselves fail, and moving each decision to the part of the system best able to make it. I'm sure there's a lot more to evolve in that vocabulary as we keep building.
A system can only judge what it can name, so before anything (model or code) could weigh how an evening would feel, someone had to sit down and encode feel. From there it was great to see Claude had excellent taste, it just needed the language to understand what we want.
Which brings me back to the ridiculousness.
People have always poured unreasonable hours into esoteric things that make a small number of people happy. Every zine, every hand-painted miniature army, every homebrew RPG campaign lovingly written for an audience of six.
What’s wonderful is that custom software can be one of those things now. A recommender of this size and scale went from something a large corporation would fund, to something a local membership club could build just for the joy of it.
That joy still did involve a ton of hours making judgement calls and iterating -- despite the online hype about one-shotting everything with AI that was certainly not the experience here. But still, it is well within the scope of a hobby project all the same.
And if you build recommenders for a living and have been wincing since paragraph three: good, you’re the other reason I wrote this. Tell us what we got wrong. I’d love nothing more than an email that starts “have you tried…” as I suspect we'll have plenty more fun building this from here.
--
PS: If you want a four player, beautiful card game that plays in under 60 minutes, give Glow a shot.

---
Sources and further reading
What we read in May 2026, before most of the rebuild: Burke (2002) on hybrid recommenders; Sarwar et al. (2001) on item-based collaborative filtering; Cormack, Clarke & Büttcher (2009) on reciprocal rank fusion; Carbonell & Goldstein (1998) on maximal marginal relevance; Masthoff on group recommendation strategies; and Abdollahpouri et al. (2019) on popularity-bias re-ranking.
Plus the industry precedents: Spotify’s Discover Weekly (a hybrid explicitly to cover cold start), Goodreads’ ~20-ratings gate before collaborative filtering turns on, and BGG’s Bayesian Geek Rating.
For the longer history: Goldberg et al. (1992) on Tapestry; Resnick et al. (1994) on GroupLens; Shardanand & Maes (1995) on Ringo and “automating word of mouth”; Gomez-Uribe & Hunt (2015) on Netflix; Herlocker, Konstan & Riedl (2000) and Sinha & Swearingen (2002) on explanations and transparency; Hou et al. (2024) and Lichtenberg et al. (2024) on LLMs as rankers.

