Enjoying Software Engineering in the Age of AI

This essay was originally written for and submitted to the Pragmatic Engineer essay contest in October 2026.

At some point earlier this year I realized I was not enjoying work the way I used to. I'm the kind of person who likes solving problems for a living. On a good day I might even go so far as to say I enjoy the work of getting to the bottom of an issue and fixing it from first principles. At some other point also earlier this year, AI tools crossed an invisible threshold and became genuinely useful to me at work. I will admit that I was one of those software people who was very unimpressed by ChatGPT in the early days, and I found the hype and excitement around LLMs really insufferable back then. I still find the hype, and now doomerism, really overblown and annoying, but have since come around to the reality that these tools are in fact very useful and have changed the nature of our work forever.

Once it became obvious that these tools were becoming essential to how I work and not going anywhere, I decided I had to either accept my AI-centric fate and learn how to use them well, or leave the industry. I've come to believe that being a software engineer but resisting the increasing spread of AI tooling and applications is futile, and a recipe for misery.

But I refuse to accept that work has to be miserable. It's where I spend most of my waking hours, and I want it to be a source of enjoyment and fulfillment in my life. So I've spent a lot of time this year reflecting on the changes in our industry and the impact they've had on my wellbeing and job satisfaction. This forced me to really think about what specifically bothers me about AI and the way we use it, and to figure out how to articulate these challenges diplomatically at work so I could do something about it. This is a story about my journey accepting and adopting AI tools in my work as a software engineer and championing their responsible usage at a normal tech company.

I use coding agents in almost every part of my workflow now. I build internal tools to make work easier, and I host our monthly AI guild, which started as an internal AI dev tools meetup and, frankly, somewhere to vent about what wasn't working. Getting to a place where I felt more productive instead of just more frustrated required investing a lot of effort into learning how to work with these new tools. In my unskilled hands I found they mostly just caused chaos and more work.

It also required some difficult conversations about how we work with each other. My day to day work is completely unrecognizable compared to even a few months ago, but I still find the hardest problems are the same as they ever were: unclear strategy and direction, slow feedback, tightly coupled systems, and poor communication. The 2025 DORA report described AI as an amplifier of an organization's existing strengths and weaknesses. That fits my experience, and it makes the problems and potential benefits harder to ignore. Fortunately, the solutions are broadly the same practices that industry leaders have been championing for decades. Doubling down on them is what made the difference for me between begrudgingly putting up with the onslaught of AI and accepting and even appreciating what it makes possible.

I am a staff software engineer at a company called Seeq. It is probably not very familiar to many of you. We are a normal tech company in many ways. We have an established product, a huge legacy codebase, a few hundred employees, about a quarter of whom are software engineers, and are not based in San Francisco (or anywhere, the company is truly fully remote). We are also unique in many ways. We operate a suite of enterprise SaaS products used every day by the industrial megacorps that make the world go round. We have many paying customers, most of which are advanced processing and manufacturing companies across oil and gas, chemicals, mining and metals, food and beverage, pharma, utilities, and now semiconductors. Modern factories have tens of thousands of sensors collecting data all hours of the day and night, and distilling all of that data into useful information is where Seeq comes in. These companies depend on our software to make operational decisions that have massively consequential and sometimes extremely expensive outcomes in the physical world. I emphasize this to say that we cannot be cavalier about what we ship to production. My team is responsible for two of the core products the company is built on, and the ones by far most used by actual paying customers.

AI made experimentation cheap and fast but engineering is still slow#

Being responsible for these kinds of systems was the first source of friction I ran into with the enthusiastic adoption of AI early on. Seeq has been very open to developers using AI tools. We've had early and easy access to new models and tools with relatively few restrictions from the start, and the approach has been mostly to just let people explore on their own and share what they learn. I think this kind of bottom-up approach to AI adoption is one of the things we've handled well. People have different strengths, preferences, and jobs to do, so it makes sense to give individuals space and permission to explore what works best for them.

