I spend my days meeting with founders and my nights building tools for them. Mostly systems to monitor + optimize their revenue engine, and some recent AI tools I’ve been building to keep up with their competitors.
Everyone asks me how I use AI. You must define terms, provide baselines, add constraints, and intelligently engineer the context to win with AI. But what exactly does that mean?
I charge 5-figures to discuss that with organizations for 3-hours in a workshop environment. I also provide personalized “how do I get value from this AI thing” tutoring starting at $600/hr to business owners, execs, creators and the builders in between.
Building with AI and working with frontier firms is a unique position that gives me a ground-level view of how the most elite engineering teams operate. Over the past year, I’ve witnessed a fundamental change in the craft of software development. A new term entered our lexicon: “vibe coding” which is the alluring idea that you can build complex software through casual, conversational prompts with an AI. It’s powerful, it’s fast, and in the hands of the undisciplined, it’s incredibly dangerous.
You can’t just vibe code a bridge, and you certainly can’t vibe code the mission-critical systems that venture-backed companies are built on.
The allure of speed often masks a truly terrifying lack of rigor, leading to architectural drift, inscrutable bugs, and mountains of technical debt. Yet, the velocity is undeniable. So, the critical question becomes: How do we harness this raw power without sacrificing the discipline that separates professional engineering from hobbyist tinkering?
Building with AI
Over the last eighteen months, I’ve developed a specific, structured workflow that I use to build software for my portfolio companies and side projects for myself. I engineered this system because I wanted the power of AI without the peril of determinism.
It’s the same system I now see being adopted by the fastest-growing and most effective engineering teams I know. It’s a method for augmenting human intellect, not replacing it.
The results?
My companies are shipping complex features more than 30% faster than they were a year ago AND they can explain the engineering choices being made. This is how you build with AI without betting your company on a black box.
Before we get to the system itself, it’s important to understand the landscape. This is an area that is changing very rapidly, and it is easy to assume we all are “up” on the basics… but let’s take a quick second to set the table.
For years, the canonical debate among developers was about their core environment: the raw, scriptable power of the Command Line Interface (CLI) versus the rich, all-in-one convenience of an Integrated Development Environment (IDE).
That debate is now largely settled: the best engineers are fluent in both, understanding them not as competitors, but as complementary forces.
I was always on team “why not use both?”.
My terminal is my orchestration layer. It’s where I interact with the nervous system of modern development: running scripts, managing Git repositories, deploying containers with Docker, and interfacing with cloud services. It’s for precise, repeatable, automated tasks.
My IDE, on the other hand, is my cockpit. It’s the deeply immersive environment where the creative work of coding, refactoring, and debugging happens. The intelligent autocompletion, graphical debuggers, and seamless integrations create a state of flow that the raw terminal can’t match. A modern engineer flows effortlessly between the two, using the right tool for the job.
Now, a third layer has descended upon this stable ecosystem: Artificial Intelligence. This AI layer is not just another tool. It’s a meta-tool that fundamentally changes how we interact with both the CLI and the IDE.
This series is going to lay out these layers.
In upcoming articles in this series we are going to look at Codex from OAI and pair it with Cursor, an AI-powered IDE. We’re also going to look at other CLIs and IDEs so you can get a survey of what’s possible.
Then we will focus on the process of developing an application using these tools, and I’ll share tricks and tips.
For now, let’s focus on the process and the thinking behind the each step in it.
Failing to Plan is Planning to Fail
My process for building any new feature no longer begins with opening a file in my IDE. It starts with a conversation. I open a dedicated interface to a powerful large language model, like Gemini 2.5 or GPT-5, and I start talking to it.
My goal in this initial stage is not to get perfect, production-ready code. That’s a rookie mistake. My aim is to generate a robust scaffold to get about 70% of the way there on the structure and boilerplate without getting bogged down.
I’m incredibly specific in this conversation. I provide the full context: the tech stack we’re using, the existing architectural patterns the new code needs to adhere to, the precise requirements of the feature, and even the format of the output I expect. For example, I might say, “Generate a new service in Go for managing user profiles. Use our standard repository pattern with a PostgreSQL backend. Provide the GORM model, the repository interface and implementation, the service layer logic for CRUD operations, and the Gin router setup for the API endpoints. Ensure all error handling follows our established pattern of returning a JSON error object with a status code.”
The AI’s output from this prompt is a massive head start. It saves me hours of typing out repetitive patterns. It generates the models, the controllers, the service layers… the entire skeleton of the feature. This initial code is my raw material, a well-formed block of marble ready for sculpting. The inertia of a blank page is gone, and I can immediately move from construction to refinement.
Once I have that scaffold, I bring it into my actual development environment, which these days is an AI-native editor like Cursor. This is where the workflow shifts from a monologue with the AI to a dynamic, interactive dialogue. This is the most crucial transition to understand. I am no longer passively receiving code, I am actively co-creating it with my AI pair programmer. The key, as one of the best senior engineers I know put it, is that I can watch the AI write the code.
I can ask it why it did it that way, what trade-offs the system considered, what alternatives exist…
This real-time feedback loop is a game-changer for catching the inevitable flaws in AI-generated code. As the AI streams its response, I can spot logical errors, inefficiencies, or “hallucinations” aka instances where the AI confidently invents a library function that doesn’t exist. That’s when intervene, correcting its course. I highlight a function and ask it to be refactored for clarity. I select a complex block of business logic and ask it to generate a suite of unit tests covering the edge cases. I point to a section and ask, “Is there a more performant way to write this?” The IDE’s context-awareness of the entire project means the AI’s suggestions are far more relevant than those from a generic chatbot. I am in full control, using the AI for bursts of speed and inspiration, but my hands are always on the wheel.
Now we arrive at the part of the system that sounds redundant on the surface but is, in my experience, the absolute cornerstone of building durable software this way. I use a second AI to review the code that was co-created with the first AI. It’s a principle of redundancy, like having two different specialists review a critical blueprint. Different AI models, trained for different purposes, excel at catching different classes of errors.
My quality assurance process now has two automated layers before a human colleague ever sees my code:
First, running locally within my IDE, I have a tool like Coderabbit’s extension. It acts as a hyper-vigilant linter and static analyzer, providing real-time feedback as I type. It catches subtle code smells, potential performance bottlenecks, and common security anti-patterns on the fly. This ensures the code is clean and adheres to best practices before I even write a commit message.