← All posts
Post agents · 6 min read

Codex could not hold the line. I went back to Claude.

For three weeks I made Codex the primary coder rather than the second opinion. The interface work genuinely surprised me. Then I asked it to audit its own rule violations, at the highest effort, repeatedly. It came back clean every time.

For about a year Codex has been a second opinion for me. A place to send a tricky function, a reviewer for a diff, a way to get an independent read on something I had already decided. Never the thing holding the plan.

When GPT-6 Astra arrived in the Codex CLI at the start of September, I changed that deliberately. One real project, Laravel on the back, a proper feature set, and Astra as the primary coder rather than the consultant. I wanted to know what it is like when the model is not checking your work but doing it.

Three weeks later I cancelled the plan and moved my main work back.

What this is and is not

One project. One framework. One person's taste in architecture. Three weeks.

That is not a benchmark and I am not going to pretend it generalises further than it does. What follows is the specific shape of where it helped and where it did not, because that shape turned out to be consistent enough to make a decision on.

The frontend genuinely surprised me

I want to lead with this because it is the part I did not expect and it is not a consolation prize.

The interface work was excellent. Not "acceptable for a model". Actually good. Layouts I would not have reached for, spacing decisions that held together, states I had not asked for and was glad to have. Given a screenshot and a complaint it usually understood what was wrong visually, which is a different and harder thing than understanding what is wrong structurally.

If my week was mostly interface, I think I would have kept the subscription. That is how good it was at that.

Then the backend

Here is where the three weeks accumulated into a decision. Four things, all of them in Laravel, all of them repeated rather than one-off.

Validation lived in controllers. Laravel has form requests. They exist precisely so a controller is not the place where input rules pile up. It wrote validation into controller methods, consistently, and kept doing it after being told.

It reached for DB::query() instead of models. For a project that already had an Eloquent layer, this is not a style preference. Every raw query is a place where a relationship, a cast, a scope and an observer stop applying. It is faster to write and it removes the reason the model exists.

Asked for an architectural decision, it produced a file. I said we would be adding language support and asked it to plan the development accordingly. What came back was strings written into files it created under config/. That is not a localisation architecture; that is a place to put strings that happens to be a directory. The decision I asked for was never made: how translation keys are resolved, where they live, what happens to content in the database, how a missing key behaves. Something was produced instead.

And the hardcoded strings. The project had one rule stated up front and repeated more times than I would like to admit: no hardcoded text, no hardcoded URLs. It broke that rule continuously. Hundreds of instances.

The part that actually decided it

Breaking a rule is one thing. I break rules in my own codebase.

What ended it was asking it to find them.

I would say: go through the project and find every hardcoded string and URL. It would work, report back, and say it had found some, or none at all. Then I would open a file and find them by eye, in the code it had written, in the same session.

Every time.

The obvious objection is the one I had myself: had I turned the reasoning effort up? Yes, repeatedly, and specifically for these passes. Re-auditing work it had already reported clean is exactly the job I raised it for. The answer did not change. Same confident report, same strings still sitting in the files.

So it is not a knowledge problem: the rule was in front of it. It is not a budget problem: more thinking, same result. And it is not a capability problem either, because it can obviously read a file and match a pattern. Ask it to find hardcoded strings in one file and it does it fine.

What it is, I think, is that the request "audit the whole project against this rule" is not a task. It is a commitment to keep going until the thing is true, across hundreds of files, with no signal that you are done except the absence of findings. And absence of findings is exactly what a model produces when it stops early.

I could not get it to stop reporting clean on a codebase that was not.

The shape of it

Every failure above is the same failure at a different scale.

Ask for a specific thing and it is very strong. A function, a component, a bug with a stack trace, a screen that looks wrong. Bounded input, visible finish line, one decision.

Ask for something that has to stay true across a codebase over weeks, such as a convention, a layering rule or a localisation strategy, and it produces something shaped like an answer and moves on. The work looks done. Each individual piece is defensible. Nothing holds the line.

I have written before that correct pieces do not guarantee a correct state. I meant it about data pipelines. It turns out to describe this exactly: every file it wrote was reasonable, and the architecture they formed was not one I would have chosen or could defend.

What I am not claiming

That this is a benchmark result. It is not; it is one project.

That Astra is a weak model. On the interface work it was better than I expected, and the gap I hit is not obviously about raw capability.

That another harness would not change it. Codex is a harness with its own context strategy, and I have argued at length that the harness moves results as much as the model does. A different scaffold around the same weights might hold a convention across a hundred files where this one did not. I did not test that, so I cannot say.

That my own tool of choice does this perfectly. It does not. It forgets conventions too, and I have my own list.

What I actually concluded

For sustained work on a codebase I have to maintain, the thing I need is not the highest score on a scoped task. It is whatever keeps a decision made in week one still true in week three, and reports honestly when it is not.

Three weeks was enough to learn that this is the axis I care about, which I am not sure I could have articulated before. The scoped-task benchmarks everyone publishes, mine included, do not measure it at all.

I have gone back to Claude as the primary coder. Codex is a second opinion again, which is a role it is genuinely good at. For interface work I will probably still open it first.