But this level of extreme flexibility and freedom leaves a lot of questions unanswered. What existing systems and processes are experiments allowed to interact with? When does an experiment become something we have to support? Who is responsible for getting it to that point, and who is responsible for the implied ongoing operation and maintenance? I realized that a lot of the friction I was experiencing was caused by leaving these questions unanswered among people with different problems to solve but working in overlapping areas.

I understand the value of prototypes. They can help determine whether an idea is worth pursuing and facilitate technical decisions. It is useful to be able to show something to potential users, let them interact with it, and discover whether you've properly understood the problem before investing significant resources into developing a solution. I've spent enough time in planning meetings and building software nobody uses to appreciate the value of this kind of work.

The problem is that developing software for production implicitly comes with requirements beyond what a prototype can deliver. It needs to handle errors and edge cases, enforce permissions, work correctly under concurrent load, and integrate with the existing product offerings and business strategy. It also needs to be deployed, observed, supported, and maintained. A prototype can be genuinely useful but still leave all of these responsibilities unhandled. Production software that has paying customers cannot.

AI made the early stages of the software development lifecycle much faster and cheaper. The later stages, though, once these prototypes have helped settle on a direction, are still substantial work. The change in the pace of development was dramatic. In my organization the number of PRs merging has increased by about 70% year over year and the volume of code merging has more than doubled. Some of this is just the natural growth of a scaleup, but over the same time period the number of engineers merging to prod only increased by about 25%. Most of the surplus throughput not accounted for by increased headcount can be attributed to our existing engineers producing more with the help of AI.

Of course volume of code shipped is not a useful measure of developer productivity, but it is a relevant metric for evaluating the load we are putting on all of the systems that surround writing code in the process of producing working software. Our review, testing, continuous integration, deployment, observability, and human attention chokepoints all suddenly had twice as much traffic flowing through them. We have a monorepo with a single shared CI pipeline, which of course started deteriorating in both speed and quality. Defects reached customers when they shouldn't have. Poorly architected changes that were too tightly coupled to existing code got merged, and the responsibility for making all of this new code reliable and for handling the fallout of this decreased stability fell implicitly onto people who often had no part in causing it.

All of this happened very fast and created a lot of downstream consequences. Shared build failures hold up every engineer in the organization and delay unrelated work. Exposing buggy functionality erodes customer trust that is harder to earn back than most people realize. Coupling experiments to existing functionality increases the effort required to change either one later on. Leaving ownership implicit means people only discover that problems are theirs once things are already on fire and the arsonists are nowhere to be found.

The accountability gap#

I am the firefighter called in to fix prod more often than I would like. When I am investigating an issue having an impact on real customers, I try to trace it back and figure out which point in our development process broke down or failed such that the error was able to reach them in the first place. It's not uncommon to find a gap where work was delegated to an agent and accepted without sufficient understanding of what it had done. I suspect this gap in understanding is behind a lot of the reliability problems teams across the industry are reporting. It also makes working out what happened and how to fix it harder.

The problem with relying too much on agents to handle the entire software development lifecycle is that at the end of the day, somebody has to actually understand how the damn thing works. No matter how sophisticated your harnesses and bots, there will come a time when you are called in to investigate an issue in production that they cannot simply fix. If this work of understanding the system is skipped and things start breaking but nobody really knows why, it falls to whoever is responsible for restoring the service to unmangle the history of decisions that led to the failure, work out which changes are important vs incidental, and separate interacting behaviours so that they can confidently fix the problem. By the time these issues arise, the person behind them has usually moved on to something else.

This accountability gap was a big part of what was behind my growing resentment and misery at work. Understanding systems is work I enjoy doing. But having that kind of work handed to me as an emergency, after someone else signed off on the implementation as finished, is pretty radicalizing. It feels deeply unfair that the person who shipped the changes got all of the benefit of any time saved by relying on AI earlier in the process, and all of the resulting obligations fell to other people downstream. Often me.

Being on the receiving end of too much of this kind of work is incredibly frustrating. It took me a while to be able to separate my frustration with this process from my reaction to AI in general. The problems with this kind of arrangement are exacerbated by AI, but not caused by it. Businesses need exploration, but also reliable delivery and maintenance of the experiments that turn out to be useful. Both kinds of work are valuable and need to get done, but AI makes the first kind much easier than the second, and transitioning between them needs explicit decisions and plans for who will handle the fallout.

