← Back to work

PersonalLib

Your reading history plus your library's catalog — the right book, available right now.

Context
Built for AI Agents, UCLA Anderson MBA
Role
Solo
Stack
Python 3 (standard library) · Streamlit / Jupyter front ends · Claude Code
Status
Prototype — live demo below

The problem

Recommendation lists tell you what's popular, not what you'll like — and even when you find something, you don't know whether your library has it or whether you're facing a three-week hold. PersonalLib answers both at once.

What I built

A recommender that reads a Goodreads CSV export, builds a taste profile from the books you rated 4–5 stars, and returns a ranked table of new titles. Each row has a plain-language reason, a note tying it to your history (“next in a series you're reading,” “you rated Book Lovers 5★”), whether it's a standalone or part of a series, its Libby availability, and a color-coded action: Borrow now, Place hold, or Save for later. It runs as a CLI, a Jupyter notebook, or a Streamlit app — the hosted demo runs the recommendation engine directly, no setup needed.

The screenshot below is a run against the sample reading history:

Screenshot of the PersonalLib recommendations table with title, author, why, Libby availability, and a borrow-or-hold action per row
Screenshot — ranked recommendations, each with a reason, library availability, and a Borrow / Hold / Save action.

How it works

Taste profile. CSV rows become structured book objects; genres and authors are counted with star ratings as vote weights, and series progress is tracked.

The recommendation engine. Every candidate in a curated database is scored on genre fit, author affinity, and series progression — with a penalty for a mid-series book whose earlier entries you haven't read, and a bump for a high average rating. Already-read titles are filtered out, and the top-scoring results are returned. It's fully deterministic — same input, same output, no API key. (The Jupyter notebook also carries an experimental GPT-4o-mini variant I built to sanity-check the rule-based scores against; the CLI and the hosted demo are the engine only.)

Availability cross-reference. Each recommendation is looked up in a mock Libby dataset (status, wait weeks, library) and turned into the Borrow / Hold / Save action.

Evaluation rubric. Every recommendation is scored on four dimensions — taste fit, actionability, accuracy, clarity — each 0–10, summed to a score out of 40, so runs can be compared.

Iterative user control. There is no ground-truth label set; the user swapping the CSV or adjusting the count is the quality signal. A daily background job can fire a macOS notification when a watched book becomes available.

PersonalLib system workflow diagram showing inputs, processing, scoring, availability lookup, outputs, and the evaluation rubric
The full pipeline, as mapped in the notebook version — inputs, scoring, the availability lookup, the scored output, and the evaluation rubric.

What I learned

This was a chance to design a full workflow from scratch — figuring out what data the system needs, where to source it, and how to turn it into a recommendation someone can actually act on. The experimenting was the fun part: where good data lives, and how to use it well enough to make a better call.

It was also a useful reality check. As the next section notes, there isn't a real API for live library availability yet, so a production version isn't feasible today — but the pipeline is a working blueprint for when that data exists.

What I'd improve

Real Libby / OverDrive availability and a much larger catalog (Open Library or Google Books); LLM-based genre inference from descriptions instead of relying on shelf tags; collaborative filtering and automatic series-chain suggestions; and Goodreads OAuth instead of a manual CSV export.