A daily log of MLB playoff odds from two independent models, plus each morning’s games and a short written recap for every team. It exists because playoff odds are published as a snapshot — every source shows you today and forgets yesterday. Recording them daily turns a number into a trend, which is the part that actually tells you something.
cron 6am → freshness check →
scrape 2 sources → Postgres →
Claude: recap + preview → static page
Fetching, parsing, storing and verifying are plain Python — cheaper, reproducible, and when they break you get a stack trace instead of a confident wrong answer. Claude is called at two points, both writing prose from numbers the scrapers already verified: a recap of yesterday, and a preview of tonight that may search the web for news no table of ours contains. Both are instructed never to invent a statistic, and the preview is told to trust our figures over anything it finds. If a model is deciding what the data is, the design is wrong. It should only decide how to say it.
Thirty summaries a day is roughly 10k input and 5k output tokens — cents. The interesting constraint was never price. It was making sure the numbers handed to the model were right in the first place.
The shape — schedule, collect, store durably, verify, then use a
model for the one step that needs judgment — is not specific to baseball. Swap
the scrapers and the prompt and it is a bot for prices, listings, deploys, or an
inbox. The build notes and the traps worth knowing are in
ARCHITECTURE.md, and every prompt and setting actually used is visible on the what we send to Claude page. The design tokens and components every page shares are catalogued on the
styles page, and every page and
endpoint this app answers is indexed on the
routes page.