The engineering practices that help fix these issues are familiar. Code needs to be more modular, concerns isolated, with clear ownership, and alignment on what is considered ready for customers. AI forced us to be more explicit about these requirements and expectations because it made the costs of leaving them implicit much more painful. We're still working as a team on resolving some of our process issues that cause this kind of tension, but we've made a lot of progress.

Human solutions to human problems#

One turning point was when I figured out how to articulate specifically what was bothering me about the way we worked with AI. In the early days of widespread AI use at my company, the biggest source of friction for me was being consistently asked to polish and distill AI-generated output on behalf of the people who had sent it to me. It's really easy to generate very verbose and plausible sounding prose with AI that is totally unclear. In order to make meaningful progress, somebody has to actually figure out what work is important, what has been checked, and what decision is being made. Part of the purpose of writing is to clarify thinking. If the author hasn't taken the time to clarify their thoughts, that work falls to the recipient. For most problems, generating text quickly doesn't really make the thinking part any faster.

I put up with this for way too long before I realized we could do better. Tom Bedor's post, If You are Asking for Human Attention, Demonstrate Human Effort, made the rounds internally and got a lot of positive reactions, and really resonated with me as an ideal and succinct heuristic for how to work with AI. People kept bringing it up and eventually that phrase became shorthand for what we considered appropriate use of AI across the org.

There wasn't a single meeting where this rule was declared. Like most changes at Seeq, it started with a few people championing the idea and it spread organically. Having shared language to describe the problem made it easier to talk about and resolve tension the next time the issue came up. The principle of taking responsibility for what you send to other people is what fundamentally underlies responsible and respectful AI usage, in my opinion. Whoever is on the receiving end of your work should have enough context to respond and shouldn't have to do the work of unmangling walls of AI slop first before they can understand what you're asking or trying to do. That is your job as the sender.

With code, as opposed to prose, this includes explaining the change well enough to make it clear what the intended effect is and how it has been verified. The point is that collaboration takes two. Asking someone for input or a review shouldn't require them to reconstruct and finish all of the thinking you skipped first. Instituting a personal policy of refusing to review unclear requests and asking the author to do a self review first improved my satisfaction at work more than almost any other single change I've made this year. I started by just asking clarifying questions when a problem statement was unclear, or when someone's description of a solution didn't make sense. Instead of framing it as a judgment about their usage of AI, I made it about the work itself. The net result was that I didn't have to do the cleanup work myself.

It sounds like a small thing, but it had a huge impact. Politely returning slop to sender changes the experience of being asked to review something. You are still being helpful by encouraging the sender to clarify their thinking and do a pass for obvious mistakes, and it removes the pain of absorbing all of the unfinished parts of the request.

I am fortunate that my coworkers at Seeq are reasonable people who will engage with these kinds of concerns in good faith. It's the kind of place where I could explain what was causing difficulty and have a productive and mature conversation about improving the situation. Our AI guild gave us a place to share what we were learning, including frustrations, alongside tools and techniques that others were finding useful to mitigate those frustrations.

My own perspective has changed a lot too. I have come to appreciate the urgency behind some of the experiments we are running. There are real market pressures to innovate and adapt quickly, and there are many people trying to respond to this legitimate business need. If I'm honest I used to think of them as reckless slop slingers coming into my codebase with a wrecking ball and leaving me to pick up the pieces. Now I've come to appreciate the value of that work more, and realized that if I wanted to protect our existing product and customers, I also needed to help enable that kind of work.

My goal shifted from trying to prevent slop cannons from being fired in the first place to figuring out how I could build safe places for them to land.

I still have strong opinions about what belongs in our production codebase. But I've been working on ways to help other people find appropriate environments for their experiments, whether it's a test tenant or experimental branch or an entirely new service with its own codebase and infrastructure. There is a real need for these kinds of experiments and I wanted to help find appropriate places to run them without holding them to all of the requirements of our supported products. I'm still working on ways to run parallel production instances for experiments, and advocating for more investment in our feature flag infrastructure that would allow us to reliably control exposure to new functionality and run real experiments safely in production.

