Technical

How to Combine Sandbox Safety with a Decision Layer That Gets the Job Done

Rippletide and Blaxel illustration showing a coding agent working safely in a sandbox, a decision layer checking architecture rules, code patterns, dependencies, permissions, and escalation needs, and an approved action producing real progress

In our previous article The Harness is the Agent: What’s Inside? We’ve made explicit the different parts of the harness, to make it easier to build it. The harness is the assembled system around the model: context, tools, memory, permissions, execution, orchestration, and feedback.

A harness turns an answer into an action. It determines what the agent can see, what it can do, where it can act, and how it learns whether the action worked.

This article focuses on two harness components: the sandbox and the decision layer. They can sometimes look like substitutes, two ways of controlling an agent, but they need to work together because they solve different problems.

The sandbox provides safe execution. It gives the agent an isolated computer in which it can inspect code, install dependencies, run tests, and create artifacts without broad access to a developer machine or production environment.

The decision layer steers the agent toward the intended outcome. It brings the relevant rules, context, patterns, and evidence requirements to a proposed action, then decides whether to allow it, block it, or escalate it.

Consider a PR agent fixing a bug. A sandbox lets it reproduce the failure, run the test suite, and safely try a patch. But a patch that makes the test pass is not necessarily the right change.

To preserve architecture rules, coding habits, and established patterns, the agent needs a decision layer. It can prevent an unwanted cross-package dependency, surface an ownership rule, require evidence for an API change, or redirect the agent toward the repository’s intended design.

Safe execution lets the agent act. The decision layer helps it get the job done as intended.

Coding agent operations split between sandbox actions, a decision hook, and a gated pull request

Different Types of Sandboxes?

A sandbox gives an agent a place to work without granting it the keys to everything else.

But “sandbox” covers several different products. A local container can be enough for a developer tool. An ephemeral cloud container can work for short, stateless tasks. A microVM offers a stronger isolation boundary. A persistent sandbox behaves more like a long-lived computer that an agent can resume between steps or sessions.

First, choose the isolation level. If agent-generated code will execute untrusted dependencies, access customer data, or run alongside multiple tenants, the boundary needs to be stronger than a convenience container.

Then consider lifecycle and state. Does every task begin from a clean image, or must the agent keep its filesystem, installed dependencies, running processes, and repository state across iterations?

Latency matters too. Coding agents repeatedly inspect, edit, test, and retry. Slow provisioning turns every loop into waiting; fast resume makes the sandbox feel like a usable working machine.

Finally, consider the surrounding controls: filesystem and process APIs, programmable network policy, credential handling, observability, cleanup, cost when idle, and how naturally the runtime connects to the agent’s tools.

For this article, we’ll use Blaxel as an example. It was the top-performing sandbox provider we tested for agent workloads, combining isolation with persistent state, fast resume, filesystem and process control, and MCP-native access.

A decision layer answers: should this happen?

A decision layer is the enforcement point between an agent’s proposed action and the tool that would execute it.

It evaluates the action against explicit policies and relevant context, then returns one of three outcomes: allow, deny, or escalate.

This is intentionally different from a longer system prompt. A prompt can tell an agent, “Do not introduce circular dependencies” or “Do not modify public APIs without approval.”

Those instructions are useful context. But they remain instructions to a probabilistic system. Under pressure from a confusing codebase, an incomplete task, or an adversarial issue description, they are suggestions the model may misunderstand, forget, or rationalize around.

A decision layer sits at the boundary instead. The model can reason freely; it just cannot cross the boundary without satisfying the rule.

For a coding agent, the decision layer can run as a hook before any tool call.

Before the agent edits a file, writes a migration, adds a dependency, or opens a pull request, the hook inspects the proposed action and the relevant context.

It checks the architecture rules, coding habits, and established patterns that apply to that part of the repository. It can ask: does this introduce a forbidden dependency? Does it bypass the expected abstraction? Does it follow the team’s error-handling, naming, and testing conventions?

If the action violates a rule, the hook blocks it before the tool runs. If the change touches a public interface, a protected area, or an unresolved trade-off, it can escalate the decision for review.

If the action complies, the agent proceeds. The tool call is allowed with the relevant rules already applied to the decision.

This is not a lint check after the fact. The gate sits between the agent and the tool, not inside the prompt.

Four-step decision flow from a proposed tool call through repository context and a decision-layer check to an allowed runtime outcome

A hands-on PR-agent implementation

The practical test is a PR agent that receives a bug report, opens an isolated checkout, reproduces the failure, and prepares a patch.

The implementation is not “give the model a repository and hope.” Split the work into two loops: an execution loop inside the sandbox, and a decision loop before consequential tool calls.

