Your codebase is NOT ready for AI (here's how to fix it)
Chapters7
Explains how AI exerts constraints on codebases and why quality and correct design matter for AI outputs.
Design your codebase with deep, well-defined interfaces so AI can work fast, test reliably, and avoid cognitive burnout.
Summary
Matt Pocock argues that the biggest limiter to AI collaboration in code is the codebase itself, not the prompts or tools. He stresses that the way you structure modules and their interfaces determines how AI interacts with your system, impacting feedback speed, traceability, and cognitive load. Pocock introduces the concept of deep modules and graybox boundaries drawn from a philosophy of software design, where big, well-encapsulated interfaces guide AI through your system while the inner implementation stays protected. He illustrates how a misaligned file-system layout can cripple AI comprehension, leading to brittle changes and confusing cross-module dependencies. By organizing your code into clearly defined services (e.g., video editor service, thumbnail service) with explicit public interfaces, you enable progressive disclosure of complexity for AI and reduce the mental burden on humans. He also notes that technologies like TypeScript/JavaScript complicate strict boundary enforcement, but tools like Effect can help create better modular boundaries. Finally, Pocock emphasizes applying modular design and strong testing from planning through PRDs to ensure new AI-driven contributors can work effectively without destabilizing the codebase. His core message: software quality has always mattered, and it matters even more when you’re integrating AI-assisted development."
Key Takeaways
- Deep modules with simple, public interfaces let AI interact with your code without needing to understand every internal detail.
- Organize the codebase so the AI can inspect the interface first, enabling progressive disclosure of complexity and faster feedback loops.
- Reduce cognitive burnout by consolidating logic into a handful of well-defined service boundaries (e.g., video editor service, authentication), not as many tiny shallow modules.
- Use graybox modules where the internal implementation can be ignored unless needed, with tests that lock in behavior and allow AI to operate at the interface level.
- Effect and similar tooling can help enforce modular boundaries in TypeScript/JavaScript, making it easier to design AI-friendly architectures.
- Apply modular interface design during planning (PRDs and implementation issues) to ensure the codebase remains testable and navigable for both humans and AI.
- Remember: a well-structured, well-tested codebase is the best onboarding for new AI-driven contributors and reduces cognitive load.
Who Is This For?
Software engineers and engineering managers who are adopting AI copilots and automation; ideal for teams building AI-assisted workflows who need to harden their codebases for reliable AI interaction.
Notable Quotes
"AI when it first goes into your codebase… has no memory. It’s like the guy from Memento who just steps in and goes, ‘Okay, I’m here. Uh, what am I doing?’"
—Illustrates AI's lack of internal context and the resulting need for strong module interfaces.
"The file system design needs to match the internal map you have of your codebase."
—Emphasizes aligning mental model with actual code organization for AI usability.
"We need to stop thinking about AI as a superpowered developer… it’s a new starter in your codebase."
—Reframes expectations and stresses accessibility for new AI-driven contributors.
Questions This Video Answers
- How can I structure my codebase to be AI-friendly with deep modules and clear interfaces?
- What are graybox modules and how do they help AI interact with a codebase?
- Which tools help enforce modular boundaries in TypeScript/JavaScript for AI workflows?
- Why is progressive disclosure of complexity important when enabling AI in coding projects?
- How do PRDs and implementation tasks change when preparing a codebase for AI collaboration?
Deep modulesGraybox modulesPublic interfacesProgressive disclosure of complexityAI-friendly code architectureEffect (tool)Typescript/JavaScript modular boundariesSoftware testingPRDs and implementation planning
Full Transcript
AI imposes super weird constraints on your codebase. And most code bases out there in the world, probably including yours, are not ready. Your codebase, way more than the prompt that you used, way more than your agents.mmd file, is the biggest influence on AI's output. And if it's designed wrong, it can cost you in a bunch of different ways. It can mean that the AI doesn't receive feedback fast enough. So, it doesn't know if what it changed actually did what it intended. It can find it super hard to make sense of things and find files and work out even how to test things.
And finally, it can lead you into cognitive burnout as you try to hold together AI and your codebase and patch it all up and keep everything in your mind. And my thesis here is that software quality matters more than ever. In other words, how easy your codebase is to change makes a huge impact on how AI then goes and changes it. And the stuff that we've known about software best practices for 20 years still holds more true than ever. And if you're interested in getting better at this stuff, then check out my newsletter, AI Hero.
I teach you all about AI coding, but this is not for vibe coders. This is for real engineers solving real problems. And if that's you, and you're not sure how to handle these new tools, then you are going to love it. Now, let's imagine that this here is our codebase. Each one of these little squares represents a module. And this module might export some functionality. It might export a function, might export some variables, might export a component if it's like a, you know, a React or a front end thing. I want you to imagine that this is the image of your codebase that you hold in your head.
Now you might inside here have some vague groupings of different functionality. For instance, here you might have let's say a thumbnail editor feature and all of these different modules contribute to that. Over here you might have a little video editor feature or something. Down here is all the code related to authentication. Up here is a bunch of CRUD forms for updating stuff maybe in a CMS. And over here are a couple of example features that I can't be bothered to think of examples for. Now, this map that I've created here of all of the located modules in this particular codebase, they're not actually reflected that much in the file system.
They're all really jumbled up together. If I want to just grab, let's say, an export from this module and import it down into this module, I can. There's nothing stopping me. And so, what you might end up with is a bunch of kind of disperate relationships between stuff that doesn't actually relate to each other. Now, you as the developer understand the mental map between all of these modules, but what the AI sees when it first goes into your codebase is this. It doesn't see all of the natural groupings and all the natural relationships. What it sees is a bunch of disparate modules that can all import from each other.
That's because AI when it jumps into your codebase, it has no memory. It has not experienced your codebase before. It's like the guy from Momento who just steps in and goes, "Okay, I'm here. Uh, what am I doing?" So, my first assertion here is that you need to make sure that the file system and the design of your codebase matches this internal map that you have of it. This is because if you describe something over in the video editor section and you use it via a prompt, then you want the AI to be able to find it easily.
The AI won't go in knowing every single function, every single module and what they supposed to do and how they link to each other. And the best way I have found to do that is with deep modules. Now, deep modules comes from this book here, which is a philosophy of software design. And the idea is that in order to make your system easily navigable and easy to change and also easy to test is that you have a deep module so lots of implementation controlled by a simple interface. What that looks like in terms of our graph is instead of many many small modules you end up with these big chunks of modules with simple controllable interfaces and this means that any exports from these modules have to come from that interface.
Now when I read that about deep modules, I immediately thought about putting AI in control of these modules because this is an opportunity to introduce a kind of seam into the codebase. I don't really care about what's happening inside here which is the implementation. I just care about what's happening in the interface because the interface which is you know the publicly accessible API of this module I can carefully control and I can apply my taste to and design and then the stuff inside here I can just delegate to an AI to control and I can write tests that completely lock down the module in terms of its behavior.
So these are not just deep modules with simple interfaces, they're also graybox modules. In other words, I don't actually need to look inside these modules. I can if I want to, if I want to influence their outcome or if I need to apply some taste to the implementation or I need to improve their performance or something, but as long as the tests are good, then I don't really need to care about what happens inside. Now, this has three massive benefits. The first one is that I can make my codebase way more navigable. Let's for the sake of argument just call each of these services, right?
The video editor service, the thumbnail service, whatever. If I document these each inside their own folder and I have the publicly accessible interface kind of like uh really obvious in a type section, then the AI when it's exploring my codebase, it can see all of these different services on the file system. It can read and understand the types that they export before it actually looks at the implementation. And then it can say, okay, I've seen the interface. I understand what this does. I don't need to look inside because I can just trust what it's returning.
In other words, we've designed our codebase for progressive disclosure of complexity. The interface sits at the top and it just explains what the module does and then when we need to we can look inside the module and make changes to it or look at it to understand its behavior more deeply. The second one is that we reduce the cognitive burnout of managing this codebase. Now as a user I can just go right I need something from uh I don't know this madeup feature or let's say the authentication bit over here. Let's say what let's see what the public interface is.
Let's just grab that and use it. And instead of needing to think about the inter relationships between all of these modules, I can just keep kind of like seven or eight lumps of stuff in my head and go, okay, the AI manages the stuff inside that. I only need to worry about designing the interfaces and how they fit together. Now, this of course is still a million miles away from vibe coding because you need to apply taste at the boundaries of these modules. You need to be really good at deciding, okay, what goes into that module, what goes into that module.
And what you really want to avoid are lots of little shallow modules, which is kind of what we had up here, right? Each of these modules is just like, sure, it's kind of interrelated and grouped together, but really they're lots of tiny shallow modules which are testable in these tiny units which are really hard to keep all in your head. And so by simplifying the mental map of the codebase, we reduce cognitive burnout that comes from managing this codebase. And again, this is nothing new. This is a 20-year-old software practice. And the third one here, I mean, I'm really just repeating myself, but this is what we've been doing all along.
This is how good code bases have supposed to have been designed. So, what works here for humans is also great for AI. We need to stop thinking about AI as like this superpowered developer as like, you know, it's going to reach AGI and understand that it's got some weird limitations. And the limitations that it has are that it's a new starter in your codebase. So you need to make your codebase friendly and ready for new starters because you're going to be spawning like 20 new starters every day or probably more just to look at your codebase and make changes.
So that means the map of your codebase needs to be easily navigable and it needs to be enforced by using these modules. Now some languages make this easier than others. For instance, in Typescript and JavaScript, it's actually not that easy to make these services make these modules uh sort of boundaried in this way. I want to give a quick shout out to effect because uh I posted a video on effect a few months ago. I'm actually using effect way more than I did back then and it makes this kind of um sort of seeming modularizing of your codebase really simple.
The final thing I want to say here is that you need to be thinking about these modules and how you're affecting them and how you're designing the interfaces in every coding session that you do. That means right from the early planning stage when you're writing your PRDs or when you're turning your PRDs into implementation issues, you need to be thinking about the modules that you're affecting and the interfaces and how you going to test them because tests and feedback loops are essential for an AI because of course they're essential for a new starter joining the codebase.
If you want the new starter to contribute effectively, you need a well- tested codebase so they can see what their changes do as they ripple out. So that's my rant for today. your codebase is probably not ready for AI because you're not using enough deep modules and instead you've got a web of interconnected kind of shallow modules like this which are really hard to navigate and really hard to test and really hard to keep in your head. Now, if you dig this then of course you will dig my newsletter where we go more deeply into topics like this.
Thanks for watching folks. What else do you think goes into making a great codebase for AI? I really love this metaphor for deep modules but I know it's not the only one going. There are plenty out there. Thanks for watching and I will see you very soon. So, when you're thinking about your codebase with AI, what are you thinking about? What kind of 20-year-old books do you want to recommend? Leave it in the comments. It's the easiest way to keep up with all of my stuff and the link is below.
More from Matt Pocock
Get daily recaps from
Matt Pocock
AI-powered summaries delivered to your inbox. Save hours every week while staying fully informed.