These efforts are at different stages. We haven't resolved all of the open questions about experimentation and support, but my role in these conversations has become much less adversarial and much more productive. It always goes more smoothly when I can help someone find an outlet for their creativity so they can try out their idea, while also diplomatically explaining the process of what it takes to ship these kinds of experiments to real customers.

The outcome I'm after is making requests easier to act on and the responsibility of running production software easier to discuss. AI power users could still use the tools as extensively as they wanted, but the people on the receiving end could also ask for more clarity. By agreeing on some baseline rules of engagement we were able to go back to discussing our work at a technical level without turning every conversation into a referendum on AI.

I find this kind of relational work difficult, like many technical people do. It is hard to diplomatically articulate what is wrong with the way someone is doing something while also leaving room for their perspective. It’s much easier to stay frustrated and hope they change their ways unprompted. In my experience it’s always worth having these kinds of awkward or hard conversations, though. Worst case things stay awkward and hard, but more often than not calmly explaining my perspective and the consequences as I see them is much more productive.

The gains in this area were incremental but impactful. We’ve gotten to a much better place as a team where less of the work of unmangling AI-generated messes falls unfairly on unsuspecting victims now, and there is enough psychological safety on the team that people feel comfortable speaking up about when it occasionally does still become problematic. Overall the result is better cooperation across the board. It also made me much more open minded about what these tools might be able to do for me once I stopped resenting their output so much.

Outsource toil, not understanding#

One way I describe what we fundamentally do as software engineers is that we try to make the connection between cause and effect as clear and understandable as possible. Virtually anyone can write code that accomplishes a narrow task now. But it still takes engineering skill to make a system changeable in the long run. Software engineering means being able to understand what behaviour we are trying to change, what is causing the current behaviour, and the mechanism behind how a given change will produce the desired outcome. Answering these questions requires understanding the system, the problem, and the intended outcome. A working prototype can be part of the answer, but we also need an explanation we can test and enough evidence to convince ourselves whether we've actually solved the problem or not. Coding agents are really good at prototyping answers but less good at delivering convincing evidence that they are the correct ones.

It's easy to end up with what appears to be a working app these days and realize you don't actually know how it works. Coding agents make it dangerously easy to conflate outsourcing toil vs outsourcing understanding. I mean "toil" here in the Google SRE handbook sense of manual, repetitive, automatable operational work without enduring value, as opposed to engineering work that delivers lasting, if incremental, improvement to the system. The distinction is useful when thinking about the purpose and appropriate use of automation.

My heuristic for adding AI to any system or process is that it needs to remove friction, not add it. I want agents to take work off of my plate. I use them to understand unfamiliar systems and code, but if I become responsible for part of a system, I need to be able to explain what it does and why, so that I can explain what effects my changes will have on the system. Reading generated walls of text doesn't inherently lead to understanding.

How we handle code reviews#

Another thing that has changed dramatically in my day to day work and how we work at Seeq in general is the way I review code. I used to have quite strong opinions about code organization and style, and I spent a lot of time interrogating the code itself for most PRs. I have given up on even mentioning nitpicks that I would have pointed out before, and have become much more flexible in the range of code styles and approaches I approve now. I am much less flexible about letting incomplete changes through now, though, and do much more in depth exploratory testing for all changes. Rather than focusing on the code itself, my bar is that I need to be convinced a change both works itself and does not break other parts of the system unintentionally before approving. I pay much closer attention than I used to assessing whether the system as a whole is structurally sound and what the blast radius of the change is.

Now I insist that each pull request encodes a single decision. AI has made me less opinionated about code but much more demanding about engineering. I used to invest time discussing naming, organization, abstractions, and idioms. I think these matter a lot less now, but it's still crucial to understand what decision a diff encodes, what it affects, how we can know it works, and how we can undo it. The onus of explaining and understanding a proposed change to a shared system falls to the author of the change. They need to understand the change so they can take responsibility for it. When implementation is cheap, the old economic justification for giant, tangled diffs is much weaker. My expectations are much higher now, and I expect engineers to spend that saved implementation time making changes smaller, better tested, and easier to understand. Our codebase reflects some of this shift in our approach to review. Comparing the same periods in 2025 and 2026, the volume of changes to test code increased about 3x, while the volume of changes to non-test code roughly doubled. Cheap implementation hasn't made verification any less important. If anything, we've been spending proportionally more of our newly available capacity proving that changes work as intended.

