Build for leverage

The demos show a coding agent with free rein over a fresh project, turning a prompt into a working feature in a few minutes. Inside an organization with something to protect, the same agent has a very different day.

It starts with a design doc the agent can't open, because it isn't allowed to reach the internal docs system, so the engineer exports the doc and pastes it in. The agent builds the feature but can't run a headless browser to check that the page renders, so the engineer opens one and looks. Along the way the agent finds a bug and wants to hand the fix to a subagent, but the subagent needs its own worktree and git is banned, so the engineer makes the fix. By evening the skill the agent relies on has made the same mistake several times, and the agent can't correct it because it isn't allowed to touch its own configuration.

Each of those restrictions guards against a risk, and each one blocks the useful work along with the dangerous work. The engineer ends the day as the agent's hands, fetching and checking things the agent could have done itself. We're getting a fraction of the value AI offers while still giving up ownership of our code and products, because our systems were built for engineers writing code by hand.

Where we are#

I love to code, and I've been doing it since long before agents came on the scene. There's something beautiful about crafting a well-designed, readable, flexible system that handles a hard problem gracefully. That said, the industry is changing whether we like it or not and hand crafting code is for the most part becoming less common.

Engineers I talk to at small, medium, and large companies all tell me agents now write most of the code on their teams. I think hand-written code is going the way of hand-written assembly. It will survive in the few places that need it and fade from everywhere else.

However, engineering is still here. The work has moved to building the systems that let agents work well and the systems that keep up with what they produce. That's where engineering effort belongs for the next several years, and most organizations haven't really started on it yet.

An agent gives an engineer a lot of leverage, but today most organizations waste much of it. Some restrict their agents until they're barely more useful than the engineer working alone. Others restrict almost nothing and carry a large risk they can't see. I think there is a third option, which is to build systems that let agents work freely while keeping the risk visible and small, and an organization can start on it today with infrastructure it mostly already owns.

The laptop is the wrong place for an agent#

An engineer's laptop is one of the most trusted machines an organization owns, since historically the assumption has been that a person with judgment sits in front of it. It carries the engineer's credentials, often with root or admin access to the systems they own. From it, the engineer can read and write production, reach customer data, approve code reviews, and send trusted messages to other employees. An agent running on that laptop inherits all of that access.

Organizations that restrict their agents usually do so at the tool level, by banning git, blocking the browser, or putting an approval prompt on every shell command.

Each of those bans is a blunt stand-in for one outbound risk. Reading a design doc is harmless, and exfiltrating it is the risk. The same split runs through git, where git worktree is harmless and git push to an unreviewed remote is the risk, and through the browser, where loading localhost:3000 is harmless and browsing to an arbitrary site is the risk. The laptop gives a security team no other place to enforce a rule, so they ban useful tooling outright, harmless uses included. Those harmless uses are how an agent gathers the context it needs, so banning them cuts into the leverage it offers rather significantly.

The bans also leak, since a rule against curl does nothing about python -c with an HTTP library, and every interpreter on the machine is another way around a command denylist. That makes a denylist a low-leverage control. Security teams spend effort on every tool it covers and it still leaks, so the lists keep growing and the agents keep getting less useful.

The ban on editing configuration is the clearest example. When the guardrail lives on a machine the agent controls, the agent can't be allowed to touch its own configuration, because a change there could switch the guardrail off. The guardrail needs to live somewhere the agent can't reach.

Move the boundary to the network#

Give the agent its own box, with root inside and every outbound request passing through a gateway the agent can't modify. For example, the box could be one or more containers per engineer in a managed Kubernetes cluster. Moving the guardrail to the network is the highest-leverage change in this setup, since one control at the network replaces every ban on the laptop.

Inside the box, nothing is banned. The agent can run git, start databases, drive headless Chrome, spawn subagents in their own worktrees, install tools, and rewrite its own skills and settings. The box still holds source code worth protecting, and the agent gets root anyway because the protection sits at the network, where nothing the agent does inside can change it.

The box runs under a delegated identity, a service principal that acts for one engineer. It inherits that engineer's read access to internal code, documentation, and production observability, so it can pull the design doc, read the service's dashboards, and search the logs for the error it's chasing. It appears in every audit log under its own name, so the organization can tell what the engineer did from what the agent did on the engineer's behalf.

