№ 530301March 2026 · Amherst, MA
HerdSearch
Natural language search for a self-updating alumni directoryProblem
Amherst College’s Alumni Directory (like almost every alumni database) is a static, significantly incomplete collection of the community’s professional history with an outdated search algorithm.
Solution
HerdSearch fills in what a directory misses, using only information people have already made public about their work, so a directory stays current instead of going stale the day it's exported. The Amherst community can ask a question in plain English and get the most relevant people, each with a reason. They can also connect their own AI assistant to search it. It was built for Amherst alumni and works for any organization.
Building rich alumni profiles from public data
Each alum has been written about in articles and posts on LinkedIn. The web has a bunch of public information on their professional history.
A roster row is a name and a class year. The waterfall runs a web search plus Claude extraction first, and Claude reports a match only when it can verify the person; a people-data provider is tried only on a miss, and its answer is kept only when a multi-signal confidence score clears. Results are stored as columns, embedded per facet (role, expertise, education, full profile) and indexed for BM25 keyword search. It uses only what people have already published about their working lives: roles, companies, bios, press. Nothing is fetched from behind a login. Admins run enrichment in bulk per network, re-run failures, compare providers on the same person, and can edit any entry or hide it from search.
Natural language search
The model never touches the database; it turns your question into fields and filters, and code does the searching.
A question becomes structured fields (role, industry, company, school, skills, achievements) plus hard filters such as class years or a 50-mile radius around a geocoded city. Each field queries its own embedding, BM25 and full-text search run alongside, and reciprocal rank fusion merges the lists into one ranking. Separate embeddings per facet were the fix for one vector blurring a question like 'Stanford MBA in fintech' into either half. The answer names the best matches with a one-line reason each, and members can upload a resume so results lean toward their own background. Claude through the AI SDK does the understanding; Postgres with pgvector does the finding.
This system works for any college or organization
Any school or chapter can live on its own subdomain with its own colors, logo and front door.
Every network lives in one Postgres database, isolated by row-level security and its own vector index, and is resolved from the subdomain in middleware. One codebase, one deploy, one cookie domain; a new school or chapter is a row in a table plus a DNS entry. The front door can be fully open, a trial code plus your name, or a contract code. Members save people into lists, and an admin console shows usage per network. The lesson: run local development on a production-shaped domain from day one, because browsers refuse shared cookies on *.localhost and the admin-to-tenant hop silently logged you out locally.
Deterministic cost visibility
Every paid call is logged with its real price, and one click can never run away.
Every model, web-search, people-data and embedding call writes one ledger row at the provider boundary, with the cost the provider reported or its published unit price, tagged by section and user, so the total reconciles with vendor invoices. Paid routes check a per-user daily budget before they spend and answer 402 past it. One click can fan out to a thousand people times four providers, so the ledger came before any dashboard. Rate-limit and quota responses write a zero-dollar row of their own, which is how the console knows a key needs upgrading before anyone notices a failure.