All of this is why I still care about code, even though I don't scrutinize it in the same way as I used to. I no longer think code needs to be optimized for human readability. Increasingly code is mostly read and changed by agents, not humans, so now my focus is primarily on whether the system enforces clear boundaries that allow both to reason locally.

When I review PRs, I'm looking for clear boundaries between components, potentially leaky side effects, unhandled failure modes, isolated and modular changes, and evidence that these changes produce the desired effects. I'm not really considering how it is written anymore. Some of these things are easier in certain languages, but the principles are the same across any system. Agents struggle with broad context in complex systems. They often make locally reasonable changes without recognizing the broader impacts on seemingly unrelated parts of the codebase, or even the business. In an ideal world we would offload all of this implicit context onto our agents, and I suspect eventually we will, but for now a tremendous amount of tribal knowledge still lives in the brains of humans, which makes us difficult to remove from the review process for changes to large legacy systems.

When I review code, I'm implicitly running through everything I know about this subsystem, how it fits into our broader architecture, how this feature or product area fits into the overall product and business strategy and endless other small things that are relevant to a given change but not documented anywhere. My brain is what is making the connections between all of these things.

Everyone knows that in theory you should write modular code with clear boundaries and isolated responsibilities. In practice I have hardly ever seen a codebase that does this reliably and well. It is just so much easier to make the thing work and worry about making it nice later, but later never comes. In theory, if a component had a clear contract between itself and all of its consumers, no shared mutable state, and explicitly injected dependencies, there would be very few potentially unintended consequences to changing it. In practice, though, almost no code is written this way, and most languages make it unnecessarily difficult to write clean code in this sense. In real codebases, everything is coupled to everything else, which makes local reasoning and correctness much less relevant. In codebases like this every change becomes an exercise in discovering new and interesting couplings in the system and, if you're ambitious, trying to untangle them.

Overall the impact of AI on this category of my engineering opinions has surprised me a lot. I used to really really care about elegant code. I spent countless hours poring over really nice, functional solutions to hard problems and coming up with perfect names for things. Now I rarely read code line by line. When I do read code, I'm looking at the structure around it more than the details of the implementation. The type of understanding I care about has effectively shifted up a level, from how each individual component of the system is written to what effect it has on everything around it, and how we can verify that. Clean code to me, now, means very local responsibilities uncoupled from other parts of the system. This was always better, but with agents making most of the changes now, it's essential.

Automation and observability#

I mentioned that AI has also increased the amount of time I spend looking for bugs and regressions. This became really tedious really fast and was one of the first things I worked on automating in my new workflow. It started out as a local skill, then evolved into a full-on exploratory-testing bot that engineers can opt in to have test their PRs. It drives a browser to explore functionality, check for regressions, drill into edge cases, and has found tons of bugs. It also leaves behind a trail of state and steps to reproduce any issues it finds on PR tenants, which makes problems much faster and easier to describe and reproduce, which saves work when the author needs to investigate and fix them.

Seeq has been adopting more and more of this kind of agent-based automation in our software development lifecycle over the course of this year, but it has also inspired a general shift toward thinking about how we can be more efficient. We’ve added a lot of automations to our development process that are completely conventional. We have a Slack review-assignment bot that assigns pull request reviewers, triggered by a magic phrase in PR descriptions. We have a GitHub bot that runs and monitors dozens of checks and merges PRs once they all pass. It's the only way to merge anything to trunk in our repo. We have other bots for assigning escalated tickets, managing PTO, and they all coordinate enough so work doesn't get assigned to someone who is away. None of these use LLMs.