The gateway needs three ways to handle traffic that leaves the box, depending on what a request could do.

  • Pass and log. The request goes through and is recorded. An example would be pushes to the internal forge. Code review and source control policy are what keep unsafe code from shipping, so the push itself can go through.
  • Check. A system decides whether each request looks like exfiltration, then blocks it or lets it through with an audit record. For example, outbound web requests for documentation or search can go through this check. Fast, cheap classifiers are one way to build that check, such as TypeSafe's jev. There are other products on the market, and an organization can build its own.
  • Ask a human. A person approves the request before it goes out. Examples would be publishing a package to a public registry or opening an issue on a public repository, where anything the agent sends becomes public.

Model inference has to sit inside the circle of trust. If the model's endpoint counts as outbound traffic, every token the agent reads leaves the organization, which is a much bigger problem than any web request. Services like Amazon Bedrock run models in accounts the model providers can't access, so the providers don't see your prompts or completions, and the traffic can stay on a private network link. Organizations already trust their cloud provider with the production database, and trusting the same provider with source code is the same kind of decision.

The goal is to give the agent free rein inside the box without letting anything harmful leave it. An engineer usually stops to think before doing something expensive or dangerous, and an agent may not, so the checks have to sit where the agent can't skip them. No setup removes the risk entirely, but this one puts every outbound request through rules and classifiers that decide what to block.

Model providers have already built similar controls into their own agents. Claude Code runs agent commands in an OS sandbox behind a filtering network proxy. OpenAI's Codex cloud blocks internet access during the agent's work by default, and its documentation names prompt injection and code exfiltration as the reasons. I'm arguing that organizations should apply the same controls to every engineer's agents.

Remote machines with the trust reversed#

Remote development machines aren't new. Codespaces, Coder, and Google Cloud Workstations sell them, and the largest tech companies have used remote machines for engineers for a while. Builds run faster on big machines in a data center, and it's cheaper to load-balance a fleet there than to ship oversized workstations to every office. That used to be a concern mostly for hyperscalers, since only they had the build times or team sizes to make it worth the trouble.

Agents give every organization a reason to make the same move, this time with the trust model reversed. Today's remote machines are trusted like laptops. They carry the engineer's credentials and have open egress, because a person is at the keyboard. An agent's box is deliberately less trusted than the engineer's laptop. It has its own identity and a gated network, and the agent gets root because the protection sits at the network instead of on the machine.

Most organizations already own the cluster, the package mirror, the egress proxy, the service account system, and the audit log. They just haven't put those pieces together this way yet. The box also follows the economics of other cloud services. It spins down when nobody's using it, and an engineer whose agents need more compute gets more boxes.

No filter is perfect#

A classifier on outbound requests will miss things. For example, a patient attacker could split data across many requests that each look harmless. Delegated identities for agents are also new, and most identity systems weren't designed with them in mind. Review as a security gate depends on reviewer agents doing that job well. Each of these is an engineering problem an organization can work on and measure. On a laptop, the same risks are spread across every tool the agent might call, and a denylist covers only the tools someone thought to list. In the box, every outbound request goes through the gateway, which gives the security team a single point to tune rules and improve checks over time.

Build for the agent's experience#

Once the agent has room to work, the next investment is in how well it works. Developer experience shaped decades of tooling, and agent experience will shape the next decade even more, for a reason unrelated to how smart the models get. A person learns to work around bad tooling once and remembers the workaround, but an agent starts every session fresh and pays the full cost again each time, across every parallel run. Fixing the tooling works the same way in the agent's favor, since one fix pays off in every session and parallel run after it, which makes agent experience one of the best places to look for leverage.

Agent experience comes down to two things: finding the context it's missing, and checking its own work.

Context#

An agent that starts from a task description and a repo is guessing. The context that makes an engineer good at their job lives in design docs, architecture notes, dashboards, logs, and old incident reviews, and an agent on a restricted laptop can reach almost none of it. In the box, under a delegated identity, it can reach all of it. The next layer of work is making that context usable, with internal systems that have CLIs and APIs an agent can call, documentation the agent can search from the command line, and production metrics the agent can query to see how the service it's changing behaves today.

If someone on the team could answer the agent's question by looking it up, the agent should be able to look it up too. Each time it can't, a person goes back to being its search engine.

Verification#

The agent also needs to check its own work before anyone else has to. Unit and integration tests are a good start, and engineers have relied on them for a long time. They tell the agent the code does what the tests say, and they say little about whether the feature works.

An app that seems impossible for an agent to verify, usually because it's a UI, is missing an interface, and the fix is to build one.

