From the Codex beta to AI-native engineering
How my work evolved from debugging snippets in a browser to directing agents, building AI applications and taking on larger engineering challenges.
On 23 November 2021, I received an invitation to OpenAI’s API beta with access to Codex and GPT-3. I still have the email. Looking at it now, I can trace a journey that has changed how I learn, build software and think about my responsibility as an engineer.
It happened gradually. I started by asking AI for help with difficult code. Today I work with agents across hosted and local models, giving them increasingly substantial tasks. Along the way, I have also built AI applications professionally. Both experiences shape what being an AI-native software engineer means to me.
From conversations to delegation
The 2021 invitation was for API access. The browser conversations that became an important part of my development workflow came later. I would bring a problematic snippet or a complex issue into the browser, work through possible explanations and take the result back into my development environment. The scope was small and I was doing most of the work around the conversation.
There was value in having something to question, ask for an explanation or use to explore another approach. I still had to decide what to bring into the conversation, what information was missing and whether the answer actually made sense. The quality of the exchange depended heavily on how well I understood the problem.
Cursor was my next step, followed by Windsurf. As AI became more integrated into my development environment, I started handing over larger pieces of work. Then came Claude Code and later Codex. My role in the interaction changed: I was increasingly defining a task, giving an agent context and reviewing changes across the codebase.
Each step involved granting more responsibility and learning how to supervise it. I had to become clearer about scope, constraints and the evidence I needed before accepting a result. Switching tools also became a way to learn quickly: try a different workflow, see where it helped and carry the useful habits forward.
Today I work with Claude Code and Codex. I also run local models through oMLX on my MacBook Pro, connecting them to Claude Code and the Pi coding agent. Exploring what I can do on my own hardware is a particularly exciting part of this stage. My setup keeps evolving as I learn what each combination is useful for.
Taking on larger challenges
One of the biggest changes has been the scope of work I feel able to take on. With agents helping me investigate unfamiliar areas and work through implementation, I have gradually faced larger challenges while growing the understanding needed to own them. Problems that once felt difficult to approach alone have become things I can break down, explore and work through.
That has made learning more immediate. I can ask for an explanation, inspect the code and follow a question further while working on a real problem. To benefit from that, I have to stay engaged. Accepting a result without understanding the relevant decisions would leave a gap in my ability to maintain it. The work needs to expand my own understanding as well as produce software.
I am learning how to manage that increased scope without losing clarity. More parallel activity creates more results to review and more opportunities for inconsistent assumptions. Clear boundaries, shared context and deliberate integration become part of the engineering work.
Building AI in production
My professional involvement with AI also includes building applications where AI is part of the product itself. I have developed and deployed NLP, generative AI and retrieval-augmented generation applications, along with the backend services and APIs that make those capabilities available to users.
I have built FastAPI endpoints exposing models and worked on automated training, validation and serving pipelines. I have worked with PostgreSQL and vector stores, then deployed and monitored services using AWS, Docker and Kubernetes. Those responsibilities connect model behavior to the rest of a software system.
That work has given me experience on both sides: using AI to engineer software and engineering the systems that make AI useful. It influences how I approach coding agents. I think about the inputs they receive, the assumptions in their output and the checks around their work. I also think about the surrounding product: who needs it, how it behaves when something fails and what it costs to keep running.
What I own when an agent writes code
As I have delegated more implementation, defining the task has become a larger part of my work. A technically sound change can still solve the wrong problem. Understanding the user, the business constraints and what success looks like gives me a basis for deciding what an agent should actually do.
I then have to make architectural decisions that will outlast the current task. Where should this behavior live? What data does it need? How does it fail? What existing component could do the job? These decisions shape the instructions I give an agent and the standard I use to review its work.
Verification is part of that responsibility. I need to understand the change, check its assumptions and choose tests that could expose a meaningful failure. Security, data handling and operational behavior deserve attention proportional to the risk. A passing test suite is useful evidence, but I still need to know what it covers.
The same applies when something breaks. I want to trace the behavior back to its cause and understand why a proposed fix addresses it. An agent can help investigate. I remain responsible for deciding whether the explanation is supported and whether the fix creates another problem elsewhere.
Investing in fundamentals and judgment
This way of working gives me more reasons to study systems. Databases, networking, concurrency and distributed systems provide the knowledge I need to evaluate a design. Without that understanding, I would have fewer ways to challenge a plausible answer or recognize a subtle failure.
Problem decomposition has become an everyday skill. Giving an agent a useful task means identifying a coherent piece of work, providing the relevant context and explaining how it will be evaluated. It also means noticing when the problem is still too ambiguous to delegate. Sometimes the next useful step is a conversation with a person or a closer look at the existing system. Knowing when AI adds little value is part of the judgment.
Technical judgment includes deciding how much complexity the situation justifies. I want to be able to explain why a design meets the current need, what its limits are and what would cause us to revisit it. That explanation matters to teammates who will maintain the system as much as it matters during implementation.
Committing through uncertainty
I am excited by what I can build today and by what might become possible next. I am all in on learning to work this way. At the same time, professional stability matters to me. Changes this fast bring uncertainty about roles, hiring and what teams will expect from engineers. I cannot confidently predict how the job market will look several years from now.
I expect the capabilities of agents to keep changing, including in areas such as architecture and debugging. I do not want my career plan to depend on a fixed boundary around what they can do. I would rather keep learning through direct use and reassess my approach as the evidence changes.
My response is to keep participating: build with the tools, learn their limits and adapt as they change. I bring direct experience developing AI applications, a habit of learning new workflows and a commitment to understanding what I ship. I’m excited to bring that experience to a team working on problems that matter.