We also still use code review as a tool for understanding and sharing context. The review assignment bot picks someone at random from the squad, so it's common to get assigned a review for something you had no part in developing. It can be a drain to get up to speed on new areas, but we have found this inefficiency to be a more than worthwhile investment because it forces a baseline level of knowledge sharing across the team. Team members are regularly exposed to changes outside of their immediate work streams this way, so we share at least some understanding of the overall system.

I think this is an important component of shared responsibility, which I increasingly believe is at the heart of team harmony. If we expect someone to be able to investigate a problem or maintain a feature later, they need to have opportunities to learn how it works before that becomes urgent. Reviewing each other's diffs is part of how that happens. We use AI extensively to help explain changes, get up to speed on unfamiliar parts of the system, and find bugs in review, but having multiple people understand why decisions are being made keeps knowledge and a shared mental model circulating through the team.

This same emphasis on outcomes-based verification in review also carried over into production for me and has changed the way I approach monitoring and following up on my work. I got a lot more serious about observability this year. I will admit it started somewhat cynically because I was convinced I could prove that the steady stream of what I considered slop getting merged was causing increased incidents. What I found was mostly that it turns out humans produce a lot of slop, too. What I ended up with, though, is a team health dashboard that shows us errors we should care about and surfaces our top production exceptions. We're working on getting better at monitoring these things proactively instead of only responding to incidents. And the main benefit of having better metrics is that it helps me ground technical discussions. Now I can point to specific errors and have a shared basis for quantifying our problems. It makes it much easier to move from frustration to action.

Now that producing code is so cheap, it's more important to decide what to spend time on. It's dangerously easy to waste days or weeks playing with prototypes before realizing you have no actual goal or purpose. I think this was always true, but making the prototypes used to take so long comparatively that deciding how to measure the outcomes was an afterthought.

Like many teams, we had been underinvesting in observability because we hadn't felt enough pain to make it a priority. Faster implementation made our missing feedback loops impossible to ignore. If you want to change a running production system frequently, you need to be able to see what happens when you do. Good intentions and careful reviews cannot provide that visibility on their own.

Modernizing CI to accommodate agentic development#

Our CI pipeline also started creaking under the strain of our increased throughput. The merge queue would get backed up, builds started taking longer and longer, tests got flakier, and other unreliable checks added uncertainty to the development process where there shouldn't be. As implementation got faster, the time spent waiting on builds and merges became a noticeable pain point.

Our response was to treat CI as an internal product in its own right and worth improving. We upgraded Gradle, added CI capacity and build parallelism, improved caching, removed the ability to bypass any tests, and started treating build breaks, including flaky tests, as urgent work. We also invested in making our linting and other mechanically automated checks faster, often in the time-honoured way developers everywhere make anything faster, by replacing TypeScript-based tools with ones written in Rust. This was a ton of work, but it has been well worth it.

Compared to this time last year, our mandatory merge check for PRs is down to about 10 minutes from around 25, with p90 merge checks at 18 minutes down from about 40. Over the same period the median whole build time fell from over 100 minutes to around 50. Reliability also improved dramatically. During comparable windows this year and last, our trunk branch spent around 145 hours red in 2025 and 55 hours red in 2026. The share of builds encountering at least one flaky test also fell from 25% in late 2025 to around 12% today.

Not everything improved. Our system test suite got slower, mostly because of the many new tests added, and is now by far the longest running PR check. We're working on moving these tests to faster layers of the test stack and getting better at only running tests that need to run based on a given changeset. Faster feedback does not have to mean less verification, so we are determined to find better and faster ways of testing our system without reducing automated coverage.

Improving CI has been one of the most worthwhile investments we've made. Saving ten or twenty minutes on one build sounds like a small improvement, but multiplied across an entire org shipping substantially more changes, the dividends are enormous. Just as importantly, reliable feedback loops let engineers carry on with work without the looming uncertainty of whether some unrelated flaky test will derail the next chunk of work. It's not as quantifiable, but removing that mental overhead is a real benefit.

We obviously still have a lot of work to do in this area and meanwhile the pace of development is still relentlessly accelerating, but these gains have already had a huge positive impact. Not least, they have convinced a critical mass of developers that this work is worth doing. Without AI, I don't think we would have felt the pain acutely enough to act, and the changes themselves would have been too cumbersome and tedious to make. I think it's fair to credit increased AI adoption for these improvements to our build pipeline on both counts.

