Codeaholicguy
· · 12 min read · AI, Software Engineering

Agentic engineering runs on boring foundations

Contents
  1. We started with quality and ownership
  2. Efficiency changed the question
  3. Multi-tenancy made hidden context explicit
  4. Consolidation reduced the surface area
  5. Trino gave agents a governed path to data
  6. Architecture made the system legible, not automatically safe
  7. What agent-ready means to me
  8. The boring foundations mattered

After Claude Code came out, I started noticing a pattern.

It was useful everywhere, but it was not equally useful everywhere. In some parts of our system, an agent could inspect the code, follow the conventions, run the tests, and make a reasonable change. In other parts, it spent most of its time rediscovering context that experienced engineers carried in their heads.

The difference was not always the model. Often, it was the system around the model.

Looking back, the foundations that made agentic engineering useful at scale were already being built through earlier investments in quality and efficiency. Those changes made our engineering environment easier for both people and agents to understand.

The connection only became clear later.

Timeline showing how quality and ownership work in 2023, platform simplification from 2024, and the Trino migration in 2025 became foundations for agentic engineering

We started with quality and ownership

In 2023, our engineering focus was quality and ownership.

We talked about craftsmanship, long-term thinking, simple solutions, efficient operations, and owning dependencies. We wanted engineers, regardless of seniority, to understand the full lifecycle of their work.

This included doc-first working, but not in the narrow sense of writing a design document before coding.

Engineers were expected to understand the problem with product, data, and design. They had to coordinate dependencies, agree on technical contracts, write and own the implementation plan, test the change, verify the deployment, monitor it in production, and keep the documentation current as the system evolved.

The document was part of the work, not a summary written after the work was done.

At the time, this had nothing to do with agents. It was basic engineering discipline. We wanted fewer defects, clearer ownership, better design decisions, and stronger operational habits.

We were also not where we wanted to be. We still had many defects and serious production incidents. Some of our quality ambition was more visible in our principles than in our daily execution.

That gap was uncomfortable, but useful. It taught me that principles are not enough.

Quality, documentation, ownership, and review discipline have to appear in the workflow. Otherwise, they depend on memory, personal taste, and individual heroics. They get weaker when priorities change or when the people who care most about them move on to something else.

This built on the engineering culture I described in What does strong engineering culture mean to me?. Craftsmanship and ownership matter, but culture becomes durable only when the system makes those behaviours easier to practise.

Efficiency changed the question

In 2024, the company needed more operational efficiency. We had to do fewer things, do them better, and get more leverage from the systems and people we already had.

That pressure changed how I thought about AI.

It is easy to treat AI as a collection of tools. Someone tries a coding assistant, gives a demo, and shares how quickly it generated a piece of code. Those experiments are useful, but they do not tell us whether the organization has become more effective.

The useful question for us was not which assistant looked best in a demo. It was how AI could increase leverage across the engineering system.

Around the same time, three earlier platform changes began to matter in a way I had not anticipated.

Multi-tenancy made hidden context explicit

ShopBack used to run much of the system as market-specific stacks. The market was often implied by the environment. A service running in one stack served one market, while the same service in another stack served a different one.

Experienced engineers understood this. They knew which deployment names, clusters, configurations, and databases belonged together.

The system did not always say it clearly.

Our multi-tenancy migration took about six months. It changed the market from something implied by infrastructure into an explicit runtime dimension.

That context had to flow through requests, configuration, data, events, background jobs, logs, tests, and release controls. Code could no longer assume that its deployment location answered the market question.

The original business reason was efficiency. Shared infrastructure reduced duplication and made it easier to operate and expand across markets.

The unexpected AI benefit was clarity.

Once the tenant stopped being hidden inside infrastructure, an engineer or agent could find it in the system itself. It was visible in code, schemas, headers, events, configuration, and tests.

It is similar to replacing a set of directions that only local people remember with street names and addresses. The knowledge becomes part of the map.

That clarity came with trade-offs. Sharing infrastructure moved more responsibility into the application. We had to think carefully about tenant isolation, resource allocation, and noisy-neighbour problems.

Multi-tenancy did not make the system simpler in every way. It exchanged one kind of complexity for another. The difference was that more of the new complexity became explicit and testable.

That is valuable for agents because an agent cannot rely on years of tribal knowledge. It needs the important assumptions to be represented somewhere it can inspect.

Consolidation reduced the surface area

After multi-tenancy, our infrastructure foundation was cleaner, but the application layer was still too fragmented.

