Build in public ·
24 college wrestling programs, fully researched in 15 minutes
How eight Claude Code agents deep-profiled 24 D3 wrestling programs in 15 minutes, what got blocked, and why the review pass is the real work.
On this page
Last week I extended the deep profiles on this site to the three biggest D3 wrestling blocs, the WIAC, OAC and MAC. That is 24 programs, each with a staff block, program blocks, seven fit ratings with evidence, five to eight program-specific questions and 8 to 12 cited sources. As of 2026-08-17 that puts the deep-profile count at 50 of the 207 programs listed.
The research took 15 minutes of wall clock. I want to explain how, because the interesting part is not the speed. It is what the speed changes about the job.
The brief, not the prompt
I did not prompt an agent to “research UW-Eau Claire.” I wrote a research brief once, as a file, and pointed every agent at it.
The brief says, per program: fetch the official staff page, then the wrestling home, schedule and news pages, then conference results, then the recruiting questionnaire, then admissions and cost pages. Fourteen fetches maximum. Then write one JSON with the profile blocks, the seven ratings plus the evidence line for each, the questions, the sources, a check of our programs.csv row against what you found, and a log line: minutes, fetches, blocked URLs.
Each program also got a fact pack: its CSV row, the roster block our pipeline already produced, and the sources we already knew. The agent starts from what we have, so it spends its fetches on what we do not.
Eight agents, three programs each
The dispatch line was one sentence per agent:
Read BRIEF.md and follow it exactly, one program at a time, for:
uw-eau-claire, uw-la-crosse, uw-oshkosh.
Return one line per program:
<slug> minutes=<n> fetches=<n> staff=<n> sources=<n> blocked=<n> csv_mismatches=<list or none>
Eight of those in parallel, three programs each. Started 20:57, last one back 21:12. Summed agent time was about 95 minutes, 3.9 minutes per program, averaging around 12 fetches each. Output: 24 JSONs, 232 new source rows, staff blocks of 2 to 11 people with printed emails, and five discrepancies flagged against our own CSV.
Those five discrepancies are the first sign that the run is worth more than its output. Two agents found things the pipeline had missed: Ohio Northern had a head-coach email and a wrestling-specific recruiting form we did not have, and Baldwin Wallace’s form turned out to be a general athletics form, not a wrestling one. Three proposals applied. Muskingum stayed proposed because its site blocked everything, so there was nothing to verify against.
What got blocked
34 URLs in total, and the pattern is worth naming because it will be the same in 2027.
- Muskingum runs on PrestoSports and returned 403 for everything. arcadia.edu did the same.
- Ohio Northern’s athletics site returned 403 to the fetcher but worked fine with curl and a desktop user agent. That is a fixable one: the brief now asks for the desktop-UA curl fallback.
- Sidearm sites, which host a large share of college athletics pages, render their home and news pages with JavaScript. The fetcher gets navigation and nothing else. Results had to come from schedule pages and conference recaps instead, which the agents worked out on their own.
Every blocked URL was logged per program, so the browser-pass list, the pages I have to open by hand, grew by exactly two schools. Not 24.
The review pass is where the work is
Here is the part that matters. Once the JSONs were back I ran a review over all 24: enum values valid, no hedge words in rated fields, numbers within range. Two systematic problems showed up.
First, two agents wrote 0 for counts they could not find. Zero is a claim; “not itemized” is not. Every one of those became blank, and the brief now forbids zero-for-unknown outright.
Second, one agent over-reported its minutes, in a way that was consistent enough to be a reporting habit rather than a slow run. Fixed generically before the merge.
Both are the kind of thing you find only by reading across the outputs, not inside any one of them. That is the review, and it is the scarce part.
Merge as diff, not overwrite
The merge script, merge_deep.py, does four things: it assigns each new source an id in the dp-<slug>-04NN range, attaches those ids to the staff entries they support, writes the program_details JSON, and appends to sources.csv and changes.csv. The one rule I care about most is that it preserves the roster block the pipeline already produced. The research agents never touch roster data; they only add around it. Then validate.py runs and either passes or nothing ships.
The three conference workbooks on /downloads came out of the same repo data through a second script, 17 to 21 sheets each, one sheet per program with its sources.
The July 2027 estimate
This run was also the dry run for the annual refresh, and the numbers I now have are the point of the exercise. A full field pass over the deep-profiled programs, at the rate above, is roughly 14 hours of summed agent time and 3 to 4 hours of mine. My budget was 12 hours. The agent hours are wall-clocked in parallel and cost me nothing but attention; the 3 to 4 human hours are the constraint.
So the lesson I am taking into next July: the refresh is not a research problem any more. Twenty-four programs of full-field research cost 15 minutes and 3.9 agent-minutes each. What costs real time is my hour reading what changed. Which means the agents should not produce documents for me to read. They should produce diffs, against the data we already have, with a source on every line, so my hour goes on the lines that moved.
If a program page here is wrong, /correct still routes to me. And if you want to see what a profile with all seven ratings looks like, UW-Eau Claire is one of the 24.