1. Give the agent a safe worktree

Start one sandbox per task, PR, or developer session. Clone the repository into that sandbox, inject only the credentials required for the task, and set an expiry policy for cleanup.

The agent should be free to inspect files, search code, run unit tests, build the affected service, and create a local diff. Those actions generate evidence and are usually reversible.

A useful default is: reads and local verification flow freely; writes to source, dependencies, CI configuration, migrations, and Git history pass through a decision hook.

This gives the agent room to investigate. It does not let an investigation silently become an architectural change.

2. Put a hook in front of mutating tools

The enforcement point is a pre-tool-call hook. The agent proposes apply_patch, write_file, git_commit, or open_pull_request; the hook receives the proposed action before it reaches the sandbox tool.

The hook should evaluate a compact input: the tool name, target paths, proposed diff or arguments, task intent, repository metadata, and the checks already run.

pre_tool_call(action, target, diff, task)
  → resolve relevant architecture rules
  → load coding conventions and ownership
  → check required evidence
  → ALLOW | BLOCK | ESCALATE

For a bug fix in services/billing.ts, the hook might retrieve: “all payment writes use PaymentRepository,” “public contract changes require the payments team,” and “a regression test is required before a patch is accepted.”

The hook is deliberately narrow. It does not need the entire engineering handbook in the prompt. It needs the rules relevant to the action the agent is about to take.

3. Encode implementation patterns, not vague advice

Avoid rules such as “keep the architecture clean.” They are too broad to enforce. Encode the concrete patterns that distinguish an acceptable patch from a locally plausible one.

For example: API handlers may call services, but not repositories directly. A new cross-package import must not create a dependency cycle. Shared types may only live in the contract package. New database migrations need a rollback and an owner. A public API needs a compatibility note.

The decision layer can also encode coding habits: use the existing error wrapper, add tests next to the modified module, preserve naming conventions, and use approved feature-flag patterns.

The point is not to freeze the codebase. It is to make deliberate exceptions visible. If a rule should be broken, the agent creates a concise escalation with the proposed exception and the evidence behind it.

4. Return a decision the agent can use

An allow decision should be specific: which action is authorised, which rules were satisfied, and what verification is still required. A block should name the violated rule and the smallest viable alternative.

An escalation should be equally actionable: the affected interface, owner, rule conflict, proposed options, and evidence from the sandbox. That turns the human review into a decision, not a fresh investigation.

Example: the PR agent proposes a direct import from billing into subscriptions. The hook blocks it because it would violate the package boundary, then points the agent toward the existing contract package. The agent can continue working instead of merely receiving a generic rejection.

Allowed patch after passing repository, regression test, dependency cycle, and owner policy checks

5. Measure whether the harness is improving the work

Do not measure this layer by how often it blocks the agent. Measure whether it reduces the work that humans must redo.

Track the percentage of patches that pass the relevant tests, the number of policy-driven blocks resolved without human help, the escalation rate by rule category, review comments about architectural drift, and reverted or follow-up PRs.

Then inspect the decision traces. A high rate of one rule violation may mean the agent needs better context, the rule is too ambiguous, or the repository lacks a reusable pattern.

The desired result is not an agent that never gets blocked. It is an agent that explores safely, produces patches consistent with the codebase, and asks for help precisely when a human decision is genuinely required.

In that design, the sandbox protects the environment. The decision layer keeps the agent on the path to a correct, maintainable outcome.

Trade-offs, honestly

A decision hook adds work to the agent loop. It has to resolve context, evaluate rules, and return a verdict before a mutating tool can run. For a risky write, that overhead is usually worth it. For routine reads, it is not.

Do not gate everything. Let the agent read files, search the repository, and run local tests quickly. Focus the decision layer on state-changing or high-impact actions: patches, dependency changes, migrations, commits, pull requests, and deployments.

Rules need maintenance. An out-of-date rule can block a valid pattern; an overly broad rule can turn a useful agent into a noisy approval machine. Treat rule quality as a product: version it, review it, observe its outcomes, and retire rules that no longer reflect the codebase.

There is also a trade-off between determinism and flexibility. A deterministic decision layer is intentionally strict when policy is clear. When the change involves a real architectural trade-off, escalation is the right result, not a forced, artificial answer.

Finally, decision traces create a new operational asset. They improve explainability and review, but they need appropriate retention, access control, and observability practices.

Start small. Gate one or two failure-prone actions, measure the blocks and escalations, then add rules where the agent repeatedly needs context or human correction.

We designed a template of enforceable rules for coding agents that can be automatically fine-tuned to your codebase.

Click here to get access.

Continue Reading