
The outdoor festival, the free concert downtown, the thing the kids would have loved. I hear about all of it on Monday, after it's already over.
My wife is home with the kids all day, I work from home, and between us we are constantly hunting for something to get everyone out of the house on the weekend.
So I built an agent to look through all the local events this weekend and summarize ones my family would be interested in.
It took an evening. It works. Then I read what it gave me, and saw what it left out.
I live in Knoxville, so that’s what I pointed it at. But almost none of this is about Knoxville. Every city has a "what's on" page or three, and they all break in the same handful of ways. The recipe travels, and I'll give you the whole thing at the bottom so you can aim it at your own town.
What I actually wanted
What I wanted was small: this Friday night, Saturday and Sunday, ranked, family friendly on top, with the time, the place, and whether it costs anything. Something I could read on Friday morning and start planning around.
The finding events part turned out to be the easy half. The two hard parts were getting in to the sources, and deciding what's actually worth my family's time. That's every build like this, and it's where the whole post lives.
Three sources, three completely different fights
Here's the useful thing I learned, and the reason this works for your city too. I found that the local event data came in these three shapes.
The official calendar that has a real feed and hides it. My city's runs on an old government CMS, just a rendered month grid with no download link. But behind the little "subscribe" button, the kind you'd click to add the calendar to your phone, sits a real iCalendar feed, a clean machine-readable list of every event.
Follow it to the .ics URL and it's the best source by a mile: 418 structured events, no scraping, no guessing. Most cities' official calendars hide a feed like this. It's just never the first thing you see.
The page that's just HTML. The downtown site has no feed at all, just events laid out in a web page. So you read it like a page. Find the repeating block, pull out the title, date, location, and link. Fiddlier than a feed, but honest work, and it gave me 77 listings.
The page that looks scrapeable but isn't. The tourism site was the wall. It looks like a normal events page, but fetch it and there are no events inside, just an empty container the JavaScript fills later from a private feed.
I found that feed and asked it politely for this weekend's events. It answered: 403 — Invalid credentials. It wants a key the page hands it at runtime, and I don't have that key.
That's a fork in the road. I could have dug the key out of the page's code, or run a fake browser to scrape what it renders. People do. But this is a public site I'm reading for my own weekend, and reverse-engineering a credential to get in crosses from "reading a public page" into "breaking into a private one." So I skipped it, and the agent notes the source unavailable and moves on.
Which means one of my three sources contributes nothing. Hold onto that.
Same discipline with robots.txt, the file where a site says what automated visitors can and can't touch. The agent reads each one before touching anything and honors it. All three were fine; if one hadn't been, skip it, don't sneak around. The goal isn't the data at any cost. It's to build something I'd be comfortable telling you I built.
The part I didn't write: the judgment
This build was different from the others I've built. Before, the hard part was code: reverse-engineering an API, wiring up endpoints, checking the model's work. The model built; I checked its wiring.
This time the model isn't the builder. It's the judge.
Think about what "family-friendly" actually requires. Almost no listing says so. A farmers market doesn't, a scavenger hunt doesn't, but a person knows instantly they're fine for kids, and that a late brewery show isn't.
That's the whole product, and exactly what a keyword list can't do. Search for "family" and you'll miss the farmers market and match a "family-style dinner" that's really a wine pairing.
So I didn't write a scorer. I let the model be the scorer. The code does the boring half: fetch, cache, dedupe, keep only this weekend. Then it hands the pile to the model with one plain-English description of my taste:
Family-friendly is the top priority. I like outdoor, live music, free or low-cost, and lower-key over big and crowded. Late-night, 21+, and bar-centric events are a poor fit.
The model reads each event the way I would and scores it: kid-appropriate (0–2), fit with my taste (0–3), and one line of why.
That's the reusable idea, and it's bigger than weekend events. When the hard part of a task is taste, stop trying to encode it and let the model apply it. Give it the context and the standard in plain words, and get out of the way.
What it looks like when it works
Here's what it handed me for this weekend, the Fourth of July weekend as it happens:
Top picks for the family
Festival on the Fourth · Sat 5:00 PM · World's Fair Park · free. The city's free, all-ages Fourth party, with live symphony and fireworks. The one honest caveat, which the agent flagged, is that it's the crowded one, which cuts against my "lower-key" lean. Worth it once a year.
Market Square Farmers Market · Sat 9:00 AM · Market Square · free to browse. Easy, all-ages, low-key morning downtown. (Showed up on two of my sources under slightly different names; the agent merged them.)
Where's Waldo Scavenger Hunt · all weekend · downtown shops · free. Self-paced hunt for Waldo in storefronts. No ticket, no schedule, made for kids.
Eastside Sunday Market · Sun 12:00 PM · Dr. Walter Hardy Park · free to browse. A smaller neighborhood market, the relaxed Sunday counterweight to Saturday's crowds.
Also worth a look
US Road Running (5K / 10K / half marathon) · Sat 8:00 AM · Holston River Park · race fee, free to cheer.
I never logged in or configured anything, and the weekend's in front of me before it happens instead of after it's gone. That's the demo, and it's a good one. Now let me argue with it.
Why "it works" still isn't "it's right"
The problems that scare me don't crash. They look right, the way this list looks right, with a whole source missing and nothing on the page to say so. There are four kinds of soft spot in it, and not one announces itself.
The big one: one of my three sources is gone, and I can't tell how much left with it. The tourism site 403'd, so everything that lives only on Visit Knoxville dropped out. That's a third of my way into the city, closed, and how much of the real weekend it took is something I have no way to know. The digest shows five events like five is the whole story. A clean list is the most convincing lie a tool can tell, because completeness has no error message.
The subtle one: it trusted the flyer. That road race I filed under "worth a look" scored family-friendly because the listing calls itself "Family Friendly." An 8:00 AM half marathon isn't a kids' outing. It only stayed out of the top picks because it didn't match my taste, not because the model caught the problem. The model reasoned around the label instead of at it. It even wrote a line about the kids coming to cheer, without ever stopping to ask whether an 8:00 AM half marathon belongs on a family list at all. It took "family friendly" as settled and built on top of it, and left a non-kid race sitting there as a family option. Change one detail so the race fit my taste, and that same misplaced trust would put it straight in the top picks. The one thing I built this to avoid walked right back in the moment the data described itself. Same trap as the fantasy football agent that lied to me.
The date-window ones: it dropped a real event and nearly kept a fake one. Friday night was in what I asked for, but the default window came back with Saturday and Sunday and quietly skipped First Friday ArtWalk, probably the best family thing all weekend. And "City Offices Closed" rode in on a date overlap, a holiday closure, not an event, until the model set it aside. It caught that one this time. Next time it won't.
The quiet one underneath: it's only seen an easy weekend. I've tested this against a single holiday weekend, when everything skews wholesome. The whole promise rests on the agent demoting the 21+ and bar stuff, and this weekend there wasn't any. The part that protects the idea has never fired. I've watched it say yes to a farmers market. I haven't watched it say no to the thing I'd regret.
So it works. "Works" means the plumbing holds and the taste is plausible. It doesn't mean the list is complete, or that a self-described "family" event is one, or that the judgment survives a messier weekend. It's less wrong than finding out on Monday. But less wrong is not right, and knowing the difference is the part I can't automate.
Build this yourself, in your city
What actually transfers here isn't Knoxville, or even weekend events. It's the shape: a few messy public sources, deterministic code to gather them, and the model as the judge of what's worth your time. Point it at your own town.
Time: an evening.
Cost: $0. No paid APIs, no keys. The judging is done by the same agent that builds it.
Stack:
Claude Code as the agent. It writes the plumbing and does the scoring.
curland a few lines of shell to fetch and cache the raw pages and feeds.Python standard library only for the parsing and dedupe (
zoneinfo,re,json,difflib). Nothing to install.
The method:
Find your three sources: the official city or government calendar, the tourism or visitors-bureau events page, and a downtown or neighborhood events page.
For each one, figure out which of the three shapes it is. Official calendars usually hide a real iCal/RSS feed behind a "subscribe" button, so follow it. A plain HTML page, you parse. A page that comes up empty when you fetch it is loading its events from a private feed. Try that feed, and if it wants credentials, skip it.
Normalize everything to the same record, filter to this weekend, and merge duplicates by fuzzy title plus date.
Hand the cleaned list to the model with your taste written out in plain English, and let it score and rank. Don't write a keyword filter.
The prompt I used
Swap in your city and its three sources. The constraints at the bottom are the whole lesson. Keep them exact:
Build me a command-line agent that finds things to do THIS WEEKEND in
<YOUR CITY> and hands me a short, ranked digest with family-friendly on top.
Sources (find your city's equivalents):
- the official city/government calendar
- the tourism / visitors-bureau events page
- a downtown or neighborhood events page
Rules — these are the point, keep them exact:
- Check each site's robots.txt first and honor it. Skip any source that
disallows the events path instead of working around it.
- Some feeds are hidden behind a "subscribe to iCal/RSS" button. Follow that
to the real .ics/.xml URL rather than scraping the rendered page.
- If a source loads its events from a private/credentialed API or a JS widget
you can't reach without a key, SKIP it and say so in the output. Do not
reverse a login or run a headless browser to break in.
- Cache every raw fetch; one fetch per source per run; use a descriptive
User-Agent.
- Normalize everything to {title, start, end, location, description, url,
source}, filter to this weekend, and dedupe on fuzzy title + date.
- Score each event by JUDGMENT, not keywords. Read the title, description,
venue, and time and infer, the way a person would: a family_friendly score
(0-2), an interest_fit score (0-3), and a one-line why. A farmers market or
a scavenger hunt reads all-ages even if it never says so; a late brewery
show does not. Do NOT trust an event's own "family friendly" label — judge
from the details. When genuinely unsure, score 1 and say so.
- Rank family-first. Drop anything not kid-appropriate to a "maybe skip"
section. Print time, place, and cost on every line ("cost unclear" if the
source doesn't say).
My taste (edit to yours): family-friendly is the top priority. I like outdoor,
live music, free or low-cost, and lower-key over big and crowded. Late-night,
21+, and bar/brewery events are a poor fit.
Point it at your town, read it Friday morning, and see what it hands you, and what it leaves out. If you build one, hit reply and tell me which of your city's three sources fought back hardest. I'm betting it's the tourism site.
— Ben