"Is the output from your coding agent garbage?" Well, it's probably because the system that you have designed is not all that great. And the better you can make the system that the agents work in, the better the output is ultimately going to be. Now, the system I'm talking about is actually composed of a bunch of primitives that allow your agent to work effectively. And the more that your agent has to either guess at or create its own primitives as a part of doing some other work, the less likely you're going to end up with some output that you're happy with. So these primitives are really everything. So we're gonna talk about that. This is Better with Kent, where we learn durable skills together to get better together. And today we're going to talk about how we can make our agents much more effective working in our projects. Now, this is actually not totally different from the way it's always been. Like tech lead was always responsible for building this system so that the individual contributors could be really effective inside that system. However, now we are all the tech leads because we've got agents working from ourselves inside of the systems that we design. And the scarce work that is the thing that's really valuable now for a product engineer is that system design. So your goal is to build like a playground for agents to operate in and safely along with the tools so that they can accomplish the task that you set them to in a most efficient and effective way. So let's define first what a primitive even is. So there are a whole bunch of different system areas. And really a primitive is the smallest unit of meaning that your system exposes. So it's like composable pieces without having to re-implement how each individual piece works. So there are a lot of different areas of this. So there's like the UI and design side of this that'd be like your components and your tokens, like buttons and text fields and spacing and all of that stuff. And without it, you're going to end up with a UI that just has all sorts of different colors and spacing and it's just gonna look really bad because the agent kind of has to make it up as it goes. You've got API and backend primitives. So this would be like the resources and the verbs that can be applied to those, like a post to the orders endpoint or canceling a subscription. And without this, then the logic is going to be duplicated and re-implemented all over the place. And you're not going to end up with a reliable system and you'll find yourself having to chase down bugs all the time or repeating yourself a lot. So having very solid primitives as far as the resources available and things that's really valuable. Related to that is your data primitives. So the different entities and the relationships that those entities have with each other, like a user and an order and order line items, all of that thing. So without that, you're going to end up with ad hoc shapes and agents will just have to guess at the different relationships that those things are going to have. So you really want to nail those types of primitives down as well. You have infra related primitives like platform related things. So for this, it'd be like how you do cron jobs and how you store the data and where like distributed systems are hosted, all of that different things. So like where you're deploying things, how you manage secrets, all of that. And without this, then your agent ends up just trying to guess and oh, whoops, I deleted the production volume and there goes the database, like not great. And related to this too is the agent and tools. And if the agent doesn't have really good callable tools, then you're going to end up with possibly deleting that volume or just writing one off bash scripts, which is gonna make your agent a lot less efficient and repeatable in the long term. And then also there are primitives around the workflows and like repeatable pieces. So you've got like a retriable capability built in or something like that. And if you've got a good primitive for that, then the agent isn't going to have to manually code in all of that work as well. So this can also be not just the infra side of things, but the libraries that you're using as well. And then finally, the authentication and trust side, like permissions and that sort of things. You need to have good primitives for that, like role-based access control or that sort of thing that will help you make sure that you don't like give god mode keys to the different agents that are using your system or your own agent using your own system. And also you're going to lack in audit trail potentially. And so those primitives being built from scratch or from the start is really important. And I don't mean you have to hand code those and now your agents can play. You can use agents to build those pieces, but you need to be very intentional about those pieces existing and not having too much overlap and all sorts of things. So let's talk a little bit about the different things that you can do with primitives to make sure that the playground that you've created for your agents to play in is actually a safe one that will result in good outputs for you. So first you need to create the primitives obviously, but then throughout the entire lifetime of the project, you also need to combine primitives together. And you like have to be really ruthless about this. Like as a new need for a new primitives shows up, is that just an existing primitive with a different shape? Or maybe over time you actually have these two primitives and you realize, you know what? Those are basically the same sort of thing. So you want to combine those primitives. Sometimes you realize, you know what? Nobody's using these features anyway. We're gonna delete these primitives. And other times you want to expand an existing primitive. And sometimes you may have a primitive that is like really close to this one. And so you're going to delete that one and expand this one to cover that use case. That's kind of like combining primitives as well. So let me give you some specific examples of when I've done this in the past. So first of all, like when you are missing a primitive, the agent is gonna find a workaround and the workarounds are gonna be broad and brittle and hard to audit and they're gonna be localized to a specific area and so you'll like recreate primitives over here. So you just need to have the good primitives in the first place. An example of this is recently I was adding to CODI these community packages. And so you can have a package inside of CODI that is then put onto like this public registry that other people can then use as a reference and they can fork it and use it in their own instance of CODI. And as I was building this, I realized we were missing a really important primitive and that is adamant versus a user. So I need to be able to review those and make sure to like de-list things if they should be de-listed. So there's a different role and different permissions that I need to have versus the other people who are using CODI, assuming that this ends up being something that I have multiple users on. At the time of this recording, I don't, but maybe in the future I will. I'm kind of putting together the pieces to make that possible. And I think that community packages is an important part of that, but without having admin and user roles with different permissions, then that's not going to work out. And so before I proceeded implementing that, I decided to make a new agent that would implement the role-based access control primitives that I needed so that this other agent could be more effective. And it's really tempting to just be like, oh yeah, we're missing that primitive. Go ahead and build that and then go forth and build the thing that you're focused on. And I have done that before, but for something like RBAC, I decided, you know what? We're gonna make an entire new agent. We're gonna put you responsible for this. And feel free to let me know if you want a video on how I did that because that was actually pretty interesting as well. And that was merged just today. So you need to make sure that you have the right primitives and that they do exist before you go and let the agent just run wild. Now on the side of combining primitives, I have some examples of this as well. Even long ago when I was working over at PayPal, I was working on the cross border transaction. And so you'd type in your friend's email address or whatever it would come up with selection. And that's called a combo box, that UI. And I looked around the code base to see, okay, how do we do combo boxes in this code base? And it turns out that we actually had three implementations of combo boxes. 'Cause we also had a combo box for selecting the country that you were sending to and the currency. And there were like a couple others. There was another place where you could enter your friend's email address, but that was not cross border transaction. So like we had a whole bunch of different combo box components. And I decided, you know what, this is bad, not just for agents, this was before agents. It was bad for everybody. And so instead I decided, okay, we're gonna sit down, we're gonna implement a really good primitive for this. And that ended up becoming downshift, which is an open source library that I implemented and now is actually widely used as a combo box or enhanced input library. So that became really valuable. And then I was able to implement it across all three of those. And we were all moving much more efficiently. So the fewer concepts that you have to know about for both humans and agents, the better. It's just fewer things to reason about, fewer things to think about. So you do want to very intentionally combine primitives as much as you possibly can so that there are fewer things to mess up. Another more recent example is in CODI, my AI assistant MCP server. I used to have this concept of skills. So it used to be that you just like CODI would write some code and then if I liked that code, I would save that into D1 in the database. And anytime that we wanted to reuse that and we could just call that a skill and we would just run that code again. It was really simple. But then Cloudflare released Artifacts, which is effectively GitHub or Git repos inside of Cloudflare. And so I said, wow, that's a lot better because we can do so much more and we can like bundle in the durable object. And like, there are so many other things that we can do with that. So I built up a new packages primitive and merged in that idea of skills into the packages primitive. And in fact, I was able to also merge in this concept of saved apps that was already existing in CODI as well, which were like apps with a UI and endpoints and all of that stuff. All of that got slurped in to this one primitive of packages and that's been really, really efficient and effective for me. So combining primitives, super powerful. And then occasionally you actually need to delete primitives. And I've got a really interesting example for this one. So Instagram originally was a four square clone called bourbon, which had a more like alcohol focused niche that it was trying to carve out. And as they watched users use their service, they weren't really popping off. Like it just wasn't working super well, but they watched users use it and they realized that the thing that they were enjoying the most was the photos part of it. And so they started deleting primitives. They got rid of a whole bunch of features and just focused solely on the photo sharing. And we all know that Instagram did quite well with that decision. So sometimes removing things is actually a really good call. And again, it kind of comes back to the idea that you have fewer things that the agent could possibly do and that reduces the number of things that the agent might use that it shouldn't be using. So you do want to trim and get rid of the fat. And sometimes this does relate to specific features, but other times it really is just about the primitives that are available. So another example from Cody, I used to have the ability for receiving an email and processing it with all of the MCP tools, like the execute and everything, all of those tools. We'd have a couple agent turns so that then we would respond with like having accomplished whatever was asked. And then I realized that this was like a little bit too specific and too rigid for what I really wanted. So instead I deleted that and replaced it with a simple event system. So now when an email is received by Cody, it just publishes an event and your package can subscribe to events. And so I expanded the package system, which actually gets into our next piece beyond delete is expanding. So as part of deleting that old primitive of email handling and just like really just kind of shrinking it down to a tiny little thing that just sends subscriptions or sends events to subscribers, packages expanded just a bit and that replaced an enormous, like actually a really significant piece of primitive that handled those emails. And so now anybody who's using Cody can just create any number of packages to handle emails and it can look at the like, "Oh, this doesn't have the right subject, so I'm gonna ignore it." Or, "Oh, let me process the body contents. Okay, great, now I can do something with it," or whatever. And so it's a lot more powerful because we got rid of that rigid primitive before and gave much more flexible primitives. And at first you might think, "Well, Kent, that means that it's a little less helpful and I have to build things myself." Well, this is called inversion of control and it ends up being a lot more powerful even if it does result in a little bit more work. And luckily when it comes to code, we're not actually doing a whole lot of the work anyway, so this ends up working out really, really well. So by narrowing email down to just emitting events and packages being able to subscribe made this primitive a lot more simple and made that combination of those two primitives really, really powerful. So you wanna combine these primitives. So with all of this intentional work on your primitives, you're going to end up with really good primitives that shrink the available space of action, what the agent has to decide on what to do by having really solid and intentional primitives that you're putting together. And you want these to be composable pieces so that the agent can take these different pieces and put them together to create something really great rather than just having an improvised script for this or a randomly hacked together UI for that, whatever. And it makes it a lot easier to audit the use of different primitives in infrastructure or auth or whatever because the system is really well shaped. It just makes the agent that much more effective. So primitives, it really that's like one of the things that matters the very most. And so that's why we're gonna get to your homework here. And that is, I want you to just ask your agent in your code base, say, what are the primitives that currently exist in the system? And what should we create or combine or delete or expand among these primitives? What's missing? What looks kind of the same? What needs a little bit more so that it can be more powerful? That is your homework. And like the agent is the one that's playing in the playground. So you may as well ask the agent and see, how do you enjoy working in my code base? And then you execute your judgment to decide how you're going to evolve this system because you understand where this product is going, what the product vision is, all of that. And you can use that to convert it into a really great system that can help you get to that place much faster. This has been better with Kent where we learned durable skills for people who build and ship really great software. So hopefully you've learned a little bit about how to design a system that agents enjoy playing in and are much more effective and you have much better output from those agents. So my hope is that you talk to your agent about creating and destroying and combining and expanding the existing primitives until you're happy with them. And this is a process that you never stop. So keep going on that. And while you're at it, go ahead and like, comment, subscribe and share and we can continue learning durable skills together. Thank you so much for getting better with me.