What Made It Actually Work at Scale

The hard boundaries, adversarial review, operating patterns, and architecture that turned Texture’s AI agent fleet from an experiment into a durable part of how we build.

Victor Quinn, Co-founder and CTO
16 minute read
What Made It Actually Work at Scale

Part 3 of a 5-part series on running an AI agent fleet inside a real company

Giving every agent its own identity solved an important problem for us. It also created a new one we did not see at first.

Before agents had individual GitHub accounts, they all committed through the same GitHub App. That app could open pull requests, but it could not merge them. When we replaced that shared identity with named accounts, the work became attributable to a specific agent. But those accounts also inherited the same merge authority as our human engineers. Nothing about the change was intended to expand what agents could do. It happened as a side effect of making them legible.

Direct pushes to main were never possible. Our branch rules required every change to go through a pull request and receive a successful human review. The agents also had an explicit instruction not to merge. The instruction existed. It just wasn't a control. And neither branch rules nor instructions captured one important distinction: a pull request can be approved without being ready to deploy.

We discovered the gap indirectly. An engineer would notice that an approved pull request had been merged and wonder who had made the final call. No one remembered doing so. After investigating several of these small mysteries, we realized that well-meaning agents were finding approved pull requests and merging them, sometimes including their own.

At Texture, merging to main triggers our deployment pipeline. An agent merging a pull request is not just tidying up GitHub. It can start putting code into production. The examples we found were low-risk: a marketing page, an SEO and prerendering fix, and a device-manufacturer seed list. None became an incident.

We got lucky.

The fix was to make merge authority its own hard boundary. Today, no agent has autonomous merge authority. An agent can investigate a problem, write the code, open a pull request, respond to review feedback, and get the work completely ready. It cannot make the final decision to ship. A human has to do that.

That distinction is where this post starts. In Part 2: Give Every Agent a Badge, I wrote about identity and access: who an agent is, what it can reach, and how its work becomes attributable. Those controls answer one kind of risk. They do not answer what happens when a well-meaning agent makes a bad decision with access it legitimately has.

To run agents at scale, we needed two different kinds of guardrails.

Soft guardrails tell an agent how to exercise judgment. Hard guardrails define what the system will allow, regardless of the judgment it exercises.

Confusing the two is how experiments become incidents.

Put the hard rules in the hard infrastructure

Prompts, operating instructions, and playbooks matter enormously. We use them constantly. They teach an agent how we want it to investigate, when it should ask for help, what good work looks like, and which tradeoffs Texture tends to make. They are especially useful where context and judgment matter.

But an instruction is still interpreted by a language model. It can be misunderstood, outweighed by another instruction, or followed in a way you did not anticipate. That makes it a poor place to enforce anything with a real blast radius.

Think about an office building. A sign saying "authorized employees only" is useful. A badge reader on the door is a control. You want both, but you would not replace the badge reader with a more emphatic sign.

The simplest mental model we have found is to treat an agent like an intern on its first day. You would not give a new intern production database access just because it might someday be useful. You would give them the minimum access required for the job in front of them, then expand it deliberately when the work demands it. An agent working on the frontend might need Sentry to investigate browser errors. It does not need access to backend logs it will never use. Individual identity and credentials make that boundary enforceable, as I covered in Part 2. The operating principle is much older and simpler: least privilege.

We eventually applied that same logic across the fleet:

  1. Use soft guardrails for judgment. How thoroughly should the agent investigate? When should it red-team its own answer (more on that below)? What conventions should it follow? Those belong in instructions and reusable playbooks.
  2. Use hard guardrails for authority. Can it merge? Can it write to a production database? Can it reach a sensitive system? Those belong in branch protection, network boundaries, identity controls, and permissions the agent cannot talk its way around.
  3. Assume mistakes will happen. The goal is not to produce a model that never gets anything wrong. The goal is to build a system where a wrong answer becomes a reviewable artifact instead of a production event.

Make the agent argue against itself

Red-teaming has become one of the most powerful techniques we use with agents. The idea is simple: do not accept the first plausible answer. Once an agent has produced a plan, diagnosis, or draft, give the work to fresh reviewers whose job is to attack it.