Consider a checkout flow. An agent can check it by driving a browser through the flow and taking screenshots, which works but is slow. The checkout can instead expose its state as a stream of JSON lines. The agent sends "add item, apply coupon, change shipping address" and reads back totals, tax, and validation errors without a browser. It can run a thousand cases in the time one screenshot round trip takes, and it can tune the business logic until every case passes.

The aim is fast, reliable checks on the business logic that don't depend on the UI, so the agent can run them on every change. The UI still needs tests that it looks correct, and many visual tests check business logic along the way. Separating the two means the agent doesn't have to render a page every time it wants to know whether a coupon applied. The tests for my terminal UI framework render to a grid of characters and compare it against a picture of the expected screen written as a string, which is one way to make the visual check fast as well.

The agent improves its own setup#

Inside the box the agent can also edit its own configuration, which turns agent experience into a loop. When a skill keeps making the same mistake, the engineer and the agent fix it together and keep what works. The box also makes it cheap to evaluate changes in the background. Give the same task to agents with different skills or settings, and compare which one produced the cleanest review, used the fewest tokens, or finished fastest. On a laptop that loop is banned, but in the box it's how the setup improves week over week.

Review the firehose#

Once the agent can reach what it needs and check its own work, it produces far more code than a person would, and it multiplies a bad change as easily as a good one. Pull requests of a few thousand lines are already normal, and few people read several of them a day line by line.

From the engineers I talk to, and from how quickly the industry has turned to pull requests written by agents, it looks like we've already started signing off on code we haven't fully read. Reading every line won't come back at this volume. We need a review system that decides where human attention goes, and I think it needs three things.

Structured changes. The agent organizes its work instead of dumping it. A change arrives as a stack of small, ordered reviews, each with a title that says what the slice is for, so a reviewer with no context, person or agent, can follow it. I've written about stacks before, and I'm building GitStack to address this.

Agent review before human review. Several reviewer agents read the stack in parallel, a judge decides which findings are worth acting on, and the author agent fixes them, until the stack converges. The reviewers must not share the author's context. If the author agent talked itself into an overengineered design, or a poisoned README talked it into something worse, the reviewers never saw that reasoning. They see the diff and the titles and judge the code on its own.

Risk scores that route attention. The reviewers score every slice. A slice that adds an outbound HTTP call, a new dependency, or a change to authentication gets a person's full attention, and a rename gets a glance. Human attention is the scarcest input in this system, and risk scores put it where it changes the most.

With changes structured, agents taking the first passes, and risk scores routing attention, the firehose becomes manageable. People spend their attention where the risk is, and the first rounds of review happen without them.

The same day, rebuilt#

This time the engineer and the agent begin with the goal. As the engineer describes what they want, the agent pulls in the supporting material it needs, like the relevant design doc, the code it will touch, or the service's dashboards. The questions it brings to the engineer are about things that aren't written down anywhere, like why the architecture looks the way it does, which tradeoff the business wants, which constraint is soft, and what done means. Together they turn the answers into a spec.

During implementation the agent works with more autonomy, building to the spec it designed with the engineer. It splits the work across subagents, each in its own worktree on the box. Each one runs its own loop of implement, review, verify, and refine, mostly against unit and integration tests. The agent then assembles their work and checks the feature end to end, through its state stream and a final screenshot. One subagent finds a bug and hands it to another. Partway through, the agent notices its skill keeps making the same mistake, fixes the skill, and reports what it changed. If quality slips at this stage, the planning tooling or skills need work, since the spec should carry everything the agent needs.

The work arrives as a stack of six reviews. Reviewer agents have already been through it, found problems, and had them fixed. Four slices are marked low risk, and the engineer skims them. Two are marked high, one that adds a call to an external payment API and one that changes a permission check. The engineer reads those two line by line, asks for one change, and approves.

The engineer spent the day deciding what to build and judging the slices that carried risk.

Engineering has always been about thinking clearly and communicating intent, and for most of its history that intent was written in code. It depends on trusting your instinct and reasoning carefully about technical and product decisions. With agents writing the code, an engineer should spend more time on those fundamentals and less on the mechanics of the code itself, because thinking clearly about a system is how you find where to push.

The models can already do much more than most organizations let them. Closing that gap takes systems we know how to build, and the organizations that find the leverage in them will get far more out of AI while keeping ownership of what they ship.

Opinions expressed here are my own and do not reflect those of any employer, past or present.