None of these practices are novel. Modularity, automated testing, observability, and reliable integration are all baseline practices that industry leaders have been preaching for years. When implementation was slower, weak engineering practices imposed frictions gradually enough that we learned to live with them. Now with the dramatically increased throughput of software through our development cycles, those weaknesses quickly become acute bottlenecks. Trying to produce code faster without investing in the systems that verify, integrate, deploy, and observe it just leads to chaos and endless firefighting. Sometimes it takes significant investment to fill the gaps and catch up after years of kicking these cans down the road, but I really think they are no longer optional. Teams that don't adopt modern software engineering best practices will continue to either miss out on the main benefits of AI or suffer in production incident hell.

Bespoke software to remove friction#

Alongside all of these org-level changes, I noticed that my own workflows were becoming more friction-riddled and frustrating. Agents were making good progress doing my work in the background and keeping many plates spinning at once, but I was constantly checking in, effectively polling them all day to see where my attention was needed.

I used to be the kind of engineer who really enjoyed getting stuck in to a problem and staying there until I had figured it out. I love the flow state that comes from cruising through a task that is just hard enough to keep you both interested and stimulated. Working with agents completely broke this for me and at first I really hated that. They introduced this whole new category of work that could proceed without my immediate involvement, which made it possible to keep several things moving forward at once, but it also meant I was constantly checking in on my agents, and polling is exhausting.

I realized that since software was effectively free to produce now, I could solve a lot of my frustrations with better bespoke tooling. Anytime I run into friction in my workflow now, I remove it with some sort of bot or tool or new app.

For example, the increased throughput of my team meant I had a lot more things to review, and I started to feel like I was drowning in notifications and dropping balls. So I built a custom command centre for myself. It's like a virtual executive assistant. It pulls everything in my work world from Confluence, Jira, Slack, GitHub, and email that could possibly need my attention and distills it into one unified, prioritized, utterly non-overwhelming list. Now I don't check notifications anywhere, I just work through my list with my AI assistants. At first I had an LLM organizing the list and fell into the trap of manually checking the AI's work, which totally defeats the purpose of automation. That's when I realized an LLM was the wrong tool for this kind of prioritization. After a few rounds of refining a deterministic prioritization algorithm, it's pretty dialled in and I trust the system enough now that I'm not manually polling all of the disparate streams of noise that could possibly be delivering me a signal anymore. Once I got to that point, it felt like nirvana. I'm missing fewer things and doing a better job promptly unblocking others. That's essential to me because most of the benefit of keeping more work in flight at once is lost if it all gets bottlenecked on one person anyway. I am determined for that person to never be me.

I also have a whole collection of other scripts, dashboards, and TUIs that manage all of the complexity of working in my company's particular environment. For example, our PRs each have a branch tenant attached, some require corresponding documentation updates, reviews from various codeowners outside the team, and checks from various out-of-band systems. No off the shelf tool would ever accommodate the endless idiosyncrasies of our workflow, but with AI it is trivially easy to build custom tools to accommodate it. Many engineers have built tools that suit their own workflows and bring all of the relevant details together in ways generic tools can't. Another example is how I manage multiple worktrees. I always have a few on the go now for the sake of keeping workstreams separate across agent sessions, but spinning them up and tearing them down was always a bit cumbersome. I and others have built everything from simple scripts to terminal interfaces for making that easier too. Mine also consolidates agent memory sessions from worktrees, which was otherwise getting lost, into my main agent memory ledger before tear down. Stuff like this is what I mean when I say AI can be used to great benefit for removing friction.

One of my favourite internal tools I built is a better interface for commenting on Confluence docs. A lot of our product development starts in documents, and discussions can run for a long time in the comments. Confluence comments were clearly just not made for this, but the document is a useful place to have the conversation because the context is right there. I wanted a lot of extra features, like drafts, seeing comment threads together in context, and a more clear overview of what had changed since I last reviewed, so I built it. It makes discussions smoother and completely eliminates what was previously one of the most annoying parts of my day.

