Production Case Study · 2025 – Present

Most AI experiments live in notebooks.
This one lives in production.

A dynasty fantasy football site built from scratch that 16 real people use every single week to make real decisions. It's also a live test for figuring out where AI actually helps — and where it just gets in the way. Not a demo. Not a toy. A real app with real stakes.

Astro + TypeScript · MFL API Integration · Claude API · Structured AI Scaffolding · Dynasty Contract Engine
15+
Years of player salary data on file
$45M
Salary cap — exact, enforced, tested
2
Leagues on one codebase
0
Times AI touches the rule-based math
01

The Problem Domain

Why dynasty fantasy football turned out to be a perfect testing ground for AI

Dynasty fantasy football isn't the same game most people know. You don't redraft every year. You own players across multiple seasons, sign them to multi-year contracts, manage a salary cap, and plan your roster the way an NFL front office would — except you're doing it in a group chat at 11pm on a Tuesday, which is its own kind of decision-making environment.

It also turns out to be a great place to test AI, because two totally different kinds of problems are happening at the same time: ones with exact right answers, and ones that are more like educated guesses.

The salary cap is $45M. Not roughly. Not "around there." Going over disqualifies your roster. That's not a place for AI to weigh in — it's just math. But figuring out whether a 27-year-old running back is worth a 3-year, $9M contract? That involves injury history, usage trends, age, offensive scheme, and a dozen other things all at once. That's exactly where AI can help.

Hard Constraints
Salary cap: exactly $45,000,000
Roster limit: exactly 28 players
Contract escalation: exactly 10%/yr
Franchise tag rules: explicitly defined
Pure math. No AI needed.
Best Guesses
How fast players decline with age
What a fair trade actually looks like
What a player will actually sell for
Which free agents fill our biggest needs
AI helps here. Answers get checked.
02

How It's Built: The Big Separation

The single most important decision made early on — and why it paid off

The most important decision made early — and never changed — was this: keep the exact math completely separate from AI's judgment calls. Not just in theory, but enforced in the actual code. It sounds simple. In reality, it takes discipline to stick to as new features pile up and the easy answer is always "just let AI handle it."

The Math Layer TypeScript · Fully Tested
Salary Engine
salary-calculations.ts — cap math, salary escalation, dead money
MFL API Layer
Pulls data from the fantasy football API and cleans it up before anything uses it
Contract Logic
Handles franchise tags, expired contracts, and how much cap space they hold
Year Rollover
Figures out which year is "now" for league purposes — testable via ?testDate=
Clean Data Handoff
Checked, verified facts pass upward. AI gets clean information — not raw messy API responses.
The AI Layer Claude API · Guided · Checked
Trade Analysis
Figures out if a trade is fair and who's getting the better end of the deal
Auction Predictor
Past results + what teams need + how many players are left → price estimate
Free Agent Fit
Ranks which available players would help your roster the most right now
Decision Support
Summarizes the situation, lays out the options, flags what could go wrong
"Letting AI do the salary cap math would make the app worse, not better. The question isn't whether AI is smart enough — it's whether this is even the right kind of question to ask AI in the first place."
03

How AI Is Used

Every AI feature follows the same four-step setup — no freestyle chatbots allowed

Every AI feature on this site follows the same four-step setup. The goal is simple: always know what AI is doing, be able to check its work, and fix it when it's wrong. That takes more planning upfront, but it pays off.