We had accumulated many small services. Each service came with its own repository, deployment, configuration, dashboard, alert, cache, dependencies, and ownership surface. Some existed for good reasons. Others were small enough that their operational cost was larger than the independence they provided.

I wrote about this in Lessons from a Decade of Complexity. At one point, a backend engineer had to handle four services on average. Updating a shared library or runtime across the organization meant repeating similar work across many repositories.

After the multi-tenancy migration, we spent another three months consolidating small services into group-level repositories and deployments.

The goal was not to build one giant monolith. We kept domain-focused modules and retained the option to split a component out when scale, reliability, or operational requirements justified it.

What changed was the default decision.

Previously, creating a new service often felt like the natural starting point. After consolidation, the default became putting the capability into the appropriate group service unless there was a strong reason to create another runtime boundary.

Over time, we went from hundreds of services to fewer than ten larger group services. That reduced the number of deployments, dashboards, alerts, and repeated infrastructure patterns that engineers had to maintain.

It also helped agents.

An agent working across dozens of small repositories has to keep discovering the same information: how the service starts, where configuration lives, how health checks work, how database migrations run, how errors are handled, and which deployment conventions apply.

When related modules share a repository and common foundations, more of that context becomes reusable. The agent can inspect neighbouring modules, follow established patterns, and understand a larger part of the change without repeatedly rebuilding its mental model.

This does not mean bigger repositories are always better. Consolidation brought its own costs.

Shared CI/CD pipelines became longer. A deployment could become a bottleneck for more teams. A badly behaved module could create a noisy-neighbour problem inside the application. Clear ownership and module boundaries became more important, not less.

For us, consolidation was not about choosing monoliths over microservices as an ideology. It was about making every boundary earn its operational cost.

The same principle now applies to agent context. Every additional repository, framework, deployment shape, and convention adds something else the agent must discover and interpret.

Trino gave agents a governed path to data

The third foundation was Trino.

We did not begin the Trino migration as an AI project either. The original problem was more direct: Redshift was no longer the right centre of gravity for our data platform.

BI reports, Metabase dashboards, ad hoc analysis, and some operational workflows still depended on Redshift, while the broader platform was moving towards Spark and the lakehouse.

The platform direction was set in 2024. The main BI migration ran through the first half of 2025, while the remaining legacy workflows were retired in the third quarter.

This gave us a more standard SQL path across company data.

That became important when agents started answering real business and engineering questions.

Without a shared query layer, every AI tool would need its own route into different warehouses, files, dashboards, and operational databases. Each integration could introduce another credential model, another set of semantics, and another opportunity to query the wrong system.

With Trino, we could put access policies, resource controls, query limits, and auditing around a common interface. The controls still had to be configured and operated correctly. Trino was not automatically governed just because it was Trino.

The common path changed what agents could do.

An engineer can ask an agent to explore an unfamiliar dataset. The agent can inspect the available schemas and fields, generate a query, execute it with the engineer's permitted access, and return both the result and the SQL used to produce it.

This is useful in a large organization where different teams own different data models. The agent can accelerate the first part of understanding a domain, which often takes longer than writing the query itself.

Product teams can use the same path to explore whether relevant data exists before committing to an implementation. Non-technical colleagues can answer appropriate routine questions without always waiting in a data-analyst queue.

During an incident, an engineer can ask an agent for a recent transaction baseline in the affected markets. The agent can query the governed dataset and combine that result with production telemetry. The result remains auditable because the query and source are visible.

This connects directly to the argument I made in Building a Data-Informed Culture. Data should be accessible to the people who need it, but accessibility has to come with permissions, accountability, and judgment.

The agent did not create data democracy. It made an existing governed data path easier to use.

It also does not replace analysts or data engineers. A generated query can be syntactically correct while using the wrong definition, joining data at the wrong level, or ignoring important business context. Analysts and data engineers still own complex analysis, semantic definitions, data quality, and interpretation.

A common query interface removes some access friction. It does not turn every field into a shared truth.

In The Missing Piece in AI Adoption for Organizations, I argued that AI needs structured and meaningful organizational context. Trino became one practical example of that idea. It gave agents a controlled way to discover and use real company data instead of relying only on whatever someone pasted into a prompt.

Hand-drawn diagram showing separate market stacks becoming a shared multi-tenant platform and then a smaller set of consolidated group services

Architecture made the system legible, not automatically safe

Multi-tenancy, service consolidation, and Trino made our environment easier to understand.

An agent could find the market context in the code instead of guessing it from infrastructure. It could inspect related modules in one repository instead of searching across many small services. It could explore company data through a controlled query path instead of connecting separately to every data system.