Building that tool was roughly when I realized my motivation and attitude toward AI were starting to shift in a meaningful way. I had initially been really annoyed by AI adoption and treated learning how to use it well as a necessary evil, or at least something I had no choice but to do if I wanted to keep working in tech. Now I have a whole collection of tools like this that genuinely make my life easier, both at home and at work. Almost none of them would have ever justified the time investment before coding agents got good enough to build them for me. I always wanted the benefits, but the cost was so high it was easier to keep putting up with the inconvenience.

AI dramatically moved the bar for me on what problems are worth solving. This is also a useful corollary to my own argument about prototypes vs production software. Many of the tools I use locally for one specific purpose would be a nightmare to deploy, but that's fine, because I never have to. Not having customers depend on them removes entire categories of requirements, and also makes the burden and responsibility of maintenance acceptable to me. If other people start depending on this software, though, those expectations need to change.

There is nothing inherently irresponsible or bad about building something small or bespoke, but it's important to match the scope and support expectations of software to its intended audience. Not every useful script or tool needs to become a general purpose product.

Finding a new version of my job that I could enjoy again#

I find the implications of all of this interesting in the context of endless predictions about when software engineers will become obsolete. In my own life I've noticed my personal demand for software skyrocket. The lower cost of delivery just keeps revealing more and more software I want in my life. Frictions that used to seem too small or personalized to address have become reasonable projects to tackle. Understanding these problems and deciding what would actually fix them is still hard, but it's becoming satisfying work that I am getting better at and increasingly enjoy doing.

I don't think every problem introduced by AI has an already-known solution, or that we are anywhere near finished figuring out how to work with it effectively. The details of my workflow and this mountain of custom software I run for myself keep changing, almost literally daily. My org's processes at work are still very much in flux, too. There are still disagreements about experimentation and product commitments, open questions around how to prioritize what gets done, what is worth doing in the first place, and what responsible engineering looks like in the age of AI.

I think eschewing AI as a professional software engineer is no longer practical, or responsible even, but that's a whole other essay. When I realized this earlier this year, it made me seriously wonder whether I even had a future in this industry. Once I figured out that what I hated about my job wasn't really the fact that everyone was using AI, but the way they were using it, I started to see a path forward. I don't hate AI. I hate reviewing work that nobody understands and inheriting responsibilities that nobody explicitly accepted. I hate waiting on unreliable infrastructure, and spending my precious attention polling machines searching for signals hidden in endless noise. AI made all of these problems so much worse so quickly that I thought I just couldn't handle it anymore.

Fortunately addressing them required remarkably little new wisdom, just a lot of patience and grit. At work, we made changes smaller and clearer. We are working on making ownership and accountability explicit. We invested tremendous time and energy improving our tests, builds, observability, and process automation. We came to a reasonable mutual understanding of when it is appropriate to ask for human attention, and set a bar for asking for it. We outsource toil, not understanding.

The tech industry has always been prone to hype cycles, but this is certainly the most dramatic upheaval I've experienced in my decade or so writing software. If you are finding this transition miserable, I think it's worth taking time to reflect on what specifically in your day to day is causing that. Reject the premise that work has to be awful.

I started this process because I refused to accept that hating my job was an inevitable part of being a software engineer now. Getting clear about what I needed from my coworkers, more attentive to what they needed from me, and willing to put in the effort to make the necessary changes made work better for me.

I use AI far more extensively now than I did when I hated what it was doing to my job. I didn't stop caring about engineering, though. I just realized that cheap code makes engineering more important. Implementation is something we can delegate now. The days of crafting artisanal functions by hand are over. That makes me sad and I miss those days, but that's okay. Understanding systems, deciding what should change, producing evidence that it worked, and taking responsibility for what happens next are all still interesting, and what the job is now.

Related

Reading Code Considered HelpfulAug 16, 2026Learning to let go in the age of AIOct 18, 2026There usually isn't a correct answerSep 7, 2026

Kira Howe is a software engineer writing about building with care in the age of AI.

More about Kira →

Follow