I recently had Danny on to talk about Air, the web framework he and his wife Audrey have been building. Danny's someone I've worked with extensively - we did a lot of pairing together on FastHTML and other projects, and he's among the most brilliant developers I've worked with. His background includes work at NASA and Kraken, and he co-created the popular Django best practices book "Two Scoops of Django."
What struck me most about his approach to AI was that he uses it to drastically improve productivity with essentially zero budget for AI tools, yet still leverages AI effectively. He had some copilot and Gemini credits gifted to him, but that's it. Here's what I learned from his talk.
Since this talk, Amp Code has generously offered to help support their OSS work for air with free credits to use Amp. That happened after the talk, so Amp is not discussed here.
The Problem Air Solves
Danny started by explaining the motivation behind Air. As he put it:
"FastAPI is super powerful and again it has become really an industry standard and FastAPI is awesome. I love the framework. However, FastAPI in terms of serving out HTML pages is not great." - Danny
FastAPI is fantastic for JSON APIs - about a quarter of Python developers have used it, and pretty much every LLM service serves content via FastAPI under the hood. But when you need to serve HTML pages alongside your API? That's where things get clunky.
As Danny explained, you might want a landing page for your API, special API docs, or a billing system tied to API usage. All of this requires the ability to showcase your API to customers in a user-friendly way. Traditionally, you'd build a separate React app, but Danny wanted to stay in Python to avoid the cognitive load and deployment complexities of managing a separate frontend.
How Air Works
The beauty of Air is its simplicity. Installation is straightforward. Air is built on top of FastAPI and works with it seamlessly. Danny started by showing how to set up and install FastAPI and Air in a UV environment, and then provided an overview of setting up a Air app live.
Danny then showed us how to create a homepage with minimal code. He emphasized: "Air pretty much everything you need in air is in the root namespace. And this is just to make it easier on humans and LLMs.". He continued building cards, and links, but this screenshot shows how a FastAPI JSON API and webpage blend together quite naturally.
Danny explained that Air uses MVP CSS, "a really light and easy to use semantic CSS framework. So this is just sending out very vanilla or plain HTML."
This is an example of an air app I (Isaac) built:
Danny's Zero-Dollar AI Budget
Here's where things get interesting. Danny told us: "our budget for AI tools is zero." But he was honest about it: "it's kind of disingenuous that I've said the budget is entirely zero because we did get some free stuff."
They get some Copilot access because they're significant open source contributors. And as Danny explained, "because our email goes through Gmail and getting off of that would be a lot of work, we get some Gemini credits. It's not much, but that is helpful."
"So Copilot and Gemini are the actually the two tools I use," Danny said. "I have really enjoyed using Claude in the past. I just don't believe there's any free access anymore."
Since this talk, Amp Code has generously offered to help support their OSS work for air with some free credits to use Amp. That happened after the talk, so Amp is not discussed here.
Validating AI-Generated Code
"Being able to validate what it gives is so important, because otherwise you spend a lot of time debugging something"
This was perhaps the most important part of Danny's talk.
But he shared something even more concerning:
"what's worse, so much worse than hallucination is when AI gives you something technically correct, but it's bad. It'll run, but it's bad to the point of being dangerous."
Danny gave an example of someone who accepted payment gateway code from Claude that would delete customer accounts whenever there was any payment issue - expired cards, late payments, anything. "They happily accepted and didn't think through the implications because they would just kind of blindly accept stuff."
His approach to validation? Write tests. He discussed several cases where figuring out how to test things, and writing the tests were a great and helpful use of AI to make a code base higher quality.
Making Libraries AI-Friendly
Danny shared four key principles for making libraries work well with AI:
1. Shallow Namespaces
Danny admitted, "I personally am fantastic at memorizing deep namespaces. So for example, if we're talking about Django, I know where all the pieces are in Django.contrib.admin... But I observed early on in my career that not everyone is like this."
He found that "shallow namespace things seem to work better, especially for something that isn't in the global registry for LLMs."
2. Simple Type Annotations
"Type annotations make sure everything is as type annotated as possible. And on top of that, keep your type annotations simple," Danny advised. He suspects that fancy type annotations might struggle both humans and LLMs.
3. Good Documentation with Examples
Danny emphasized that "Air is extremely well documented. It could be better. We're making it better. But that has been one of our design goals from the beginning."
4. MCP Support
"Finally, a big thing that library creators can do is provide MCP for their stuff," Danny noted. Audrey is working on this for Air, though they're still figuring out how to serve MCP stuff using FastAPI.
Here are a couple of examples of heavy AI-assisted PRs I did when contributing to air. One is a Type hints PR and one is a documentation PR. I wrote about the experience doing the documentation PR in detail here
Practical AI Usage Patterns
"testing is a good example of where like you can actually use AI to make your code better because you can have better tests or thorough tests and more examples." - Danny
Another pattern he finds particularly effective: "Just because a function is generally easier to set up for testing than everything else... I'll be like, okay, I don't understand this. My brain isn't big enough, but I can understand small atomic pieces. Give me functions."
He also had an interesting perspective on "vibe coding": "The whole point of vibe coding is, you don't care what's happening under the hood. You're just doing it until it doesn't appear to break, right? And that's fine. There's nothing wrong with that." But he emphasized knowing when that's appropriate and when it's not. He acknowledged that using a vibe-coding style approach for brainstorming, or like interactive wireframing, can be helpful.
There are also different use cases to consider. Building a web development framework people will depend on, building medical diagnostic software, and making a static landing page, you just want to look nice and share a few details about yourself, all demand different levels of rigor.
Key Takeaways
Danny's approach to building Air demonstrates a pragmatic use of AI in development. He and Audrey have been building it quickly with AI assistance, but always with validation, testing, and a human in the loop checking that the output makes sense. They use AI as a tool, but always stay in control.
Awesome article! Looks like the more human-friendly a codebase is, the more AI friendly it is, too. Documentation, good typing practices, and general best practices is becoming less of a courtesy and more of a requirement if we want to maximize AI quality.