A coding agent can ask to do some pretty consequential things during an ordinary task, whether that’s installing a dependency, running a shell command, or changing a file somewhere it wasn't originally expected to touch. The model can request any of those actions, but whether they actually happen depends on the software around it.

The same model can sit inside a tightly constrained runtime on one team and have much broader access somewhere else.
In practice, the agent harness is the runtime and orchestration software around the model that manages the agent loop, tools and execution. A lot of teams can handle those decisions locally.
At least, at first.
Problems creep in once several harnesses start doing their own version of model access, routing, logging or cost attribution. Nothing necessarily breaks and the agents keep working. Then a shared rule changes and somebody has to work out how many slightly different copies of it are sitting around.
An agent harness is the runtime around the model
Take an agent making a change to an authentication service.
It reads the controller and a couple of tests, makes an edit, runs them, gets a failure back and goes looking somewhere else in the codebase. The model is making decisions throughout that process, although it isn't directly reading the repository or executing the test command.
Something has to expose the file system, run the command and return the result so the model has something new to work with.
Broadly, that surrounding runtime is the agent harness.

There isn't a completely fixed boundary around the term. Tool execution and the run loop are usually in there. Retries might be too. Approvals and telemetry can move around depending on how the agent was built and what the rest of the engineering stack already provides.
We've also seen problems appear when agents are running on individual engineers' laptops.
The machine where the agent works can have a different set of tools, credentials and assumptions from the environment where the code eventually runs. For plenty of changes that barely matters. Once the same workflow is supposed to behave consistently across a lot of engineers, it starts becoming harder to ignore.
A controlled runtime gives you somewhere to decide those things deliberately.

The agent might be able to read most of the repository but only write to one service, while its shell runs inside an isolated environment with access to the package registry and test runner but no production AWS credentials.
You can already see this becoming part of the coding-agent stack.
Docker Sandboxes run coding agents inside isolated microVMs, with separate controls around the filesystem and credentials. The agent can still work against a repository, while other host resources stay outside the sandbox unless they're explicitly shared or forwarded into it.

A sandbox is only one part of that runtime. The harness still has to manage the agent loop, expose tools and decide what information goes back into the next model call.
In that environment, npm test can run normally while terraform apply might require approval or simply fail because the runtime never received the credentials it needs.
A harness controls what the agent can do
By the time the model asks to use a tool, several decisions may already have been made for it:
Which paths are writable
Whether the shell has external network access
Which credentials were injected when the run started
Whether a deployment tool is even installed
Before an action
A frontend task probably needs the repository and a test runner. Reading infra could still be useful if some deployment configuration explains how the application is wired together.
Writing to infra is another matter.
You might mount it read-only, let the runtime reach the package registry without opening arbitrary external access, and leave production credentials out of the environment entirely.
Access doesn't have to mean putting a long-lived cloud credential into the runtime either. AWS STS can issue temporary role credentials, while session policies can narrow the permissions available for that particular session.
We've found it useful to ask a very basic question here: does the agent need this capability for the work it's doing? Quite often the answer removes the need for another policy check.
You can still tell the model not to deploy anything. That may save it from wasting part of the run trying, while the actual boundary comes from what the runtime allows rather than whether the instruction was followed.
When an action is requested
Shell access gets out of control fast because a generic permission doesn't tell you much about the command being attempted.
An agent might run npm test, then later ask for terraform apply. Both use the same shell, but the second request has very different consequences.
Once the command exists, the runtime has more information available. It has the exact request, the run it belongs to, the environment where it will execute and whatever permissions were attached when the task started.
Existing coding agents already expose controls at roughly this level.
Claude Code has allow and deny rules for tools, different permission modes, and explicit controls for adding directories the agent can access. You can allow a pattern such as particular Git commands without treating every possible Bash command as equivalent.

