Two months ago, I thought I was spending my time figuring out how to use Codex better.
I was wrong.
I was actually figuring out what I should expect from an AI coding agent in the first place.
Over the last couple of months, I have spent a lot of time experimenting with Codex and other agentic coding tools. I tried different models, different harnesses, different workflows, and different ways of splitting work across multiple agents.
At the same time, I kept seeing people build setups that looked almost unlimited.
One person would have a $200 subscription here, another $200 subscription there, multiple coding agents running in parallel, several models from different providers, and a workflow that looked incredibly sophisticated.
My first reaction was simple: I want that too.
Then I remembered something important.
I have roughly $20 a month that I am comfortable spending on these tools.
That constraint completely changed how I looked at AI coding.
I couldn’t just pick the most expensive model, run five agents at the same time, and call it a workflow. I had to ask a much more practical question:
What is the cheapest setup that can reliably get my work done?
That question led me somewhere more interesting.
I started noticing that a simple CRUD task, a repetitive refactor, or writing unit tests doesn’t require the same level of reasoning as debugging an issue that crosses twenty microservices, Kubernetes, a database, and several layers of infrastructure.
I also realized that the model is only part of the equation. The harness, the context it receives, the tools it can use, the permissions it has, and the way the work is verified can all change the outcome.
Perhaps the biggest lesson was that I was spending too much time trying to copy workflows designed around someone else’s constraints.
Today, when I see a new model, a new coding agent, or an impressive multi-agent setup, I don’t immediately ask, “Is this better?”
I ask:
“Better for what?”
This article is about what I learned from two months of using Codex, experimenting with the surrounding AI coding ecosystem, and trying to make all of it work within real constraints.
Some lessons are about models and cost. Others are about harnesses, orchestration, permissions, and engineering judgment.
And some of them have very little to do with AI at all.
They are lessons I probably should have learned from software architecture years ago.
The question I was asking was wrong
For a while, whenever I tried a new coding agent, I evaluated it with one question:
Which one is the best?
That sounds reasonable until you start using these tools for very different kinds of engineering work.
A model that feels incredible while debugging a distributed system might be completely unnecessary for creating a few API endpoints. And a model that works perfectly well for repetitive implementation can become frustrating when the task requires understanding a large, unfamiliar codebase.
I started seeing this difference in my own work.
If I need to create a few CRUD endpoints, add some unit tests, rename a set of files, or make a straightforward refactor, I don’t need an agent to spend a huge amount of effort reasoning about the entire system. The task is relatively constrained. I already know what needs to happen.
Now take a different kind of problem.
Suppose a request is timing out somewhere in a system with twenty microservices. The request passes through an API gateway, several backend services, a message queue, a database, Kubernetes, and distributed tracing.
Now the agent has to investigate the system, follow the request across boundaries, inspect logs and configuration, form hypotheses, test them, and verify that the fix actually works.
That is a completely different problem.
The difference isn’t just the number of lines of code. It is the amount of uncertainty involved.
For the first task, I mostly need execution.
For the second, I need investigation, reasoning, context, tool usage, and verification.
That distinction changed the way I started looking at models.
Instead of asking, “Which model should I use?”, I started asking:
“What does this task actually require?”
If the answer is mostly repetitive execution, a cheaper model can often be enough.
If the task involves an unfamiliar repository, ambiguous requirements, multiple systems, or a difficult debugging problem, stronger reasoning becomes much more valuable.
This also changed how I think about the model comparisons we see online. A benchmark can tell you something useful about a model or an agent, but it cannot tell you which one is the best choice for every task you have.
The best model for writing a simple test is probably not the same model I’d want investigating why production requests are intermittently failing.
And once I started thinking this way, another problem became obvious:
The cheapest model isn’t necessarily the cheapest solution.
The cheapest model isn’t always the cheapest solution
Once I started thinking about models based on the task, I ran into another problem.
I initially thought choosing the cheaper model would automatically mean I was saving money.
That isn’t always true.
Suppose a cheaper model takes ten or fifteen turns to understand a problem, keeps making the wrong changes, and still needs me to step in and fix things. A stronger model might solve the same problem in two or three turns.
The price of the model is lower in the first case. The cost of getting the work done may not be.
That made me think less about cost per request and more about cost per successfully completed task.
That cost includes more than the model itself. It includes iterations, context consumed, the time I spend supervising the agent, and the cost of fixing things when it gets something wrong.
Artificial Analysis is useful here because it makes some of these trade-offs easier to see. Its coding-agent benchmarks compare performance, token usage, cost, and execution time, and it also lets you compare different agent harnesses. Its published cost metric is based on pay-per-token API pricing, so it is better viewed as a way to understand relative efficiency than as a direct comparison of consumer subscription prices.
And the interesting part is that there isn’t one tool that wins at everything.
One system can be cheaper, another can be faster, and another can perform better on a particular type of task. That’s why I don’t think a leaderboard should answer the question of what you should use.
Don’t look at a leaderboard and ask, “Which one should I buy?”
Look at it and ask, “Which of these characteristics actually matter for the work I do?”
If I mostly write straightforward backend code, I may care more about cost and speed.
If I regularly work on unfamiliar repositories or difficult debugging problems, I may be willing to spend more for stronger reasoning.
If I need an agent to work inside a particular environment, the harness and tool access may matter more than the model’s headline score.
This is also where having a smaller budget can teach you something valuable.
If I can afford only a $20 subscription today, I have to learn how to make good decisions within that constraint. I can use stronger models when the problem actually requires them and cheaper models when they don’t.
The goal isn’t to stay on the cheapest tools forever.
If one day I can comfortably afford a $200 plan, or a company gives me substantial credits, I want to already know how to use that extra capability well.
Having access to a more powerful model doesn’t automatically make me a better engineer.
Knowing when to use it, when not to use it, and how to structure the work around it is the skill that compounds.
If I learn that discipline with a $20 budget today, I can carry the same thinking into a $200 budget tomorrow.
The tools can get more powerful.
The decision-making should get better too.
The model is only part of the agent
The more I experimented with coding agents, the more I realized I was giving too much credit to the model.
I would try a new model, see how it performed, and immediately think, this model is better or this model is worse.
But the model doesn’t work in isolation.
A coding agent needs to understand the repository, read files, search for code, run commands, inspect errors, modify files, and verify whether its changes actually work. How those capabilities are exposed to the model can have a huge impact on the result.
That surrounding layer is what I think of as the harness.
Codex, OpenCode, Pi, Cursor, and other agentic coding tools can provide different harnesses around models. They can differ in how they manage context, expose tools, handle permissions, run commands, recover from failures, and verify changes.
So I stopped looking at an agent and asking only:
“Which model is underneath?”
I started asking:
“What can this agent actually do?”
Consider two agents using models with similar capabilities.
One can inspect the repository, search through the codebase, run tests, execute shell commands, inspect the output, and continue working based on what it discovers.
The other has limited context and fewer tools.
Even with comparable models, I would expect very different results.
For a small change, that difference might barely matter. The agent already has enough information to make the change.
For a complicated debugging task, the ability to investigate becomes much more important. The agent needs to form a hypothesis, gather evidence, change something, run the system again, and determine whether the evidence supports the hypothesis.
That is why I now think about an AI coding setup as a combination of:
model capability + harness + context + tools + permissions + verification
The model still matters a lot. But treating it as the entire system misses a large part of what determines whether an agent can actually get useful work done.
You can have a very capable model inside a poor workflow and get mediocre results.
You can also have a reasonably capable model inside a well-designed workflow and get surprisingly useful results.
Once I started seeing agents this way, another question naturally followed:
If the setup matters this much, how much of someone else’s AI workflow should I actually copy?
I stopped copying other people’s AI workflows
For almost three months, I have been exploring different ways people are using AI for software engineering.
I have watched videos, read blogs, followed experiments, and looked at workflows from engineers building with these tools across different parts of the world. Some of them are genuinely impressive. They have figured out ways to run agents in parallel, delegate tasks, review each other’s work, and keep large projects moving with very little manual intervention.
And almost every time I saw one of these setups, I had the same thought:
Why can’t I do this too?
If someone is running ten or fifteen agents at the same time, why shouldn’t I?
If someone has multiple subscriptions and access to several expensive models, why shouldn’t I build the same setup?
Then I realized I was looking at the workflow without looking at the problem that created it.
Someone might be running fifteen agents because they have a large workload, a tight deadline, and enough credits to make parallelism worthwhile. They may have reached that workflow because doing everything sequentially had become the bottleneck.
That doesn’t mean I have the same bottleneck.
If I have enough time but limited credits, running fifteen agents to build an application doesn’t necessarily make sense. I can use one agent, work through the tasks sequentially, and trade time for compute.
It might take longer.
That’s okay.
Time and compute are both resources. If you have plenty of compute but very little time, parallelism can make sense. If you have limited compute but enough time, sequential work can be the better trade-off.
AI coding tools make this easy to forget because they constantly encourage us to use more. More agents. More models. More context. More parallel tasks.
But the fact that you can run fifteen agents doesn’t mean you should.
What changed my thinking was asking a different question whenever I saw an impressive workflow:
What problem forced this person to build this workflow?
Maybe they introduced multiple agents because their tasks were highly parallelizable. Maybe they needed faster feedback. Maybe they were working across several repositories. Maybe their project was large enough that one agent could no longer handle everything efficiently.
Once you understand the problem, you can design your own solution.
You might end up with the same workflow.
Or you might discover that you need only one agent and a completely different process.
That is the part I think is easy to miss when learning from people who are already operating at a much larger scale. Their solution can be excellent and still be completely wrong for your situation.
So I stopped copying workflows.
I started studying the reasoning behind them.
And that has become one of the most useful habits I’ve developed while working with AI coding agents:
Don’t copy someone’s solution. Understand the problem that led them to that solution, then solve that problem in your own way.
Because when your constraints change, the right workflow should change with them.
Don’t build tomorrow’s architecture today
There is another lesson from software engineering that kept coming back to me while I was experimenting with AI coding agents.
I used to over-engineer things.
If I was building a new application, my first instinct was often to think about API gateways, multiple microservices, message queues, orchestration layers, and all the infrastructure I might need when the system became large.
The problem was that I was designing for a future that didn’t exist yet.
A project might have a few users and a handful of APIs, but I was already designing it as if millions of requests were coming tomorrow.
Over time, I started to appreciate a simpler approach:
Build the simplest architecture that solves the problem you actually have today. Add complexity when the requirements justify it.
For many applications, that might mean starting with a modular monolith and extracting services later when there is a real reason to do so.
The same thinking applies surprisingly well to AI coding workflows.
When I started exploring agentic coding, I made a similar mistake.
I saw people running multiple agents in parallel, with one agent planning, another implementing, another reviewing, and another validating. It looked powerful, so I started thinking that a serious AI coding workflow should probably look like that.
But again, I was solving a problem I didn’t have.
If I am building a small feature that one agent can complete reliably, adding an orchestrator and four specialized agents doesn’t make the system better. It adds coordination, context passing, failure modes, and more things I need to supervise.
The workflow architecture becomes a problem of its own.
Parallel agents become useful when there is actually parallel work to do.
If I have several independent tasks that can safely run at the same time, parallelism can reduce the total time. If different repositories need to be investigated independently, multiple agents may make sense. If a large project has enough independent workstreams, orchestration can become valuable.
But if the work is inherently sequential, adding more agents doesn’t magically make it parallel.
This is the same engineering instinct I now try to apply to both software architecture and AI workflows:
Don’t build tomorrow’s architecture today.
Start with what the problem requires.
Then add complexity when the problem earns it.
I no longer see multi-agent systems as the natural next step after using a single coding agent.
I see them as an architectural choice.
And architectural choices should come from requirements, not from how impressive the final setup looks.
That sounds like a small distinction.
For me, it changed the way I build with AI.
More capability requires more control
There is another part of AI coding that took me a little longer to appreciate.
The more capable an agent becomes, the more access you naturally want to give it.
At first, that might mean reading files and editing code. Then you give it permission to run tests, install dependencies, use the terminal, inspect logs, interact with a database, or access cloud infrastructure.
And once an agent can do all of that, it can investigate problems that would otherwise take a lot of manual work.
But there is a trade-off.
More capability also means a larger blast radius when something goes wrong.
Suppose an agent is debugging a database issue. If it can only read the schema and run safe queries, its ability to investigate is limited, but the damage it can cause is limited too.
Now give that same agent unrestricted database access.
It may be able to solve the problem much faster. But if it misunderstands the situation and decides that dropping and recreating a table is the easiest way to fix the schema, the mistake is no longer just a bad code change.
The same applies to cloud infrastructure.
An agent with access to Kubernetes, deployment configuration, cloud resources, and production logs can investigate problems that a locally restricted agent simply cannot see.
But giving an agent unrestricted control over all of those systems just because it makes debugging easier is a very different trade-off.
This changed how I think about permissions.
I used to think of permissions mainly as a way to unblock the agent.
Now I think of them as part of the architecture.
The question isn’t only:
“What does the agent need access to?”
It is also:
“What is the worst thing this agent could do with that access?”
That leads to a much more practical approach.
Give the agent enough access to do its job, but keep destructive operations behind appropriate boundaries. Separate read access from write access where possible. Use isolated environments when experimenting. Require human approval for actions that can cause irreversible changes.
And most importantly, verify what the agent actually did.
An agent can produce a correct-looking answer while making incorrect assumptions along the way. A successful command does not necessarily mean a successful fix.
For me, this is one of the biggest differences between experimenting with an AI coding agent and actually using one for serious engineering work.
When the agent only writes code, I can review the diff.
When the agent can also operate the environment, I need to think about the consequences of every permission I give it.
The goal isn’t to make agents powerless.
It is to give them capabilities proportional to the trust we place in them.
Once an AI agent moves from “write this code” to “go investigate and fix this system,” permissions, isolation, and verification become just as important as the model’s reasoning ability.
The more autonomous the workflow becomes, the more deliberately the surrounding harness needs to define its boundaries.
That is the lesson I took away:
The best AI workflow isn’t the one that gives the agent the most freedom. It’s the one that gives it enough freedom to be useful while keeping its actions within a boundary you can trust.
What my AI coding setup looks like today
After experimenting with all of this, my AI coding setup is much less complicated than I initially thought it needed to be.
I don’t have one model or coding agent that I expect to handle everything.
I choose based on the task.
For straightforward implementation work, I am comfortable using a cheaper model or a tool that gives me enough capability at a lower cost. CRUD APIs, unit tests, repetitive changes, and well-defined tasks usually don’t justify using the strongest model available.
When the problem becomes harder, I want stronger reasoning and a better environment around the agent. That might mean using Codex for deeper investigation, switching models when another one fits the problem better, or changing the harness because its tooling makes more sense for the task.
I have also become much more comfortable with sequential workflows.
I don’t need five agents running just because my tooling supports five agents. If one agent can finish the task reliably, that is often the better engineering decision.
When there is genuinely independent work, parallel agents become useful. At that point, the extra compute is buying something valuable: time.
So today, I don’t really have a single “AI coding stack.”
I have a set of tools I can reach for depending on the problem, the constraints, and what I am trying to optimize.
And I am comfortable changing that setup.
If a better option appears tomorrow, I am willing to switch. These tools are changing too quickly for me to build my workflow or identity around one particular product.
What matters more is understanding why I am using a tool, what capability I am paying for, and whether that capability is actually improving the outcome.
The tools will keep changing.
The models will keep changing.
My decision-making process should survive those changes.
The tools I use
I have tried enough tools at this point to realize that I don’t need all of them.
My choices are mostly driven by three things: capability, cost, and how well the tool fits the way I work.
I don’t see these tools as direct replacements for one another.
OpenCode is useful when I want flexibility around models and providers. Cursor is interesting for its integrated development experience. Other options can make sense when they are already available to me through an existing subscription or bundled offer.
Codex is the tool I currently come back to most for deeper engineering work. That is a personal choice based on how I work today, not a claim that it is the best tool for everyone.
And that distinction matters.
I am not trying to build a stack that looks impressive. I want a setup that gives me the capabilities I need without paying for capabilities I don’t use.
The exact tools will probably change.
The way I choose them shouldn’t.
What two months of Codex taught me about AI coding
I have been using AI for software development for around one and a half years, so these last two months weren’t about discovering AI coding for the first time.
They were about understanding how I want to use it.
After experimenting with Codex, Claude Code, different models, harnesses, and agentic workflows, I don’t think there is a single tool everyone should use.
But if you ask me a much more specific question, “If I have around $20 to spend every month, what would you personally choose?”
My answer is Codex.
That’s my personal preference based on how I work today.
I have used both Codex and Claude Code, and I genuinely like Claude Code. The interactive coding experience and surrounding capabilities make it a very good product.
But for my workflow, Codex currently feels more efficient.
That doesn’t mean I think Codex will always be the answer. These products are changing too quickly for me to make that claim.
It is also why I would be careful about locking yourself into yearly plans for AI coding tools. Models, pricing, usage limits, and new products can change quickly. I would rather keep the flexibility to switch when the trade-offs change.
But after everything I’ve experimented with, the lesson that matters most to me isn’t Codex versus Claude Code.
It is this:
Don’t optimize for their workflow. Optimize for your workflow.
You will see engineers running ten agents in parallel.
You will see people using several expensive models.
You will see elaborate orchestration systems and workflows that look incredibly sophisticated.
Learn from them.
Understand why they built that workflow.
Then ask yourself whether you have the same problem.
If you don’t, don’t copy the solution.
Build your own.
Maybe you need one agent. Maybe you need several. Maybe you need a powerful model for difficult debugging and a cheaper one for repetitive work. Maybe your constraints lead you to a completely different setup.
That’s where I think the real engineering skill is.
Not knowing which tool is currently winning.
Not having the most expensive subscription.
Not running the most agents.
Knowing how to look at a problem, understand your constraints, and design the workflow that makes sense for you.
The tools will change.
The models will change.
The prices will change.
Your ability to make good decisions should outlast all of them.
Don’t optimize for their workflow. Optimize for your workflow.
📖 Blog by Naresh B. A.
👨💻 Backend & AI Systems Engineer | Distributed Systems · Production ML
🌐 Portfolio: (Naresh B A)
📫 Let’s connect on (LinkedIn) | GitHub: (Naresh B A)
Thanks for reading. This is my personal engineering perspective, and I’d genuinely be interested in hearing where you agree or disagree.❤️


Top comments (0)