We make that concrete by assigning distinct adversarial perspectives. For a strategy document, one reviewer might look for security gaps, another for unsupported claims, another for operational failure modes, and another for places where the argument will lose a skeptical reader. We often run those reviews across multiple models, then have the primary agent compare the findings, look for points of convergence, and revise the work. A generic instruction to "double-check this" rarely creates enough distance from the original answer. A fresh context, a specific skeptical role, and permission to disagree usually do.

Model diversity creates another kind of distance. Because we route agent traffic through OpenRouter, each agent can use one API key to reach models from many providers and choose a different model for each adversary. One critic might run on Claude Opus, another on Grok 4.5, another on ChatGPT Sol, and another on something else entirely. This reduces the chance that every reviewer shares the same model-specific blind spots, and it lets us use different models for the kinds of reasoning where each is strongest. The goal is not to stage a model horse race. It is to keep one model's habits from quietly becoming the boundary of the review.

This is a force multiplier because generating a credible answer and trying to disprove it are different jobs. Models are prone to anchoring on the path they have already taken, much like people are. The more context you provide, the more useful an agent can become, but it can also get wrapped around the axle of that particular context. A red-team pass steps outside the accumulated conversation. Reviewers arrive cold: they see only the work and the question they have been asked to challenge, which lets them notice assumptions and alternatives the original agent has stopped seeing. Red-teaming turns one agent's first pass into raw material for a small panel of critics, at a cost and speed that would be impractical if every review had to begin with a room full of specialists.

It does not make the result automatically correct, and it does not replace expert or human review. It makes the work that reaches that review substantially stronger. Weak assumptions get surfaced, missing evidence becomes visible, and the final human decision starts from something that has already survived an adversarial pass.

Every code change now passes through independent catches. CodeRabbit analyzes every pull request, whether it came from a person or an agent. It has been consistently valuable throughout the life of the company. In practice, it acts as its own small red team: CodeRabbit sees only the diff, without the accumulated context or assumptions of the person or agent who wrote it. A human still has to review and approve the work. And approval does not authorize an agent to merge it: a human separately makes the final decision to ship. The realistic failure mode is an agent writing a mediocre or incorrect pull request. That is annoying, but bounded. It gets caught in review or waits for a human rather than shipping itself.

The safety claim is not that agents cannot make mistakes.

It is that they cannot put those mistakes into production without a person deciding to let them through.

That creates an unusually favorable tradeoff. An agent is writing a pull request, not shipping code. In the worst case, it produces an awful change that a reviewer dismisses. The damage is a little wasted compute and review time. In the best case, it works in the background, finds and implements a solution autonomously, and measurably improves the product. The human only needs to inspect the finished work and decide whether it is good enough to ship. We get autonomous execution while keeping the consequential decision with a person. That combination is both a game changer and remarkably safe.

Decide what you will offload before the work arrives

Once the hard boundary was in place, we could be much more aggressive inside it. We did not have to debate from scratch every time an agent found a bug or an alert fired. We had a clear operating model for which work belonged with the fleet and which decisions stayed human.

Our non-negotiables are simple:

  1. Bug fixes: yes. An agent can reproduce the issue, trace the relevant code, write a fix, add tests, and open a pull request.
  2. Troubleshooting: absolutely. This is one of the fleet's most valuable jobs. An agent can inspect logs and monitoring data, follow one clue into another system, query the data it is authorized to read, test a hypothesis, discard it, and keep looping until it finds the root cause. A human can do the same work, but usually in a serial chain of interruptions. An agent can stay on it without losing the thread.
  3. Architecture decisions: no. The fleet can gather context, identify options, challenge an assumption, and help document a decision. The actual architecture is human-driven and human-checked. No exceptions.
  4. Production deployment: human decision. Agents prepare changes. Humans decide whether those changes ship.

These boundaries matter because not all autonomy is the same. Letting an agent spend an hour investigating a Sentry alert inside a read-only environment is fundamentally different from letting one redesign a system or alter production data on its own. Talking about "agent autonomy" as one giant yes-or-no choice obscures the useful part: you can grant a lot of freedom inside a carefully chosen box.

The box matters. Our agent fleet runs with a separate cloud vendor from Texture's production infrastructure, with no network path between them. Access is least-privilege and read-only by default. Standing access explicitly excludes data stores containing customer PII or sensitive grid data. Texture is also SOC 2 Type 2 certified, with the controls independently audited and available through our public trust center.

That is not a promise that software is infallible. It is a description of the system around it.