A model request from the same run can pass through a gateway, where model-access rules or routing are applied and telemetry is recorded. The gateway doesn't automatically receive the file-system event that happens afterwards or the command that fails locally unless those events are deliberately sent there.
Some implementations blur these boundaries more than others.
After an action
Tool results can be awkward in ways that don't show up in the permission model.
A test might fail with three useful lines of output, while another command dumps 40,000 lines into the terminal. Something times out. The agent changes the same piece of code three times and keeps getting variations of the same failure.
Some harnesses trim or structure that output before another model call. Others pass much more of it through.
Scope can move as well. The task starts in one service, the agent follows a dependency, then decides the fix it wants involves another repository or an infrastructure change that wasn't part of the original work. It can ask for more access without automatically receiving it.
If the task required the tests to pass, a passing result is better evidence of completion than the model saying the work looks finished. Of course, that might only be the local suite. CI can still find something else later.
Instructions influence behaviour, controls enforce it
A repository can tell the agent which test command to use, how a service is structured, or which technologies the team expects it to use.
We've heard the problem from enterprise architects who already had standards for approved frameworks and technologies. The standards weren't missing. Coding agents were being used without enough of that context, and the result was actually more technology sprawl because the agents were reaching for frameworks and technologies outside the enterprise standards.
The policy existed but it just wasn't necessarily reaching the thing writing the code.
Instruction files and other context can help with that. They still aren't the same as a hard boundary.
“Don't modify infra” tells the model what it should do. A read-only mount decides what happens if it tries anyway.

Shared model policy shouldn’t live in every harness
Keeping model selection, fallback behaviour, request metadata and cost tracking inside one harness can be perfectly reasonable.
Then another team builds an agent.
One runtime attributes spend to a developer while another uses a repository. Somebody adds a fallback model to one of them. An approved-provider list appears in two configurations. A third team needs slightly different behaviour and makes another version rather than turning the first two into shared infrastructure.
The agents still work, so nobody has much reason to touch any of it.
Now a provider is no longer approved for a particular workload. Before changing the rule, somebody has to find out which runtimes are carrying their own version of the provider policy and whether they all interpret the workload in the same way.
Our view is that controls which genuinely apply across model traffic shouldn't have to be rebuilt around every harness.
That matters more once model choice changes with the workload. Some enterprises are perfectly comfortable sending one class of work to a particular provider while more sensitive engineering work has residency, sovereignty or infrastructure requirements that send it somewhere else.
A provider-native view only covers the model traffic going through that provider.
That's also one reason we don't think the harness, model, cloud and underlying infrastructure should have to come from the same vendor. In a composable stack, an enterprise might choose one harness for how it works with developers, different models for different task classes, and its own cloud because that's where the workload is allowed to run.
A shared model layer is useful for things that really are shared across those runtimes, including provider rules, model access, routing and model telemetry.

It doesn't need to absorb everything else. A denied tool call might still only exist in the harness logs, along with the failed command or the file that was actually changed.
Harness, gateway, and Software Factory control different things
The boundaries here aren't as neat as an architecture diagram usually makes them look.
Close to execution, the runtime has access to the requested tool call, filesystem permissions, mounted credentials and the result of the previous action.
In the model path, a gateway can receive the model request, routing information and whatever workload metadata the harness sends, while recording things such as token usage. Further out, the Software Factory may have the task specification, CI results, approval records and whatever evidence is required before the work can move forward.
GitHub's required status checks are a straightforward example. An agent can finish its run, open a pull request and have every test it ran locally pass. If a protected branch still has a required CI or security check failing, GitHub can block the merge. The agent runtime doesn't need to own that decision.
Not to mention there’s overlap. A harness can record model cost for one run while a gateway aggregates model usage across many agents and requests. Existing CI, identity, platform and security systems will already own parts of this in plenty of enterprises too.

Put each control where it actually has enough context
A narrow agent changing one repository doesn't need the same permissions or execution envelope as an agent allowed to work across services. Some enterprises already have platform controls that can be reused. Others will put more responsibility into the harness because that's what they have today.
Controls also accumulate in ordinary ways.
A team needs two models, so it adds model selection. Later it adds fallback, then cost tracking. Another team needs something similar, except its metadata works differently, so it builds another version.
Nobody sat down and decided the enterprise should have five implementations of model policy. It just ended up there.
A shell restriction still needs execution context. A provider rule that's supposed to apply across every engineering workload probably shouldn't be copied into every runtime. Merge approval pulls in information the immediate agent loop may not have at all.
There'll be grey areas once existing platform and security systems are involved. Some controls will also be sitting where they are for no deeper reason than that was the easiest place to put them when the first agent was built.
If you're working through those boundaries in your own agent stack, book a demo to see how shared model controls can sit across your existing harnesses without pulling local execution into the same layer.