1
Only Give AI What It Needs
Every time AI gets asked something, it only receives the data that's relevant to that specific question — not the entire database. Asking about a trade? AI gets that player's contract, your team's cap space, and some recent history. Nothing more. What information AI gets is a decision, not an afterthought.
2
Ask Specific Questions, Get Useful Answers
AI questions are specific, not vague. "Given this contract, age, and last season's stats — rate this player's trade value 1–10 and name the three biggest reasons" gives you something you can actually check. "Tell me about this player" gives you a wall of text that sounds plausible but is hard to verify.
3
Know How It Can Go Wrong Before It Does
Before any AI feature goes live, the ways it can fail are written down first. What does a wrong-but-confident answer look like? When should you not trust it? What happens if it breaks completely? Writing this down before launch means you're testing for problems you've already thought through — not stumbling onto them when 16 people are counting on the app.
4
Show Your Work
Every AI answer shows what data it used. A trade recommendation shows the salary numbers side by side. An auction estimate shows what similar players sold for in past years. If the answer is wrong, you can trace it back to bad data — which is much easier to fix than bad reasoning.
04

AI Builds It Too

AI isn't just a feature in the app — it helps write the app itself

The most interesting part of this project isn't any one feature. It's how the whole thing gets built. AI doesn't just power the features inside the app — it's part of the process of writing the code itself.

The AI Insights System is a running notebook of everything learned along the way — organized into files by topic (design patterns, API quirks, component rules) and by feature. Before every coding session, the relevant notes get loaded in. After, anything new gets written back.

This means AI gets smarter about the project over time instead of forgetting everything between sessions. It's not starting from scratch each time — it has notes. The knowledge stacks up.

The same rules that apply to using AI in the product apply here too: give it only what it needs, keep a clear format, and make sure mistakes get caught and fixed instead of quietly piling up.

AI Insights System
Task begins
↓
Load relevant domain + feature files into context
↓
AI executes task with accumulated project knowledge
↓
New learnings written back to corpus
↑ compounds
domains/design-system.md
domains/mfl-api.md
domains/frontend.md
features/trade-builder.md
features/auction-predictor.md
"The way the site is built runs on the same principles as the site itself: focused information, clear format, and a feedback loop that improves over time. How it's built is the point."
05

What We Learned the Hard Way

Two patterns that only show up when real people use your AI features for real

Two patterns showed up that you'd never catch in a test environment — only after a full season of real decisions with real consequences when the answers were wrong.

Pattern 01
Narrow Questions Beat Wide-Open Ones

Asking AI a specific question works better than asking a broad one. Not because AI is smarter with less to think about — but because a narrow question makes it easier to spot a wrong answer. "Rate this trade value 1–10 and name the three biggest factors" gives you something you can verify. "What do you think about this player?" sounds useful but hides bad answers until they've already cost you something.

Pattern 02
Bad Data Is Usually the Problem, Not Bad AI

When AI gives a wrong answer, the data fed to it is usually the culprit — not the AI itself. Outdated stats, a salary that's off by a year, a player who got traded mid-season. Given clean, accurate data, AI's reasoning is usually fine. This means keeping the underlying data accurate matters just as much as anything AI does with it.

06

Ship Small, Learn Fast, Repeat

The site is built the same way it works — one piece at a time, always with the next step in mind

The same approach used to build AI features is used to build the whole site: be clear about what you're making, ship something small, see how it works, fix what's broken, and repeat. Every feature is built to work together with the others — not as a one-time standalone thing.

The What's New section — which updates every week with real screenshots and plain-English explanations — isn't just documentation. It's a discipline. If you can't write clearly what changed and why it matters, you probably don't fully understand what you built yet.

Every piece of this site was built with the Auction Price Predictor in mind as the eventual goal. Features don't ship just because they work — they ship when they fit into the larger system. Being able to plug into other features isn't optional, it's a requirement from day one.

Foundation
MFL API integration Salary engine Roster hub Contract logic
→
Decision Tools
Trade builder Free agent view League planner Draft predictor
→
Analytics Layer
Salary MVPs Dead money League summary Historical analysis
→
Predictive System
Auction predictor AI trade framing Value signals Scarcity model
07

The Auction Price Predictor

What this entire system was designed to support

Dynasty auctions are one of the hardest things to predict in fantasy sports. You're not just asking "is this player good?" — you're asking "what will someone actually pay for this player, right now, with these 12 managers, given who's already been sold?" The same player can go for double or half the price depending on when they show up in the auction and how desperate people are at that position.