The default is not absolute. Sometimes a bounded job genuinely requires more access. In those cases, the permission is scoped to the task, limited in time, and revoked when the work is finished. I will show what that looks like in practice in Part 4.

Model cost without attribution is just a bill

Safety was not the only scaling problem. The fleet was also consuming more models, across more providers, doing more kinds of work. Direct provider keys made every change harder than it needed to be. Switching a model meant changing credentials or configuration. Comparing spend meant reconciling separate dashboards. Taking advantage of different pricing or provider credits meant touching the agents themselves.

We had already moved model access behind OpenRouter for the model diversity I described earlier. It solved this problem too: one place to route requests across providers, switch models without registering and distributing another set of credentials, and see the cost of the fleet as a whole.

Then we repeated a mistake from Part 2.

We gave every agent the same key.

The shared key made routing easier, but it erased attribution. We could see what the fleet cost without seeing which agent generated the spend. That is the billing equivalent of making every engineer commit through the same GitHub account: the total is visible, but the operating information is gone.

So we moved to a separate OpenRouter key for every agent. Now model spend is attributable to the role producing it. We can see which agents are being used heavily, which workloads are expensive, and whether a cheaper model actually produces a cheaper outcome once retries and failed work are included.

That last part matters. The least expensive model call is not always the least expensive way to finish a job.

The pulse is what makes it an agent

A chatbot waits for you to say something. Our agents wake up on a schedule.

OpenClaw calls this a heartbeat. On each pulse, an agent checks the systems relevant to its job. An engineering agent might look for a newly assigned Linear issue, review the status of its open pull requests, check whether someone left feedback, and decide what to do next. A coordination agent might look across incoming bugs, stalled work, and alerts, then route or follow up without a person asking it to.

That scheduled check-and-act loop is one of the most important differences between a chatbot and something that can operate more like a teammate. It is also much harder than it sounds.

Our first instinct was to run heartbeats on a cheaper, faster model. The work looked routine: check a few systems, notice what changed, take the obvious next step. Why spend more reasoning capacity on that?

Because the next step was not always obvious.

The agent had to reconcile state across several systems. An issue might look idle in Linear while the associated pull request was waiting on a human review. A failed check might mean the code was wrong, or that an external service had flaked. A Slack message might change the priority of work already underway. The agent needed to distinguish "nothing to do" from "something is stuck" and "this now belongs to someone else."

The cheaper model did not do that reliably enough. It skipped things, misread state, or failed to carry the loop all the way through. We formalized the heartbeat as a reconciliation pattern: observe the current state, compare it with the desired state, take the next bounded action, and record what happened. Then we moved the work to a stronger model.

That cost more per call and less per completed outcome.

This is a general lesson for anyone building a fleet: optimize for useful work finished, not tokens purchased. Small models are excellent for narrow, deterministic tasks. Once a task requires judgment across multiple systems, the model that looks cheap on a pricing page can become expensive through omissions, retries, and human cleanup.

Good architecture makes bad output obvious

Hard permission boundaries keep an agent from doing something it is not authorized to do. They do not guarantee that the work it produces will fit the rest of the system.

That safety came from an investment we had made long before the fleet reached this scale: strong internal patterns.

Our frontend work uses a company-owned design system: buttons, menus, typography, charts, maps, and the rest of the building blocks that make Texture look and behave like Texture. Agents are expected to use those components instead of inventing a new interface from scratch every time.

Texture's Edges design system organizes 134 production-ready React components into reusable groups.

We learned this one the ugly way. Before that expectation was clear and the system was mature enough, agent-written frontend code was a mess. It worked in the narrowest sense, but it was inconsistent and required too much human cleanup. The model was not missing the ability to write HTML and CSS. It was missing a constrained vocabulary for what "correct" looked like inside our product.

The design system provides that vocabulary. It makes good output easier to produce, and deviation easier to spot. If an agent free-hands a component that ignores the established system, it looks wrong in the preview and in review. The pattern is a productivity multiplier and a safety net at the same time.

The same idea applies to the backend. Texture is organized into focused services, each owning a clear business domain and exposing a well-defined API surface. Those services are composed into one coherent graph that the frontend can use. An agent does not need to invent where telemetry belongs, how locations should be represented, or which system owns alerts every time it builds something. The architecture already answers those questions.

