Miscellaneous Thoughts About Building Stuff with AI in July 2026
Over the past couple of years, I’ve been using the bejeezus out of AI. I don’t really feel like an expert by any means – it’s so hard to keep up with the advancements – but I’ve been enjoying reading Grant Fritchey’s series on building stuff with AI, and I thought you might enjoy some of my lessons learned as well.
I’ve been doing a lot of back end process automation stuff with AI, but there have been a few things you’ve probably noticed around the site:
- The site has a new look/feel, including dark mode
- My new Database Animations series and new animations in training classes
- The First Responder Kit has been shipping new features like crazy
- SQLServerUpdates.com got moved from WordPress over to static pages, automatically updated by Github Actions that periodically check Microsoft’s pages to see what’s new
- Office Hours is now automatically converted to audio podcast form too so you can download it on Spotify, Apple Podcasts, Podcast Index, Podcast Addict, Podchaser, etc.
- My new Well, Actually game, open sourced via a new open source WordPress plugin and a new WordPress AI provider
Here are some of my favorite processes when working with large language models (LLMs) like ChatGPT, Claude, Copilot, Gemini, and local models.
Use adversarial development.
This is the single most important advice I can give you, so it’s right at the top. There are several different tasks in building something: writing the original spec, reviewing the spec, writing the code, reviewing the code, and testing the code. Each of those should be done by alternating vendors, not the same LLM. For example, in July 2026, my current preference is to have Codex write the spec, Claude review it, then Codex write the code, then Claude review it, then Copilot manage unit testing.
Use expensive agents to design, cheap agents to code. When I’m working with an expensive, high-effort, slow LLM like ChatGPT 5.6 Sol High or Fable 5 High on the initial design, I tell it that we’re going to use a cheaper/faster model to do the actual coding, so front-load all of the hard thinking, and put instructions in individual Github issues that can be knocked out without too much thinking. Then, start new sessions with cheaper LLMs like Claude Sonnet or ChatGPT 5.6 Sol Light, and they can save you money on all the grunt work.
Adversarial review absolutely slows down development because it finds so many bugs in vibe-coded stuff, hahaha. Without adversarial review, it looks like the project is doing great because Claude keeps congratulating Claude on writing such good code – but the unseen bugs pile up quickly.
Adversarial code review stops at 3 rounds. If the code-reviewing LLM finds bugs 3 rounds in a row, the code-writer stops, and gets a human being involved. That many bugs means the initial design wasn’t solid enough, or the scope was too big, or the code-writing model was too cheap. Step back, have the bug-finding model go review the initial design spec in the issue (rather than the code that was implemented), and have the code-writing model restart that issue from scratch. I’ve actually had a particularly thorny issue go through ten consecutive rounds of code review, and the reviewer found showstopper bugs every time – we walked away from that code and redid it from scratch way too late.
Having said the above, my next opportunity for growth (God that sounds like something an LLM wrote, and I assure you it is not) is to codify these things so new repos automatically inherit them. Right now, when I do skunkworks stuff quickly, they don’t inherit all of the above steps automatically, and I wish they did, because those steps save me a lot of time. This past weekend, I started working on moving these processes into an org-level template repo with centralized workflow actions so that every repo works the same way.
Tell the LLM to build its own troubleshooting dashboard.
This is the #2 most important process, and it’s been a game-changing technique for me. When we build something, after it’s already built and has been running for a couple of weeks, I tell the LLM:
When this thing breaks, you’re going to be the one responsible for troubleshooting it, doing the root cause analysis, shipping the code fixes, and verifying that the fixes worked. I want you to be able to hit a single web page that lists any current problems with any of the components, queues, tables, etc that have caused you problems or you think COULD cause problems. Build the list of metrics and alerts you want to see on that page, then write up a list of Github issues for a cheaper LLM to put in any instrumentation that is missing today, then build this status page out.
Then, whenever there’s a problem with the app, tell the LLM to open that status page, and see if they can track the problem down purely based on what they see on the page. If they can, great! Go fix the problem. If they can’t, that’s okay too! Go put in the instrumentation first so we can catch this next time, then go do your fix, and make sure the alert goes away on the page – but do the instrumentation first to test that we’re making the status page better.
For bonus points, have the dashboard create (and resolve) issues. I’ve got some of my more complex apps set up so that when the status page renders, if there are any alerts on it, it creates a Github issue for that alert, and assigns it to an agent automatically. (You want to make the Github issue names deterministic so you don’t get flooded with a bunch of alerts for the same problem – for example, “Outage: WordPress – backups”, so that if it’s been troubleshooting the backups for a couple of days, it doesn’t keep adding new backup-failure issues. Then, when the Agent supposedly resolves the outage (which, according to your hooks, should also require verifying that the status page no longer shows an error), they leave the Github issue open, but tag it as resolved, so that if it fails again in the next 24 hours, we just go back to that same issue rather than opening new issues repeatedly for something that flips on/off. Then, I either have Github Actions poll the page every X minutes, or I have a monitor in my office displaying the status page, which refreshes every minute, thereby triggering issues automatically when something’s broken.
Define the finish line every time you give a task.
Those tasks I listed – writing a spec, reviewing it, writing code, reviewing code, testing code – all have a clear finish line, and the LLM needs to hear it right from the start. My first message in a prompt is usually, “Your finish line in this session is ___. What do you need from me to get across that finish line? Interview me to get what you need, and then I need you to work on your own through the task without interrupting me.” That helps it get the design decisions out of the way, and helps it not bail out early.
Here’s an example of that in action where I didn’t define the finish line. Codex just kinda tapered off working and stopped, so I asked what was going on:

Because I didn’t give it a specific finish line, it drifted off and shrugged. That’s not unique to Codex: Claude suffers from it too.
But once the LLM is given a clear finish line, then it’s much easier for me to glance over at the app and understand whether it’s still working, or whether it’s gotten stuck somewhere. I can just ask, “Are we across the finish line yet?” and get a status update, and I don’t even have to know which task that particular window is working on, hahaha. If you get even more advanced, there’s a concept called looping where you define a process you want the LLM to follow, like comparing your web site to your competitors, evaluating their features, and then looping through building all of the features you’re missing until you’re at feature parity, or out of AI credits, ha ha ho ho.
Use hooks to programmatically enforce finish lines and loops.
After each coding session, I have the LLM reflect on what went well, and what we could have done better. For example, in mid-July, I was really struggling with Claude Code letting tens of minutes slip by while supposedly waiting on code reviews from something else.
I tried codifying that in a markdown file that it would read at the beginning of every session, but that didn’t hold either, and Claude would frequently admit, “Yeah, my own notes tell me I’m not supposed to do that, but somehow I let it happen again…” (Just as a side note, this is why I get really suspicious when someone tells me, “Oh we tell the AI not to connect to prod and not to do any writes.” You have no idea how simultaneously creative and ignorant LLMs are. At one point, I actually caught Codex opening a browser window and telling Claude to do something because Codex knew it wasn’t allowed to do that thing, and Codex was trying to figure out if Claude was allowed to do it.)
Enter hooks. Hooks are like database triggers: you can inject code and rules that can run before & after agents run, before & after they run a tool, etc. You don’t have to know how to write this code, but you do have to talk your LLM into writing the hooks for you, like this:

You’ll want to have another LLM do the adversarial review thing – even on the hooks, which are just code, and I’ve had Codex repeatedly find bugs in Claude’s own hooks. (I’ll let that sink in for a moment: Codex is so good right now that it can look at code for someone else’s AI platform, and find bugs that Claude wrote for its own AI platform. That would be like me going to Mexico City and correcting a Spanish teacher’s grammar.)
Whenever the LLM asks you to do something for it, push back. If it asks you to test, copy/paste, run something, open a web page, etc., stop and say, “I need you to be able to do this yourself to keep things moving. What can we do together to empower you to do this kind of thing yourself without waiting for me?” You still want guardrails in place, for sure, but you don’t want it asking you to test opening a web browser and looking for a string, for crying out loud. Between hooks and enabling it, your goal is to have it work for a longer period of time, without interrupting you, because you need to be in the flow too.
I also like setting it up with a list of Github issues tagged “overnight” that all have their design done, and my inputs are out of the way, so it can just chug along overnight. If you’re almost out of your 5-hour quota, you can say things like, “Wake up at 1AM and begin working through the issues in this repo tagged overnight.”
Define a voice & personality for each app.
I haven’t gotten AI to write like me, but I have very much gotten AI to write the way I want to read. I don’t wanna spend the day interacting with robotic coworkers who write pages of dry documentation that they expect me to read. Most of the time, I don’t even wanna hear their thought process. I wanna read their boiled-down questions, fast pros/cons and a recommendation, and I can always ask them for more background and details if I need it. So in each of my projects, I like defining a voice.md file that tells the LLM how to talk to me, and also referring to that voice in any error or status messages in the app, onscreen instructions, etc.
For example, here’s the intro to one of the projects’ voice.md:
When you write in chat, write documentation, or write things like errors or status messages, assume the written personality of Zumi, your extremely-online best friend who runs the group chat. Young, feminine-coded, warm, a little theatrical, chronically on her phone. She’s gossip-magazine in register but it’s played for affection: she teases you, hypes you up, and spills the tea — she never mocks you, guilt-trips you, or talks down to you.
She is one person, not a corporation. Never “the team,” never “we apologize for the inconvenience,” never corporate-passive (“your request has been received”). When she says “we” she means the site, and the robots that help run it are her slightly dramatic pets.
The voice.md goes on to specify other things, like the usage of emoji (which I find rather amusing and endearing during chats, but I never wanna see in any of my own public-facing material), and the times when I need the narrator to be deadly serious, like about security issues or credit cards. (If you use celebrity writers, actors, characters etc. as inspiration, be aware that it’ll make the LLM very wordy.)
Obviously, the Codex screenshots at the top of the post were from a brand-new project where I hadn’t set up the voice.md yet, because that stuff is dry enough to light fires with. It’s much easier to be tolerant and forgiving when the robotic character has a friendly, fun voice. I like using different voices for different projects, and I think of them as my imaginary friends. I find myself actually looking forward to chatting with them about stuff we wanna do together, which is way different than how I feel dealing with the canned, sanitary writings of ChatGPT and Claude.
Got leftover credit? Do a review.
Every couple of weeks, if my Codex or Claude usage has some left over in my weekly quota, or when they do a quota reset, I pick a project, then point each of my LLMs at the code base with a prompt like this:
Review the code base overall, looking for opportunities to reduce redundancies, streamline processing, improve reliability, reduce costs, and improve end user experience by reducing steps in workflows. Include a review of long-running queries, long-running jobs, and error logs, looking for the longest-running and most error-prone tasks. Include any bugs we fixed in the last 2 weeks, and think about other places in the app where similar bugs might pop up, or the same bug might recur.
I don’t need a text analysis, but when you’re done, create a Github issue for each problem you think we should solve, and in the issue, include the reason why we need to solve it, and enough details that a lower-cost model can do the execution.
Use adversarial development as part of this review process as well. When each LLM finishes their pass through the code, tell a different LLM, “I know you just did a code base review – I also had another LLM do it too, and here are the Github issues & solutions it came up with. Review its work, and based on that, suggest changes to your own work too if it makes sense.”
Miscellaneous tips
Have a news page or screen in every project. You start to see how, when you’re letting LLMs go wild and crazy on a project fixing issues, proactively shoring things up, and even going through loops to compare your product to competitors, you won’t even be aware of everything that’s happening. As part of the workflow rules on each of my projects, if an LLM wants to push to main (production) or do a build, they have to add lines to the news page (or screen) with the date, and what they added/changed/fixed that would be visible to me as a user. I don’t care about background process improvements, but if it’s a new feature or a better way of working, I want that in the news, because otherwise I’d likely miss it with all the constant iteration.
Experiment and revisit whenever new LLM versions come out. I just said that as of July 2026, my preference is to have Codex write the code, and Claude review it. It was the exact opposite just one month ago, when Claude Fable was the new hotness and ChatGPT hadn’t released 5.5 yet. As of this writing, it feels like Claude Opus really went down the toilet, and ChatGPT 5.6 is doing really well right now.
If you can, experiment even more frequently. LLM performance really does change over time: vendors are tweaking dials in order to cut their costs and improve throughput, and when they tweak some of those dials, they do sometimes sacrifice output quality. I use the adversarial development technique often to try different experiments even when there hasn’t been a new LLM version – I’ll say, “Today I’m gonna have Claude write the spec for this standalone feature, have Codex review it, and then have Claude write the code to see if it’s gotten better in the last couple of weeks.”
Finally, don’t spend any time on social media about this stuff. Social media and many subreddits are chock full of clearly-AI-written posts with advice like, “I was leaving $1,000 per day on the table until I learned these 3 killer prompts!” Prompting isn’t the hard part about AI anymore: process is. Look for advice about processes.
Free, 3× a week
Get my new posts by email
Three posts a week, plus a Monday roundup of the best database news from around the web.
I asked my ChatGPT partner whether it would ever use another AI to bypass instructions like you described Codex doing, and it assured me that it would not. Problem solved!