That's exactly the kind of messy, multi-factor problem where AI can actually help — as long as it's sitting on top of a solid foundation that knows exactly how much cap space each team has left, which positions still need to be filled, and what players have actually cost in previous years.

Every decision made building this site — how the layers split, how data flows, how shared tools are built — was made with this feature in mind. The groundwork is done. This is what comes next.

Auction Predictor: System Inputs
Historical Salary Data
15 years of what players actually sold for, sorted by year and position
Roster Context
Exactly how much cap space each team has left and which positions they still need to fill
Positional Scarcity
How many good options are left at each position as the auction winds down
Player Signal
Age, contract situation, recent performance, and what NFL team they're on
Output → A price range for what the player will likely sell for, plus how that affects each team's roster situation
08

Doing It All Yourself

When there's no one to hand off to, you learn every part of the system

Most teams have specialists. Designers hand off to engineers. Engineers hand off to data teams. Business people delegate everything technical. This project had none of that. Every part of it — design, code, data, AI, content, strategy — had to be figured out and owned by one person.

The result is that everything connects. How the site looks shapes how data is structured. How data is structured shapes what AI is told. What AI produces shapes what goes in the changelog. What's in the changelog shapes what gets built next. It's one system wearing different hats.

Design System Tokens
A full visual style system built from scratch — font sizes, colors, spacing, shadows — all stored as reusable variables. Both leagues share the same system, so fixing a design detail updates everywhere at once.
tokens.css · design-system.astro
Content Modeling
The What's New section isn't just a blog — it's a structured data format with required fields, screenshot rules, and an automatic weekly rollup. If you skip any of it, the build breaks.
whats-new.json · weekly-changelog-rollup.mjs
Front-End Architecture
The site is built with Astro and TypeScript. The same codebase powers two separate leagues — same components, same layout, zero copy-paste. PlayerCell, the Trade Builder, and the Player Modal are all reusable building blocks that work anywhere they're needed.
TheLeagueLayout · league-context.ts
Performance Engineering
Data from the MFL API gets downloaded and saved at build time, so most pages don't have to fetch anything when you open them — they're already done. If a page needs live data, it asks for it, but that's the exception. Fast pages, no waiting.
prerender = true · pnpm sync:all
Analytics
Dead Money Awards, Salary-Adjusted MVP, League Summary — these aren't just fun pages. They're built on shared math that other tools can reuse. The same salary calculations that power the Dead Money page also power the Trade Builder. Write it once, use it everywhere.
salary-calculations.ts · dead-money.astro
Building With Purpose
Every feature gets built because it helps someone win: better cap decisions, smarter trades, sharper auction bids. The game strategy and the build plan live in the same document — so the answer to "what should we build next?" is always the same: whatever makes you more competitive.
CLAUDE.md · Team Strategy section
Finding Your Voice
The What's New entries aren't just patch notes — they have a personality. Funny, specific, written like a person. There are actual rules about how to write them (yes, rules for changelog entries). Because if you can't explain what you built in a way that's worth reading, you might as well not have shipped it.
whats-new.json · CLAUDE.md writing style guide
Shipping Consistently
Every release shows up on the homepage for a week. Bug fixes get grouped and posted every Monday automatically. Screenshots are required — the build fails without them. The whole system is set up so that shipping something and telling people about it are the same step.
weekly-changelog-rollup.mjs · hero-resolver.ts
"These aren't separate skills that happen to live in the same person. It's one skill: understand how the whole thing works, own it from top to bottom, and just ship it."

The Bottom Line

The AI tools that actually work in the real world aren't better because they use a smarter model. They're better because of everything around the model: how the questions get asked, what information gets passed in, how the answers get checked, and whether anyone's paying attention when something goes wrong.

This project is proof of that. It's built in a domain where the rules are strict, the stakes are real, and 16 people are checking in every week to see if their team is still competitive. That's about as good a test as you can get.