If an agent ignores that pattern and creates a one-off endpoint in the wrong place, the deviation is obvious. It does not fit the shape of the system, so the automated reviewer or a human reviewer can catch it quickly. More often, the agent can assemble significant new frontend capability from what already exists without needing new backend work at all.

This is the part of AI adoption that gets underestimated. Companies often ask whether a model can write code in their codebase. A better question is whether the codebase has made the right answer legible.

This is not a deviation from what is good for human engineers. The same patterns make the code easier for people to read, reason about, and review. They reduce one-off decisions, keep implementations consistent, and give a new engineer a map of how the system works instead of asking them to reconstruct years of unwritten context.

What changed was the level of diligence required. A human-only team can compensate for a fuzzy pattern through experience, conversation, and judgment. Autonomous agents will reproduce whatever pattern the codebase makes easiest to see, at far greater speed and volume. That forced us to double down on making the good patterns exceptionally clear, consistent, and reusable. Generative AI also makes that work faster than it has ever been: documenting a convention, consolidating duplicated approaches, or migrating code onto a shared component is now much cheaper.

This is why "AI slop" is not an inevitable consequence of using agents. It is often the result of letting them take the wheel in a codebase that has not made quality legible. Giving an agent broad freedom to generate whatever works is very inadvisable. Give it strong patterns to extend, and both the agents and the humans produce more coherent work.

Agents amplify the environment you give them. Clear boundaries, reusable components, and coherent architecture make them dramatically better. A pile of exceptions and undocumented conventions gives them more ways to be wrong, faster.

As of this writing in August 2026, Texture's monorepo had crossed pull request number 14,000, with 12,091 pull requests merged over the company's history. Agent accounts authored roughly 1,900 of those merged pull requests, or about 16 percent.

That lifetime number understates the current reality because its denominator includes roughly two and a half years before we had autonomous agents doing meaningful work. Since January 1, agent accounts have authored 1,737 of the 5,343 pull requests merged into the monorepo: nearly one-third of all pull requests merged this year.

A chart showing that autonomous agent accounts authored 16 percent of Texture's merged monorepo pull requests over the company's history and 33 percent in 2026 through August 6.

The number matters less as a score than as evidence that this is not a demo. The fleet is participating in the daily work of the company at meaningful volume. It handles bugs, investigations, implementation, follow-up, and all the mechanical connective tissue around those tasks. Humans still own the architecture, the tradeoffs, and the decision to ship.

This was never a headcount-reduction exercise. The point is not to take the same roadmap and find fewer people to execute it. The point is to expand what the same team can imagine, investigate, and ship while giving people more room for the work that actually requires their judgment.

For Texture, that multiplier is especially important because we are building the operating system for the electric grid. Utilities run an enormous range of critical workflows, and there is a correspondingly enormous amount of software to build. People in the industry are often surprised by how quickly our team ships new capabilities and how we can outpace companies with many times our engineering headcount. Our development pace is not slowing down; it is accelerating, even though we have not added engineering headcount this year. We are using agents to close the gap between the size of the mission and the size of the team. We are not lowering the bar. We are helping a small group of excellent engineers build far more than a team our size ordinarily could.

The honest version is that getting here created a long list of new problems. Identity, credential attribution, model routing, branch protection, observability, reconciliation loops, and design-system compliance: none of this arrived fully formed. We learned most of it by watching something fail, correcting it, and turning the correction into infrastructure.

That is why treating agents like real team members matters. Real identity makes their work attributable. Real access controls constrain what they can reach. Real operating patterns make their output easier to trust. Real guardrails turn their mistakes into things a human can review instead of things a customer experiences.

Parts 1 through 3 have been about building that foundation. In Part 4, I will show what it looks like when the fleet actually goes to work: responding to bugs, shipping website changes for nontechnical teammates, and operating as a second set of eyes during a high-stakes database migration.

That is where the investment starts to pay off.


This is Part 3 of a 5-part series on how we built and rebuilt the way AI agents operate inside Texture.

Victor Quinn
Victor QuinnCo-founder and CTO

Engineering leader with 20+ years scaling systems across 8 industries. Co-founder/CTO at Texture, building next-gen energy infrastructure. J.D. holder and technical architect who believes in code that ships and ships fast.

Built for the people keeping the grid running.

Book a demo and see Texture in action, on your system with your data.