
Hello! So I got some questions on Twitter after I asked what maybe people are interested in when it comes to sort of an update on agentic coding since I shared recently that most of what I'm doing right now is writing code with a combination of Clot and OpenAI, Codex in particular.
And so I figured I go over the questions that came and yeah try to answer them. Okay, so maybe one of the ways in which I can go after this is to start with what it is that I have here. So in this code base I have basically two things.
It's a back-end and it's a front-end. And the front-end is in Solid.js. I can kind of show this. This is what the front-end looks like. It's basically just a debugging tool. Like this is nobody supposed to see this other than myself. There's like an internal thing. And it consists of an API.
So this is the API here. Which is auto-generated. This is just an open API visualizer. And this is SolidShares. And I will maybe share a little bit about like how I build it. But I want to kind of share a little bit about like how much I care about either one of those things.
I actually care very little about the UI. You can, for instance, see like this thing here is most likely unused. Declared, but it's never read. Like this is actually like, I don't actually hate the AI output for the UI. It's actually, it's pretty decent. But I usually consider that to be like a debug tool.
Whereas the underlying API is actually important for me that this works really well because it's going to power, or it's already in parts powering. I think that I care a lot about, right? So one of the questions was Codex versus Claude. And maybe before I go into this, I also covered the other question, which is like how much am I actually writing into any ones of these config files?
So what I have is I have a ClaudeMD, which has just a bunch of commands in it. And if you have watched the other things that I made, it's probably quite familiar. This is basically auto-generated. It's kind of boring. And the agent file is just a symlink. So really there's no MCP, there's no nothing, right?
It's like none of this matters as far as I'm concerned. What does matter is, again, I have a make dev command that I use. In this case, I have clearly in some other window, stuff running. So I'll close this quickly so that I can show it to you here.
Actually, let me close off this. And close this. Okay. So you can see this is on the other screen, but in essence, I can now here run mcdev and I have my dev server running. And you can basically see there's a backend that auto reloads. I have a webhook listener, which is kind of important for me for debugging.
And there's the UI running. And I have already shown this before, but if I have, I don't know a world, then I also have it here, right? So that's, that really is like, for as far as I'm concerned, that's what optimizes the loop is that all my logs go into here.
Okay. So maybe we start with, with one of the things of, of, of why I think at the moment, I'm quite productive with this thing. It's like, this is not optimal code, right? There's a, there's probably a bunch of stuff we don't like in particular. There's very clearly some, some unreferenced stuff here.
So codex is for refactoring at the moment, my tool of choice. So we already know that in delivery details, we have some unreferenced code and it's quite likely that we have a little bit more of it. So what I want to do is I want to say, um, we're going to look into the pages and the components of the pages and see if there is, um, if there is something we should clean up.
All right. So let's say I noticed that in blah, blah, blah, blah, delivery details, which is this one here, um, we have unused code. I'm afraid there is probably more like that in other files. Um, please check all of the components and pages for unused code. So I would just, oh, actually there's one more thing.
I set this to the wrong. I just want codex medium. Um, so codex is quite good at basically refactoring. Um, and really that is all I'm doing, right? I'm just talking to the thing. I'm giving you some instructions and it is a way to deal with, um, challenges with code quality by having this refactoring going.
One, one other question that, um, came up, I think on Hacker News or on Lobsters, which is like, why is there 30,000 lines of go code here? Um, if, if all it's doing is just email sending and receiving. And the answer is it's not just doing email sending receiving, because for that, you really don't need to do all that much.
Um, what I built here is basically, um, um, um, an inbox system that, um, is programmable in a way. So, um, I can kind of demonstrate this for a second here. Um, so I have, um, I have a folder where it's just a whole bunch of test things. Um, and I think if I do test full, sorry, um, LS ML, I think it's, uh, I think this one here, let's see.
So it sends to this address. So, um, let's do the following. Let's use our API. Let's create a mailbox here quickly. I don't have a UI for this part yet. So it's going to be in example.local. That's my domain. I'm going to create here. Uh, let's call this bot.
I'll just leave the rest here empty. Send. So now if I go here, I should have a mailbox, right? So if I do to bot at example.local, I have a way to do like this test, email, HTML, where is it? Not text. What was it? This one. Copy this into mail hook, uh, mail drop.
So this is a folder that this watches for local development. It, um, parsed the email, it sent a webhook that was received by the webhook listener. And if I go here, I can now see that I have an email here and it should have converted that into other formats too.
And I also dump out the, um, HTML. And there's not a ton of really clever software engineering going on there, but there's enough that it was a project that took a little while, right? And so we can look a little bit into what it's doing. Um, but I think that the core most important part of this is optimized for fast iteration, right?
Um, so this is why, for instance, if I drop files into this local folder, it starts processing, even though obviously, um, in production, this is not how it works. So let's see quickly what this is doing. So, um, it's, it's identifying unused code, right? And this is one of the reasons why I largely do not review frontend changes in this project.
Um, and, but I do very, very carefully review backend changes. And again, this is, I talked about this recently, building your own little debug UIs is something that I was not doing all that much in the past because often I didn't have the time for it, but here I can, right?
And so, um, I basically had it do a bunch of changes over the last couple of days to add me this email rendering here, which is kind of useful. Um, and, and clearly in the process, we left some shit behind, right? But like Codex is, is capable of, of doing this.
And the other tool that I then use, um, to figure out what's going on is largely GitHub desktop, actually. I, this is, I wouldn't call it, it's my favorite review tool, but it's the one that I actually use the most. Um, and so I can show this here when I find the window.
Um, so basically you can see this is that it changes that it sort of dumps in here. This is largely how I review at the moment. Um, and if I need a little bit more, then I go into, um, into VS code. So it, it's largely did this now, right?
So, um, obviously, um, I do formatting afterwards because one of the problems that Codex has, for instance, is that it, uh, it destroys white space. Uh, particularly in Go code, it often throws tabs away. And then I can just review this quickly. So this was an import. It was clearly unused.
Um, we can kind of know that this was unused because otherwise, um, this whole page would, would have failed to load already. Um, and it would have picked up on this. Um, there was an unused import. There was even more unused things. This drop down code. Clearly we got rid of one point.
Um, this was reformatting, uh, this it's interesting actually that we're no longer reading this. Um, so this, this code here can actually check here. There's a piece of code here where if I go to web hooks, um, so in the delivery log, we should have seen this one here, right?
This was the web hook that fired. That was the one that triggered this request here. So if I re-delivered this, I should see it here, right? So this did work. Um, so whatever this re-delivering thing, there might have been a popular one point, but clearly it doesn't exist right now.
Um, there's also, I, I don't like that there's an alert. We're all going to look into this, but it's not so important for debugging tool. Um, so, so I would say now that this is an acceptable change. Um, let's call this, uh, UI cleanup, small UI cleanup. And we're just going to check in out of this and say this, um, small UI cleanup for debug UI, right?
So I'm pushed this up and I'm just going to open this quickly in another browser off screen because I want to make sure that, uh, it doesn't show anything it shouldn't show. Um, but I'm going to do this here. So I'll show you, this is the pull request. This is an automated cleanup that should remove unused code.
And regardless of if I'm using codex or if I'm using, um, Claude, I use codex for reviewing. In this case, it's probably going to be entirely useless, but kind of just want to show it. This is generally the workflow that I have. Um, and that's good enough, right? Um, what else?
I usually keep a to-do thing here that, um, that keeps open things that I want to work with. Um, there's actually a bunch of, uh, things I need to take care of if I, before I want to release it, um, actually don't use this anymore. So this license in question is gone, but there was, for instance, I pointed it towards parsing of Winmail.dat files.
Um, so I have an implementation of this here. Oops. TN, uh, T, uh, let's, let's call it the transport neutral encapsulation format, right? So this implementation here is auto-generated by JetGPT, uh, or Claude. I think it was Claude, and it was against a Python implementation, um, of this parser.
And so I think from a licensing point of view, um, this is a derived work, um, even though a machine generated it. So I need to clarify the licensing, right? So there's a small little list of stuff that I want to pay attention to before I release it. But really, for the most part, that's how I work, right?
I, um, and so let's see how we were to implement a backend API, right? So at the moment, I picked Go for this project. And after some iteration, I came to the conclusion that I want to have this reference API in api.yaml. So this is where all the the APIs are that I have.
And then it generates out, um, with, um, I forgot the name of the library that I'm using here. Uh, I can look in a link make file. So I'm using, uh, this OAPI code gen tool, which is this one here, to generate, um, the types and the server, um, implementation for G.
And, and let's see how we can add an endpoint. Um, so what I was thinking here, one endpoint that we can do is at the moment we have this endpoint, um, which returns us the current tenant, but we don't actually have an endpoint to create tenants. And this is in parts because we don't have a super user, um, mechanism to create new tenants, but this is kind of annoying.
So what I was thinking what we can do here is we can create, um, basically an extension to our API key so that we have an extra API key that has super user permissions, right? So basically we're going to create, um, a new API key that has more permissions.
And then we want to have an API that uses those permissions to create new tenants. We're actually not going to do all of this, but I kind of want to show you that the system that I do. So I, I usually have a file called plan.md, which in this case we can delete because that was the last thing.
And so let's say, um, super user tenant management, right? This is what I want to do. And so let's say we want to add a flag to API keys that gives them root permissions. Uh, we should come up with a better term than root or super user, but these are internal permissions, which are allowing us to do cross tenant operations.
So that's the first thing. These permissions will then be used for a new endpoint that allows us to create and delete tenants. One thing that we need to consider here is that the system currently has an assumption that the tenant endpoint can only ever return one tenant. So there's already an open question about what the tenant endpoint would do if an internal key comes by.
All right. So this is, I'm basically just dumping my thoughts here. And so the idea here is obviously that this endpoint that we have returns a single tenant because the way the system works is a little bit different for instance than, um, than I did in the past where, um, each tenant has a URL space that's unique to them.
So there's, if, if you list the domains that you have on your account, which is basically just which, which URLs are associated with it, um, it always keys to the current tenant, right? So, so that obviously there are different solutions to which we can do this. This could return more than one tenant, um, or this could error out if, if we come with a super key.
Um, so, so there's a bunch of stuff we can consider. There's also the question if the internal key should immediately give you access to all of the tenants, or if there should be a mechanism by which you have to gain access to a tenant by, for instance, sudoing into the tenant.
Right. So this is just a brain dump. And so what I'm doing here now is I'm going to save this. Um, and so the first thing we can do here is, um, we can think for this problem. So we say like, I have a plan in plan, plan, oops, plan MD with some open questions.
Uh, we don't want to solve this problem right now. We don't want to implement this problem. I just want to have a back and forth with you to think through the ramifications of this request. And that is one of the things that I'm doing, which is I want to just have another human.
In this case, I don't have a human with me just to think for this problem. And so, uh, using codecs to have this conversation, I think is usually one way for me to think for this a little bit more. Um, so one of the things it says here is like, we distinguish internal credentials, clearly system or operator keys.
So audit alerts, treat them differently from customer keys. Um, root style, access bypass is kind of wanting an assumption. Uh, duh, duh, duh, duh. So this actually brings up an interesting point here, which is, um, we might have this problem here, which is there might be queries, nodes. We might have queries that assume a single tenant and might only return the first tenant.
Oops. We might have queries that only read a single row because they assume a single tenant, which might create some security concerns here. We need to be extra careful. All right. Because if I have a query, it just implicitly assumes there's only one tenant. Um, I don't necessarily know immediately what's going to happen.
Um, so in general, I like the idea of sudoing into, um, a tenant with a super user key because it makes a very deliberate act and then I can have an audit log entry, but it also adds some overhead here. So, um, I don't know yet if that's the right solution here.
Um, and also if I sudo into something, where do I store the state, right? So let's say, um, let's make another note here. Um, so this is basically a follow-up questions. If we sudo into a tenant, where do we store the state temporary API key question mark, right? Because we could sign and derive key, but that's, that might be tremendous over-engineering.
Um, this here. Actually, there's a general question. We don't have deletion at all right now. Um, it might be, we might need soft deletes for tenants for end days to allow account restoration. Um, dun-dun-dun-dun-dun. Okay. So let's start with really this question here. So the most important question here is if we want to go with the path of sudoing into an account, which is probably the right way of going because it changed the least amount of assumptions about the API surface, where would we store ideally in the most simplest way, the data about which account we're, we suited into.
We obviously can't store this globally because then the system key can only ever have one tenant active at any one time, which would be a concurrency issue. Um, and if we start doing things such as derived signed keys, um, this might add some overhead, although maybe this is pretty simple.
So let's think through what options we have here. And the thing is, I don't actually care what it says right now because like for me, it was already the thinking process that helped. So actually maybe signing here a derived key for one specific tenant isn't actually that much work.
Um, I think I might actually prefer this. So one thing it says, header per request, allow a super key to send X, uh, with a normal endpoint. So this would just, I basically just be, um, a regular API request, but you sent an extra information that you want to operate in a scope of a tenant.
That wouldn't be too terrible, but I think it would also be kind of tricky with how the SDK that I generated kind of works. So I don't know if this is necessary the right way. Um, can derive a key. The simplest is top priority where the header approach wins.
So you're in a schema. Um, so since I'm pseudo anyways, and it will not require an extra opt in with the system key, I think we might actually do this header. Um, so if we were to do the header, um, what would be the right way to annotate in the APIs if we have to add ourselves into a tenant context?
Um, please check the Go code that we currently have that fetches the tenant context from, um, the HTTP request and also what would be a good strategy for how we make the SDK compatible with effectively pseudoing into a specific tenant. So I let it think about this, but in the meantime, I'm going to look at the SDK, um, which is auto-generated.
Um, base client change. Uh, so let's look at the Python one because the problem that I have right now is that each request that is sent. So actually, uh, let me look at a generated one because otherwise this is going to be hard to look at. So all of this is vibe coded just to be clear.
Um, so let's for instance, say, uh, these are the resources, right? So I have, um, for instance, I have, um, um, list by domain, which allows me to list all the emails that are on one thing here, right? So none of these parameters would allow me to pseudo. And the way the client works is that similar to how the stainless SDK style is where the base client holds references to all the sub resources.
So if I do this here, right, I have basically blah, blah, blah, blah, blah. What is it? Uh, this is the wrong client. Where's my, where's my client? Um, base client is probably in it. No, where do I have it? Uh, maybe I guess it might be here. Is it mail hook?
Okay. So this is the base client, right? So it creates all of these resources here. So if you do client dot attachments dot, for instance, download, it will do that. So it, one way obviously would be to have a global variable on the client that switches the whole client into a different thing, or I'm starting to auto generate, um, a tenant ID into all of these endpoints.
Um, that's going to be a question if we want to do this. Um, so, So the Python clients are a centralized request preparation in prepare request, um, yeah, but, yeah. Okay. So one idea would be to say like, okay, the entire client needs to be recreated. Um, and then we just store it on the base client, which would be here, right?
So we could have a flag on here, which is which tenant we pick that overrides then could even already reuse this, which then overrides. So you basically would have to sudo the whole client. Okay. Do I like this? Um, okay. So let's plan for this. Okay. So let's do the following.
And I kind of want to write it into my plan too, so I don't forget. Um, so this question is resolved. Um, so let's see implementation. So we're going to add a new X, uh, actually X mail tenant, mail hook tenant header, which allows a system level key to select a tenant.
Uh, system level key is only allowed to access API endpoints. Um, which are marked for a system to do find a way to mark it in the api.yaml or if the X mail hook tenant header was set to a tenant. And, um, um, we need to add a sudo method to the generated client in Python and TypeScript, which binds, which creates a derived client, which in turn, um, which has the tenant set locally as a state, right?
So that's the idea. Um, and then here again, to do, how do we reuse the connection pool? So we are not going to do any of this yet. So we're basically going to start with add a system, add a flag to all the API models that marks it as system level to do name of that flag.
So, um, so one question here is do we want to reuse the context or if we want to start, I think we're going to continue with the context. So, uh, I'm going to just resolve to do's here quickly. So, um, what do we call this? I think we call this name of the flag is system key.
actually maybe we call it key type. And so name of the new attribute is key type with two values, tenant or internal. All existing keys are tenant. Um, and the API level keys, which we have. So we have these keys, this list API keys. This one at the moment would only list keys that the tenant has access to, which is a bunch.
The question now is, do I want to make this endpoint allow it to return cross tenant keys? And I don't actually know the answer yet. Um, I think, I think the answer might be yes. So, um, which are marked for system. If, um, so we basically need two ways to mark this here.
We, we need to mark endpoints, which you are in fact allowed to use a system key without sudo and the ones where you have to use sudo. So, um, when we set somewhere, how to mark an API.yaml, um, we need three types, default, tenant specific, um, also called tenant.
Then we call it internal, only internal keys can access it. And, um, let's call it tenant or internal can be accessed by either and might affect the existing logic. Um, so let's see if we can generate ourselves somewhere. Um, existing logic, for instance, we need to change the query filters, right?
Um, so this we do later that the client stuff we don't care about. So, um, let's do this before implementing, ask me about open questions. And this part here is not so much about code generation. It's just really just to get my mind to understanding the problem a little bit.
Um, because I didn't really think for this at all yet. So one of the things that this has, it already has some markers in here. So this is the, this is the reference out of which I'm generating the code. And for instance, I believe I had X mail hook, X item potency, right?
So I have already this to mark that I said, I didn't potency key support. Um, so we could actually give it a hint. Uh, we already use custom markers in the api.yaml for X item potency. So maybe that will help it, right? Um, so let's see, because it could be friends.
I have like X key type or something to address this question here. Okay. Um, so, so this, um, okay, look, this is already nice because we already have some endpoints, which probably now need to change the nullability. Um, okay. So, um, now what I'm doing is I'm going to take all of these, blah, blah, blah, blah, blah.
Just dumping them down here. So, um, here, the answer is the system does not have a tenant. So the current mode of only ever having one tenant is correct, but you are right that we will now allow requests to come in without a tenant. And we can use that information to distinguish system versus tenant access.
It's actually, I think it might be safe or might be better. Yeah. So the off middleware writes exactly one tenant in the context and every header calls 20. So we need, um, actually the, this is the answer for both of them. Um, we will allow tenant the key endpoints to return a null tenant for system keys.
Um, and this side, this goes here. Blup, blup, blup, I think. Okay, header semantics, um, answer. This will be mandatory. Or it errors with 400 bad request. Um, and then we say create a custom error code because we have error codes in addition to issue status endpoints. Um, and then we have API surface labeling to mirror existing idempotency extension, um, answer, make it x-axis scope.
Blah, blah, blah, blah. Don't touch the SDKs. Touch the SDKs. In fact, very important. We don't want to do any of this Um, don't touch it. As I said, don't create new endpoints yet. Right. So now, now for now, this should be all, and now let's see what it does.
Right. So, um, first of all, we'll go to make a new branch, internal keys, and then we just let it do some stuff. And let's see what it does. So one of the, so I'm actually going to stick to codex here just because it has in the context, but this is maybe the point where I would probably switch to Claude a little bit at the moment.
Um, so let's see. It asks more questions. Um, for enforcement, the enum request context right now, so the middleware can reject. Um, For internal or tenant, we allow to hit without x mailhook tenant. Um, we can look at them by secret to load. We need to either extend that query or at a separate fetch environment.
Um, get a tenant by API key. Let's see. What does it return? Actually, this is, this is the part where, um, some of the existing code I'm not a huge fan of because it's here. We basically call this in a bunch of places. Here. Um, I would replace with lookup API key details or get API key or similar and have actually, uh, replace, what's it called?
Get tenant by API key with actually, maybe we're reading the R. So we're reading just the API key. Um, with a method that returns both the tenant nilable and the API key. So we can check the internal flag. And the name for the error code everything tenant impersonation is good.
Uh, no need to sketch, just go to implementation. So it is the part where we don't care and necessarily now at this point, if it generates exactly the code that I want, because now I just want to see the code. Um, and this is kind of how I work, right?
Which is back and forth on, on just helping my mind a little bit, understand what I'm doing here and building my way step-by-step to it. And if the code that it generates now is exactly the code that I need or not, it doesn't really matter for now because up to this point, most of what I'm doing here was I would have done with another person, right?
I would have probably tried to find the headspace for myself to get into the mood where I can make this decision myself or have a, try to have a productive conversation with a second person, um, just to, to get into, uh, finding the solution really, right? Because like a couple of minutes ago, the solution was maybe not precisely clear to me yet what it would be.
Um, but now I'm much closer to, to what I actually want. And what, what ChatGPT did here was just be a really excellent robot doc. Um, and so maybe now to, to the question of, um, why I'm stuck with Codex now, that was actually mostly just laziness now. Um, I, one of the challenges with Codex is we might not even see what it's going to build because it's very, very slow.
Um, I think there's a good chance it's going to rip for like 10 minutes before I even see the output it produces. And this is actually one of my least favorite aspects of Codex, which is why normally for implementation, I am, I'm still leaning towards, um, Claude because Claude just, it doesn't just go wide and search everything.
It, it, it eventually goes to implementation. While we're waiting for all of this to happen, um, we can talk about the question of paralyzing. So the question came up, how do I paralyze? Um, and so one way of paralyzing is now to go and see, for instance, uh, what our code review did, right?
So, um, Codex didn't find any issues, right? I can have another look, but I already looked previously that this was just simple changes. So now I can just say, let's merge it. Um, so that's one way to paralyze is just do something else in the meantime. But now the question here obviously is while it's changing the code here, how can I do something else, uh, without interfering with it?
And so the easiest one is work trees. So you can do get work tree. Um, like for instance, I added this branch recently. So, um, let's say we want to do, um, what I want to do, um, mailbox creation, right? I want to add a button to create mailboxes.
Um, and we want to do this off the main branch. So now I have this work tree here. Um, I actually want to, uh, this is prior to having the UI fixes. Um, so that's okay. But now I can open Visual Studio Code here and I'm basically sitting in a very similar code base, um, which is within, um, its own checkout.
So I don't need to, uh, isolate the agents from each other because they're not going to step in here. So now I can say Claud, let's do this with Claud for the moment. Um, we want to add a new button and, and pop over to the mailbox creation. Actually, this doesn't make any sense.
We want to add a new button to create mailboxes to the mailbox list in the UI. Please use the pop over style that we already have for the API. So the web hook management. So we kind of use one to use the same thing. Please register URL route for the creating new mailbox screen.
We also want to use the same UI component to edit existing mailboxes. So now we should probably check quickly what the API supports. So, uh, we have mailboxes, create or update this allow. Okay. Um, please make this UI have all the functionality to edit and update, uh, and create new mailboxes with all the settings.
Now I can hope, hope that it just goes there, but, um, I can also just say, um, like, check in API.Yaml, but also this is more or less what the request looks like. But please make sure to use the generated SDK and not direct API endpoints. So I hope, um, that it manages to do that.
Actually, one of the problems here is that in this work tree, I don't have the generated SDK. So that's one of the things that I kind of want to improve. Um, so I need to go to mailbox creation, SDKs, generator, UV run, Python, sorry, uh, main.py, Python or TypeScript.
And this will actually not work. I need to also run mail, I just suck at this, um, SDKs, TypeScript, npm run, build, npm i. Okay. Now it will be able to find the SDK hopefully here. Um, so that's one of the things that's just not optimal with the, with the, where, with the work trees is that you basically start from scratch and I don't have this perfectly set up yet for this to work.
Um, but now we see how Claude does it. Uh, Claude has a very different approach. Claude for the most part, um, goes to action much quicker than, um, Codex. Um, but we're also now seeing that Codex is already in the writing code part. And so while it's doing that, we can already see what it's doing, right?
So, um, so let's look at what the API changes are. So the first thing it did is clearly we're doing this now, um, because the API key in the storage now is nullable, right? So we have to do this. Um, and this is a API, this is an endpoint that I, this is a command line tool to create tenants.
So this is a change that makes a ton of sense. Um, here we have the same, um, this is in the API keys, create and delete. So actually this is going to be a little bit annoying because it means that we are, um, let me just think for this.
It's okay. Um, mailbox test. It's okay. So all of this is okay. So this is the first change that's kind of interesting. We can already see that it's fucked up. Um, it, Codex keep fucking up this, um, and I haven't found a way to fix it yet. For whatever reason it thinks that migrations work like this, they don't.
Um, so there's one problem with Codex right now, which is if I edit this file, it's going to, uh, undo my changes. So I need to remember now that this migration is screwed. So I will go, um, here into my, uh, plan and make a note, review notes. migration is again fucked, right?
Um, just, I need to remember this. Um, and we can see that it didn't really do, uh, also it edited this. Um, so why is it screwed, right? Because it creates the up migration and the down migration to the same file. That's not how my migration system works. I don't know where it gets the idea that there's some goose thingy going on.
So I need to do this. This is all generated, but it manually generated. That's okay. It will redo it. If I were to run the schema migration now, it would actually not do anything because it alters and de-alters basically in one go. Um, this now is okay. There's new key type going in.
So this is all fine. Um, this is kind of interesting. Um, I don't like this pattern. This is just generally one that I need to look at if there's a better way of doing it, but it keeps doing that. Um, that's okay. So we have internal and tenant as the API key type.
It's kind of interesting because this means we also have another type, which is, which key is allowed to go in, which is probably in middleware. So we have the impersonation header and then this one has, where is it, uh, access scope internal tenant or internal. Okay. So there, there we should check, right?
It's a security related. So it's, if hate it, hate it, hate it, hate it, hate it, hate it, um, nil check for self. Right. This is nonsense. Um, in resolve access scope, right? It's like, like, why, why would I do that? Um, like the, this, the, you should not call this if s is nil.
I don't like this. Um, I use also the question if access scopes, like, in fact, the whole thing here, this should be a panic if at all. Um, okay. Okay. Owning tenant. Um, this also, I don't like this, um, oops, um, key type should not be empty if migration is correct.
So let's actually check the migration. So the migration here should default to tenant. So it it should never be possible for the access scopes, uh, not the access scopes. Uh, what is it? The key type would be empty, right? This is, this is a debt, this is a debt, that code path.
Um, yeah, well, we're going to see a bunch of this. And so, um, this is why I, just for a close, this is why I use generally a lot more codex still for writing code. It's like, this is still going, and I already don't like what it did. And I can't change it now because if I change it now, it will regress my changes.
So, but what I can do here now is I can, um, I can run the formatter. It will not format everything because, um, I don't have pretty installed, but that's okay. Um, maybe it's not okay. Uh, why does it want to run this? I will Did it really only create this?
I will add this for now. Edit mailbox creation and edit screen. I will push this up. So I will not review this at all because this is UI code. I will straight go to have codex review this. This is how lazy I am. Um, this adds a way to add and edit mailboxes in the UI.
Right. Codex review. Again, this is UI code for a debug screen. I don't care. I will review it later if there's a security thing, but like it didn't edit any backend code. So there shouldn't be any way for it to break authentication or anything dangerous. So I'm going to, um, stick with this for now.
And then I can, in the same time, look into, uh, more of this. So with codex, I'm for now limited to telling it to respond to my changes. So I'm just going to copy this all in here. Careful with the migration in particular. The migration doesn't actually have a down path.
So this migration was a no-op migration. Um, I have no idea if it's going to be able to edit these changes, but we can see. And I can, in the meantime, review more stuff. So get the API key with tenant. That's okay. This is okay. This will be interesting.
So, um, why does it do a left join? It does a left join because it's now nullable. Are we really running this all the time? This was the thing that I wanted to cache. Um, uh, it's okay. So we're going to create tenant and the API key. Um, that's okay.
It's not, not amazing, but it's okay. I, I need to cache all of this anyways. I don't have, I didn't have time for this. Um, okay. But right, you get the idea. Um, this is basically how I work. There's, there's no, no anything interesting in it. It's just talking to the machine, treating it like another programmer, not the most optimal programmer of all, but no crazy MCP stuff, no crazy prompts in the Cloud MD file or anything like this.
It's really just, just this, right? There's, there's no magic in it. Um, And now the question is, was this more efficient than I would have done otherwise? Well, it always depends a little bit, right? Like in some ways, sometimes when I come out here with like having understood what I actually wanted to do, probably could go in and do the changes myself.
But if you think about it, it's actually not so insignificant what it does. And only having to think about the little bit of stuff to review in the end, it's, I feel like it's good, but also I don't do multiple things at once. Right? So anyways, I hope this was helpful in one form or another.
Um, and yeah, let me know on Twitter or else if there's something else you want to know.