Refactoring Legacy Codebases
Join Lee Robinson, VP of Developer Experience, to hear how he migrated cursor.com from a CMS to raw code in 3 days. The project cost $260, took 344 agent requests, consumed 297M tokens, and resulted in 67 commits across 1023 files, with zero site downtime and weeks saved off the projected timeline.
Terms in this video
Transcript
Yes, this is Lee from Cursor Learn. If you haven't seen Cursorlearn, please go check it out after this. If you want an intro to more of the AI foundations, I'm guessing if you're here though, you probably understand it at least a little bit. But if not, no worries. We can we can cover that as well in another session. But for today, I want to talk about migrating existing code bases, some of the tips and tricks that we've used at Cursor, where we're headed in
the future and where coding agents are headed in the future, and then we'll actually just make a plan to migrate a codebase live and kind of see what that looks like, uh, and play around with it and talk through some of the trade-offs. So, let's get into it. Please feel free to continue dropping in the chat where you're tuning in from. I'll have the chat open and I'll try to answer things as they come up or we'll have time for Q&A at the end as well.
So, where this all started was a tweet that I had and the tweet was uh I migrated cursor from a CMS to raw code and markdown. I thought it would take a few weeks but actually was able to get it done pretty quickly and I wrote up this blog post about it that seemed to resonate with a lot of people. I think because they were all adjusting their worldview to the latest coding agents and the latest models and the capability jump that is now possible especially for
migrations. So in this blog post I talk a little bit about how we were questioning some of the decisions whether we needed these abstractions. Do you need the CMS? Do you need these layers between the code? This was one type of migration. Although this could be legacy code uh programming language to a newer programming language or old dependencies that are out ofd and have security vulnerabilities that you need to move off but it's like 10 layers
deep in the backlog and you just haven't prioritized doing it. All of those things fall into this category of do we need them abstractions in our codebase? Are they helpful or are they hurtful? And now that it is more doable for us to do a migration, could AI help us do that in an effective way? So that was where we started. And I have a whole rant in this post if you want to learn more about why I was fed up with the CMS. But the more interesting part to talk about
today is how we actually did the migration. So I want to start with if you have not used the latest generation of models, you should consider giving them a shot. This is Opus 4.5. This is GPT 5.1 or 5.2 soon. Codeex Max Extra High. I don't make the names. Don't shoot the messenger. I don't I don't know. I'm I'm trying I'm trying my best there with the names. But those are the the two models that are the latest and greatest right now for for long horizon or long running tasks. So, if you haven't tried those
out, especially in a multimodel harness like cursor where we optimize each model inside of our harness for using these tools uh and these these models, it's worth giving a shot because you'll have a drastically different experience than if you use the previous generation of models. Um, one thing that was really interesting here that I hadn't previously thought about was asking the agent to go and extract data from me from existing systems and then turn that into files on disk because the agents can then read
those files on disk which was really really really helpful and when you do that it makes it much easier to then allow the agent to iterate towards a goal. So, while I'm kind of explaining this, let's actually kick off a plan and we'll kind of talk through some of this stuff at the same time. So, I have two things open here. The first one is the uh cursor website codebase where we're going to talk about this in a little bit. But on the other side, I found a
random repository on GitHub, PG Vector, and it's written in C. and they might decide that they want to migrate this repository from C to something a bit more modern like Rust for example. My number one tip or any migration is you need to start with a plan. In general, I would recommend doing this for any larger size feature that you're doing inside of a coding agent like cursor. So you can um you can tab shift tab to plan or you can hit it from the drop down. Um you can go into plan mode
and I can say uh let's migrate this codebase to Rust. Now you can think about plan mode like a prompt optimizer. You don't have to specify everything up front. You're going on this journey to work with the model to figure out what you want to do in an interactive way to create a artifact, a plan, a markdown file that you can make sure is good before you actually go write the code. So, first the agent is going to go research the codebase. It's going to look at the files. It's going to understand how it's
structured. This could be Cobalt. This could be like 2012 JavaScript codebase. This could be C. It could be, I don't know, vera log. It could be anything, right? And it's going to come back to you and it's going to ask you questions. What type of migration do we want to do? Do we want to do a full rewrite? Do you want to do hybrid, standalone? And part of this is a business decision.
Part of this depends on your level of confidence with coding agents. In general, as you're getting more familiar with these things, I wouldn't recommend trying to shoot for a entire rewrite in one shot. it's just probably not going to happen. Uh I have some tips we can talk about the end where models are getting better at doing some of these things with some tricks, but generally it's going to take multiple runs. To do the migration that I did, it took many
runs and I had repeated patterns that I was able to use. So let's do hybrid. Goal of this migration is um let's do memory safety. I think Rust does a good job with that. And then we should start with this feature set. We're not going to do kind of full feature parody. We could just start with this. So now that I've answered some questions, I've refined what we're doing. It's going to go and actually figure out a plan for how we would do this. The repository size does not
matter. In fact, for larger repositories, cursor gives the agent really powerful tools that allow it to go search through the codebase and find the relevant bits of code. So if you scroll up here, you see explored a directory. So it's reading files. It's understanding. It's thinking. Uh, and if you look here, it's again thinking about what it wants to do. It's exploring directories, reading files. Um, it's using tools like GP, so it can read specific parts of files. It can also do semantic search if it decides that it
needs to ask for a more generic thing like where is the main C function at? Well, maybe it's not called main.c, maybe it's it's somewhere else. um it's going to go and it's going to give you back this plan. Now, one of the really nice things about cursor and and planning is I'm just going to uh pull this over a little bit. Actually, we have a guey that allows you to iterate and change uh iterate edit and iterate together. Iterate uh it allows you to
edit and iterate on the plans in a guey and it also supports mermaid diagrams which are pretty helpful. So we've got this diagram of how it's thinking about doing the migration. It lists specific files that we need to migrate, functions that we need to migrate, um build integration code changes. Um, now the key thing for this to actually work well is you have to give the agent verifiable outputs. It could go generate a bunch of code and that code might not work. So
you need to know that you can allow the agent to generate code and verify that it works. Now increasingly the models are getting good enough that when you make a plan, it usually makes code that works. But they're not perfect. They still make mistakes. So if you give the models verifiable outputs, they can fix their errors and work towards that plan. Now the reason I picked this repository for one reason was it's C. The second reason was they have tests. So if you
search for test, they have all these different um test files which is great. Those tests can then be used to validate and verify that the migration was successful. The agent can take advantage of a good combination of determinism and non-determinism. Determinism is like a script or a code mod that can change files, which is great. And then non-determinism or probabilistic behavior of an AI model is it's coming up and it's generating code on the fly.
And we want that too. We need both of those things. And the agent because it has access to tools like running shell commands, reading things from your repository, reading files, it can go in and it can do a very good job with that migration. So that's that's kind of how this migration started for me moving the CMS off. So we started with the plan, we started iterating on the plan and I was pretty impressed by how far it got in the plan. Now once I started uh
iterating, some of the things didn't work. Some of the pages were not a perfect match. And one of the things that's very nice with the integrated browser and cursor or you can just hook it up to Chrome externally if you want. You can do a prompt like this. the features page is not a perfect match.
Review how we exported the data and then keep iterating with the browser. Take screenshots until it's a perfect match, which is a good reminder that you can add screenshots into the prompt input here. You can paste in a screenshot and you can do at browser like this and it will actually use this browser like we have on the left and the agent is able to control that browser.
It's able to read console logs, network logs. That was how I built this entire interface. So, I started doing that, creating a plan, which I just showed here a little bit. But also, a feature um that should be out for everyone uh in the coming weeks is you can ask it to use sub agents to do things in parallel.
That just speeds up the process a little bit. Um however, I have another trip uh tip at the end we're going to talk through for speeding up the process. But then in the process of deleting all this complexity, I decided I'm just going to make more things while I'm here. And one of them was this asset manager. So what you find is that in the process of migrating a codebase, removing a bunch of abstractions and getting to this new state once you get comfortable with
working with the coding agents, you realize you can ask for new things that are a lightweight, explicit, tailored version of exactly what you need and nothing else. So we needed an asset manager. I could have used a SAS product. I could have used something off the shelf. I just built this very minimal version that works for us. Probably five or 10 prompts, changed it to be exactly what we needed here, and then we were done with it. Like that was
all we needed and it works great and we own the code forever. Now, there are a few things with the migration that I had to make sure were really good. One was the test coverage. So, we talked about how this repo has tests that helps give it the verifiable outputs. uh I needed to have other things that the agent can verify like lints which is helpful and type languages. So having a type language typescript or rust really really helps to ensure that the quality
you're getting back is good. So I did this in about you know 3 days uh within the cursor ultra plan. I was just running a bunch a bunch of agents uh to get this done and was able to save you know a decent chunk of money in doing this as well. Now, I took this even further and did another project where I built an entire Rustbas based image optimization library from scratch using only coding agents. Go check this out if you want to learn a little bit more. But
the the reason for this was to show this is not just for migrations. You can take this very far. The models are getting much better at these things. But this is kind of a side tangent from where we're going to go. Um, with our migration, I think it's helpful if we take one thing away from this. it is the verifiable outputs. So you kick off this migration, you need to give the agent a way to verify its changes. Now before we get into some other coding agents best
practices, I want to show a new way that some people have been experimenting with getting agents to run longer. So let's imagine for example that you wanted this agent to run for a very long time. You wanted this agent to do the entire migration, you would need to give it a very ambitious goal. All tests are passing. The entire codebase has moved from C to Rust. Every file in the old world has been deleted. We have 100% feature parody. The current
generation of models is not good enough to do that in one shot. There's just no way. It's way too much work. You have a limited context window. So for something like Opus or GPT, this is like 200,000 tokens. It's just not doable. One thing that the latest crop of agents have been working on is effectively a long running agent loop. Um some we've referred to this internally as grinding. You're just grinding out a task. Externally there uh people are referring to this which is
hilarious as Ralph Wiggum which is a character from Simpsons. I'm not making this up. He's actually the guy in the meme that says like chuckles, haha, I'm in danger, which is hilarious. Um, this has been going on for like 6 months where people have been experimenting with this. I want to explain the concept. You don't need to copy this code. There are skills that you can use that will just automatically install this for you. And I'll explain skills as
well. But the concept is helpful because I think in 6 to 12 months, you will start to see more things like this as skills. And you will see this built into products itself like maybe cursors agents can just get better at running for a very very long time. So today agents can run for maybe hours. With something like this you're getting agents to run for potentially days. The way it works is you take the cursor agent and you make it extensible. You
give it hooks and we have a hook system that can run before you submit a prompt and then when prompts end before you submit a prompt it's going to go and it's going to call this script. So it can be a TypeScript script, it can be a bash script, it can be whatever you want. It's going to save information about what you're trying to do and it's basically logging all of this stuff to a scratchpad. It's like a working memory that exists outside of the one context
window. So instead of the limits of one context window and compaction or self summarization over that and just continuing going models get lazy after a while. What this does is it lifts the state. It lifts the plan and it lifts the scratch pad out to files in the file system. And as the agent goes and goes and goes and goes, it makes changes. It reads the plan and it checks against progress in the scratch pad. And if it's not done yet, then it keeps grinding. So
when the agent stops running, it checks. Hey, are we done? No. Okay, keep going. It sounds kind of trivial. It sounds kind of obvious, but it actually makes a lot of sense. And today you can do this with skills. So the Ralph Wigum idea, there are skills you can install uh inside of cursor or other coding agents that will do this. skills are a new concept that um are now an open standard. So they started in anthropic. They put out this specification kind of called skills and really what they do is they allow for
dynamic context and we have a blog post about this if you're curious. Dynamic context discovery just published a couple days ago. Would recommend checking this out. But what they do is you get to decide when you want to load in not just a prompt but scripts. This is giving a non-deterministic coding agent the ability to run deterministic scripts which is great. So scripts here can be things like grinding and continuing to iterate in loop. This could be something like making it a very good front-end engineer or making it
really good at DevOps. You can do lots of interesting things with this. This is an open standard that's supported in um will be supported in all versions of cursor for all users in the coming weeks. It's right now it's only out for some users, but it it's selectively rolling out for everyone. So maybe by the time you watch this, it will already be live. So you don't necessarily have to implement this thing in userland. You can install a skill. We're going to make
that very easy to do. Uh and I would expect the products to get better at this over time where you don't have to do all this stuff by hand. But the general idea holds. You have to imagine that in the next year agents will get better at running for significantly longer. So your job then is to make a really good plan and the plan needs to be very ambitious. You need to have the checks and balances in your codebase that will allow you to do the migration.
So before you try to do the migration, if you have no tests, you're probably going to have a bad time. I mean, think about it. How would a human do that anyway? How would a human migrate a codebase? You'd have to do a bunch of manual work to make sure that it actually worked as expected. Um, and you can ask if you're doing web development, you can ask the agent to go use the browser to do that manual verification, but you probably want test anyway and
the ability to generate tests is much easier now with the latest models. So, I would recommend doing that. I'm going to pause and go through some of the questions and then I'm going to get on to the next kind of spiel here about um about coding agents, but I see there's some chatter in the chat. Um, so let me do that. Um, I think one question I'm seeing a lot is like what guard grills do you put in place to stop agents from going off scope or refactoring too
aggressively? Overall, just like how would you think about making sure this is done the right way? >> Yeah, I think in um in today's state, I don't expect that you can just run an agent in this like massive for loop or while loop forever and expect that it won't get something wrong. It it probably will get something wrong. So, you kind of have to still be watching it. A more realistic approach for today's models and today's agents is that you break down your migration into an incremental set of pieces. So you
might have one plan that's the master plan and then you're executing that over multiple agent runs that allows you to step in have a human in the loop and verify that things are going as expected along your journey on the migration. Maybe in 6 to 12 months that won't be as necessary but I think it's still pretty helpful today to do that. Um, but tests and types give you some of that validation so that the agents can fix their work before you have to go
manually fix it, especially if you have end to-end test or or broader testing. Um, other questions in the chat. How are skills different from tools? Um, you can kind of think about a skill like an external tool. So, an agent harness, which is actually this is a good time for me to I'll flip over this. Uh, so you can look at it while I'm gapping. Um, an agent harness is three things.
It's instructions, so like a system prompt. That's tools. So, you have first party tools, uh, which are things like editing files, searching your codebase, running shell commands. Then you also have third party tools. Those are MCP servers which give you tools. They're also things like skills. So when you install a skill, you're effectively giving the agent a new trick. You're teaching it a skill. It is a tool it can learn and use to do interesting things.
Uh and then you have the user messages. So I'll talk a little bit more about some of these agent best practices here which relate very closely to doing migrations. Other questions in the chat? Uh, this sounds great, but wouldn't it cost more tokens if it doesn't go through compacting? I will say that for people who are doing these infinite loops, they are not as costsensitive. It will definitely cost more to run an agent that runs many many loops for a very
long time. So, you have to be mindful of that. Um, I think that in the ideal state, the agent harnesses will build in the tools that get very very good at doing summarization over long periods of time because then you can take advantage of prompt caching and you can take advantage of basically compacting things down and only keeping the most important important parts in the the working memory or in the context.
Um, there was a few questions on like the grind file and where to get the skill. Um, there's a few skills available today on GitHub if you just search for Ralph Wiggum. It's basically the exact same thing here. We're also going to be publishing these to be more uh discoverable inside of Cursor, which I think would be helpful. I kind of like the name Grind.
I actually saw this is hilarious. I saw them change the name from Ralph Wiggum to Ralph Loop. Probably because there's a trademark issue with the with the Simpsons, which is really funny. Uh, Emily, do you see other questions I should answer now? Yeah, I think I saw some people ask like what is max mode and when a chat runs out of context, what's the best practice there?
>> Yeah. Um, max mode conceptually is a way for you to get the most out of a model in cursor. Uh, we're working on refactoring this a little bit today. What that means is if a model supports a million token context window, it will use that. Um, so that can be helpful in some instances. Um, that usually comes with an additional cost. Um the from 200k to a million token context costs more money but for some people that is worth paying for. Um in the future we'd
like to make maximum maybe even more opinionated like it sets the reasoning level and it sets other configurations. If you've seen GPT5.1 codeex max extra high you know ultimate edition limited edition plus like we want to make that easier so you can understand what's going on.
Um, yeah. Can we integrate skills with agents? Yes, definitely. So, skills are basically just giving the agent new tools. You're teaching the agent how to do new things and CUR's agent will will support those. Um, yeah. So, while we're here, while we're talking about migrating code bases, you're doing all this through curses agent. And I think it's important to talk through some of the best practices of working with agents uh as they relate to migrations. So, this blog post isn't live yet. I'll
hopefully get it published here today or tomorrow, but there was a few things in here that I've already talked about and then there's a few more I want to talk about. We already talked about starting with plans. That is a key to a migration. You need to start with plan. One fun tip is that you can save your plans to your workspace uh if you would like to kind of share them with your team or you want to do a longer running plan. And if it is easier to fix the
plan than it is to kind of go fix all the generated code for focused plans. So you can ask multiple models to generate multiple plans. Pick the best one, try it. If it generates the code to get something wrong, you can revert that change and then make the plan better. Some people take this very far where they only basically write in markdown. Um, which is definitely a thing. I don't know. I don't do that, but I think some people can't do that. Um, some other
agent best practices. In the old world, you had to like tag a bunch of stuff into the context, but agents are now getting very good at just finding things. And cursors semantic search is very powerful that allows you to look through the codebase. And we also have made the grepping process of actually running GP uh significantly faster by maintaining an index on the client. Um another thing is trying to figure out when to start a new conversation which
definitely relates to migrations. I think for migrations, your goal is to keep the context high quality. And sometimes that's going to involve running over basically to the limits of that window when you're doing something very complex. But I think there's kind of two modes here.
Either you're doing the more human in the loop way where you're verifying the changes along the way or you're trying out one of these approaches where you get the agents to run for significantly longer if you have the right guard rails with tests and types and lids that make it so it doesn't just go generate a bunch of slop. Uh question, do you reduce token usage if you give better context? Um yeah, I think so. I think if you're more precise upfront, then you have less back and forth, less file searching, less tool
calling, less code edits about what the agent needs to do. Um, so yeah, definitely um porting skills before should add TDD tests. Um, I do have a thing in here in case you're interested. Uh, one workflow that I find really helpful for agents is doing test-driven development. This is kind of like not all engineers agreed on this, but it it can be very helpful with agents, which is you ask the agent to write tests, they should fail, like they should not pass. You make sure that
they're failing and that they're the right spec for what you need. You commit the test and then you ask the agent to go write code and keep going until it passes the test. This is the verifiable outputs thing. Like engineers were doing this by hand for a long time and a lot of engineers really love this. But man, it's really helpful as models get better about writing tests, especially like the older generation of models could write tests that would trick you where they
would just like make up a test that would pass. The newer models and harnesses like cursor are getting better at this where they don't do that. Still worth checking for sure. However, it's it's definitely worth something to consider. Um other questions?
Uh I'm using this in a slightly different manner to build triggers where I can build on tribal knowledge. Once it's done, I can come back and call the trigger and it loads in that tribal knowledge. So you can start doing analysis uh and then start a new agent and pass it off. Yeah, we also support sub agents which is kind of uh that should be out in the coming weeks which allow you to do a little bit of this pass off. Um, a sub agent is basically
like if there was a workflow that you were doing before you created a PR that you want to almost have a persona of that thing. Um, like verify that all of my changes were implemented to spec. Go run this sub agent. It's more than just a prompt. It's also um you can define the tools that you want to give the model. Maybe you you only want to have read tools. You don't want it to edit any code. Um, that will be very helpful.
Would it be smart to install as many skills as possible since uh it makes it better? So this is one of the things that we talk about a little in dynamic context discovery which is that historically you had this cost where you wanted to use things like MCP but it installed a bunch of tools and it just totally bloated your context window. And what we've done with dynamic context discovery is similar to skills, you only load the things you need. So you can more confidently install a bunch
of skills and not worry that unused skills will affect the context of the conversation that you're having right now. Um, a good example of this is I I think about this in basically two different ways. There are rules for static context. It's in every single conversation. And there's skills for dynamic context. So the agent decides what to use. And that improvement I talked about is for skills and MCPs. So rules like every single run needs to know these things. It's
minimal. It's high quality. I want in every conversation. U these can be simple, you know. Don't overoptimize these skills. So things like commands or hooks or the agent skills thing that we showed. These things extend the world knowledge of an agent and you probably want to install multiple of them. And with this dynamic context discovery, it doesn't blow the context window when you install multiple, which is super super helpful.
Please publish this blog post ASAP. I'm going to hopefully get it out today. I I've got some work to do to polish it, but uh I want to make sure this workshop was really good first and that we all had a great time here. Um what other questions do you all have while we're here together?
Uh I'm using my own MCP for dynamic skills. Yeah, there's been some interesting things that happen in userland where you can kind of implement this. Our goal is to make this the default experience. So, if you're the type of person who has multiple MCP servers installed, you don't get this big hit for having all of those servers installed.
Um, if we add multi-leacy repo, oh, like a multi-reo or a monor or yeah, a monor repo, then will all of the repo get indexed and I don't spend more on the tokens. So, if you have a monor repo inside of cursor, cursor will index it the same way it would index a poly repo. So a singular codebase and it's probably going to help you in comparison to an agent that does not have semantic search reduce the usage of tokens and also have better accuracy on
finding things. We have a blog post here if you want to check it out. Um the takeaway from this post is that all models inside of cursors agent harness get better when you give them semantic search which makes sense. You want to say something like, "Go find the authentication in my monor repo." And actually, it's in three places. It's in the front end. There's an API in the back end. Oh, it's using the mobile app, too. Great. It can go search that even
though the file name does not say off. TSO. And if you're only relying on GP, which looks for Reax Max's uh matches, it's going to take a lot more GPS to find it. It's going to search like ostar reax or security star reax or o n oz z. It's like this is what semantic search is really good for. Cursor just kind of does this out of the box for you. Uh and it ends up with uh we we found this through AB testing. The code that sticks around there that uses semantic search
it sticks around for longer and actually gets committed. So highly recommend that. Highly highly recommend that. Um, >> I see a question from Chris about now that there's a lot of different humans working with a bunch of different AI agents on the same codebase or features, what kind of is the recommendation for larger teams um, kind of all vibing together? >> Yeah, I think I would recommend that you have a rules file static context that you commit to your repo. This is a
living artifact that you and your team updates over time. If the agent gets something wrong, you should update that file and persist that into memory. And one way I've seen this work well for teams is on a PR, let's say uh you're looking at some AI generated code and it's wrong. They forgot a critical business requirement. On the PR, you can do click a comment at cursor add this rule to our our global cursor rule that you shouldn't use any types in
Typescript. Great. That is how you continuously compound and get better and uplevel the engineering team over time as you're getting better and better with agents. You can also share rules. You can share commands. You can share sh u skills across your team. Um we have a bunch of other enterprise features that make it easy to manage these um for team admins.
>> And then I still am seeing a bit confusion like what is the difference between commands between skills? Is this like a new and improved version? How how are we kind of thinking about that? >> Yeah, I think you could boil down the world to just static and dynamic context and just two concepts, rules and skills.
Skills are still new, so bear with me here a little bit. But commands, so doing like slashcode review, that is just a skill. It's a skill that's only a prompt. You could also put a like a script in there if you wanted, but command is a subset of skills. MCP servers have tools. They are kind of just skills too. The only big difference is that MCP servers have OOTH. There is not currently an authentication spec in skills. So, one of the really nice
things about MCP servers, I was just using the Slack MCP server today. It it authenticates and it can go read all my messages. This is really important for enterprise internal tools. Um, you need to have that O layer. You can't just unsecurely access things. So that's the big difference with MCP servers versus rules and skills. But commands are a subset of skills. Um that's kind of how I think about the world. >> There's another question around your
migration. How did you model cost predictability when you're using agents at this scale? And how do you prevent runaway spend? How can you predict that this migration is going to cost me this many tokens at this spend versus another uh type of migration? >> Yeah, it's a great question. We have tried to add um both usage visibility. So you can view your usage in the product or on the web as well as spending limits and alerts um where as you progress along a certain amount of spend you can get notifications towards
that. If the question is how much did I think it would cost upfront? I didn't really have a great ballpark on that because to be honest I wasn't sure if it was even doable upfront. Now that I know that it's doable and I know roughly how many agents I used uh and the amount of work that I got done, I could probably better estimate this in the future. And this is something that I think everyone is still learning right now. I mean, historically, estimating software
projects has been like the bane of everyone's existence and no one has ever been good at it. And I think we're getting a little better with these new tools and we're also inside of cursor for enterprises who really care about this stuff. We provide a ton of analytics that allow them to understand usage patterns and how to forecast this stuff a little bit better. Um, but it's, you know, it's a lot of work to try to figure out this right thing. So for
those people who are doing that, um, we'd love to work with them. >> Cool. >> That's pretty much everything. Um, if there's any additional questions, please feel free to tag me on Twitterx X.com/lero or come to our future workshops. We're going to have a bunch more. We'd love to help teach you the future of coding with AI. We're all figuring this out together and hopefully we can teach you some of the new patterns and tricks we're developing internally, but also we're seeing from all of our customers.
>> Awesome. Thanks everyone for joining. Have a good one. Thank you.