That made the system more legible.

But a system that is easier to understand is not automatically safer to change.

Our 2024 retrospective made this distinction clear. Some quality outcomes improved. We expanded test automation and reduced parts of our bug backlog. At the same time, several mechanisms meant to sustain quality were weaker than we wanted.

Code-quality visibility depended on a tool that stopped being used, and we did not replace it quickly. Architecture review existed as an intention, but it had not become a lightweight, repeatable part of delivery. Production-quality reporting arrived late. We had bug-resolution expectations, but the follow-through was inconsistent.

The lesson was not that quality declined everywhere. It was that improvements did not sustain themselves.

These were not principles we had forgotten to write down. We had already said that quality, ownership, monitoring, and long-term thinking mattered. What was missing was consistent enforcement inside the workflow.

AI makes that gap more important.

An agent can understand the tenant model, find the right module, and query the right data. Those foundations help it decide where to work and give it better context for the task.

They do not prove that its change is correct.

This is where I think many agentic workflows are moving in the wrong direction. The agent produces something, then the engineer spends time asking why it is correct. The agent responds with a convincing explanation, and the engineer has to reconstruct the reasoning step by step.

That does not create much leverage. It moves the effort from implementation into review.

The agent should be responsible for producing evidence that it did the right thing.

For a bug fix, it should reproduce the failure before the change and show that the same case passes afterwards. For a code change, it should run the relevant tests, type checks, and linters and report the actual results. For a user-interface change, it should exercise the flow and provide screenshots or browser evidence. For a data question, it should return the query, source, assumptions, and result. For a production change, it should show the relevant logs, metrics, deployment checks, and rollback path.

The required evidence should match the risk of the change. A small documentation edit does not need the same proof as a payment-flow change.

An explanation can still be useful, but an explanation is not verification. A model can explain an incorrect result as confidently as a correct one.

The engineer's job is to judge whether the evidence is relevant, sufficient, and trustworthy. That still requires experience and human judgment, but it is a much higher-leverage use of them than repeating all the work the agent was supposed to do.

The distinction I use now is:

Legibility helps an agent act. Evidence tells us whether the action was correct.

An agent-ready engineering system needs both.

It needs explicit context so the agent can understand the environment. It also needs workflows that require the agent to prove its work before asking a human to accept it.

Without the first, the agent spends its time guessing.

Without the second, the reviewer spends their time reasoning on behalf of the agent.

What agent-ready means to me

I now think an agent-ready engineering system has four characteristics.

First, important context is explicit. Business dimensions, technical constraints, and ownership rules appear in code, data, tests, documentation, and runtime contracts. They are not known only by the people who have been around the longest.

Second, the system's surface area is intentional. Every repository, service, deployment, and convention adds operational and cognitive cost. Each one should exist for a reason.

Third, access to data and tools is governed and reusable. Agents should operate through controlled interfaces with the user's permissions. They should not receive a collection of broad credentials simply because integration is easier that way.

Finally, evidence is part of the output. Tests, validation results, screenshots, queries, logs, and deployment checks are deliverables, not optional follow-up work.

An organization assessing its own readiness can look for a few signals:

  • Important assumptions that experienced engineers know but the system does not express
  • Product changes that require navigating many repositories and runtime patterns
  • Data that is available to humans but lacks a safe path for agents
  • Tests and reviews that allow confident output to pass without proving correctness
  • Generated work for which no person clearly owns the production outcome

Buying another AI tool will not remove these constraints.

The boring foundations mattered

Multi-tenancy, service consolidation, and Trino were not predictions about the future of AI.

They were pragmatic responses to problems we already had. We wanted less duplicated infrastructure, fewer unnecessary moving parts, better access to data, and a stronger engineering workflow.

Their later AI value came from the same underlying property: they turned hidden organizational knowledge into explicit, reusable contracts.

After Claude Code arrived, that value became much easier to see. The parts of our environment that were clear to engineers were usually clearer to agents. The parts that depended on tribal knowledge, inconsistent conventions, or weak feedback remained difficult.

The tool does not fix the operating model. It amplifies it.

Multi-tenancy, consolidation, and Trino gave our agents a clearer system to work inside. The harder work is making sure that testing, review, monitoring, and ownership remain strong enough to control the increased speed.

The boring foundations mattered. They still do.

If this perspective resonates with you, subscribe to my blog. I share what I learn while building real systems with AI in the loop. You can also follow me on X or Threads for more thoughts and ongoing experiments.