# Why AI Agents Need an Execution Boundary

> Source: <https://dev.to/ranknod/why-ai-agents-need-an-execution-boundary-4797>
> Published: 2026-09-18 18:38:45+00:00

Imagine an AI agent is reviewing a page before publication.

It decides the page is ready, calls `publish_page`, and the request succeeds. But the response times out.

The agent cannot tell whether publication happened, so it tries again.

Now imagine something else changed between those attempts: the page was edited, the user's permissions changed, or an approval was revoked.

The problem is no longer whether the model made a reasonable decision. The problem is that model intent has been allowed to become a real-world side effect without enough deterministic control around it.

That is why AI agents that can change external systems need an **execution boundary**.

The model should produce intent. Application code should control authority and side effects.

A useful architecture looks like this:

AI reasoning

↓

Structured action proposal

↓

Execution boundary

↓

External system

The execution boundary is not just a human-approval step. It is the layer responsible for validation, authorization, policy enforcement, workflow state, approvals, idempotency, retries, execution, auditing, and verification.

A simple agent prototype often looks like this:

User request

↓

LLM

↓

Tool call

↓

External system

The model decides that `publish_page` is appropriate, and the application immediately performs the action.

That is convenient during prototyping, but several different responsibilities have now been collapsed into one decision.

Before a page is actually published, the system may still need to ask:

`publish_page` a supported operation?
Those are not questions the model should resolve by itself.

They belong to deterministic application logic.

Instead of allowing the agent to invoke privileged side effects directly, let it propose an action.

For example:

```
{
  "type": "publish_page",
  "resourceId": "page_284",
  "reason": "draft_ready_for_publication",
  "operationId": "op_8f219"
}
```

This object represents what the agent wants to happen.

It does not prove that the action is allowed.

A safer flow is:

Agent proposal

↓

Schema validation

↓

Authorization

↓

Policy evaluation

↓

Approval if required

↓

Pre-execution validation

↓

Execution

↓

Verification

↓

Audit record

That middle layer is the execution boundary.

The model remains useful for reasoning. The application remains responsible for deciding whether the proposed action may affect the outside world.

Free-form output is difficult to validate reliably.

A bounded action vocabulary gives the application something predictable to inspect:

```
type AgentAction =
  | {
      type: "publish_page";
      resourceId: string;
      operationId: string;
    }
  | {
      type: "create_ticket";
      projectId: string;
      title: string;
      operationId: string;
    };
```

This example is illustrative rather than production-tested, but the design principle matters.

The agent can select from known actions. It cannot invent a privileged operation simply by describing one convincingly.

Application code can then own the control path:

```
async function processAgentAction(
  action: AgentAction,
  actor: Actor
) {
  validateSchema(action);
  await authorize(actor, action);
  await enforcePolicy(action);

  if (requiresApproval(action)) {
    return queueForApproval(action, actor);
  }

  return executeIdempotently(action, actor);
}
```

The important separation is:

**The model produces intent. The application grants authority.**

That makes the boundary easier to test, audit, and reason about.

Suppose the agent proposes:

```
{
  "type": "publish_page",
  "resourceId": "page_284",
  "operationId": "op_8f219"
}
```

The application still needs to decide whether publication is allowed.

That may depend on:

`page_284`;
An agent may understand how publishing works without having authority to publish.

That distinction is useful across agent roles.

A research agent might be allowed to search and summarize. An editing agent might be allowed to create a draft. A publishing agent might be allowed to request publication.

`request publication` does not have to mean `publish immediately`.

Capability and permission are separate concerns.

If an action needs human approval, approval should be represented in application state rather than only as an instruction in a prompt.

For a publishing workflow, the states might look like this:

PROPOSED

↓

VALIDATED

↓

AWAITING_APPROVAL

↓

APPROVED

↓

EXECUTING

↓

VERIFYING

↓

COMPLETED

Failure or exception states might include:

REJECTED

VALIDATION_FAILED

EXECUTION_FAILED

RETRY_PENDING

CANCELLED

This gives the application explicit answers to operational questions:

It also prevents "approval required" from becoming a vague behavioral suggestion to the model.

Approval itself should not automatically make an action safe forever.

Imagine `page_284` is approved for publication at 10:00.

Before the executor runs, one of these things changes:

The executor should not assume that an earlier approval proves the current action is still valid.

For important side effects, recheck authorization, relevant state, and approval validity immediately before execution.

An approval should authorize a specific action under specific conditions, not create unlimited future authority.

Now return to the original publishing example.

The executor sends a request to publish `page_284`.

The request succeeds.

The response times out.

From the application's point of view, the result is ambiguous.

Retrying blindly may cause the same side effect twice.

That is where idempotency becomes part of the execution boundary.

The proposal may contain an operation identifier:

```
{
  "type": "publish_page",
  "resourceId": "page_284",
  "operationId": "op_8f219"
}
```

Before execution, the application checks whether `op_8f219` has already completed or is already in progress.

There is one important detail here: an identifier should not automatically become trustworthy just because the model supplied it.

Ideally, trusted orchestration or application code should create the `operationId`, or at minimum validate it before use.

The model should not control the transactional identity of privileged operations without checks.

Once the operation is tracked by trusted code, the execution layer can safely handle:

The model does not need to remember transactional state. The system does.

Even successful execution is not necessarily the end of the workflow.

Suppose the publishing API returns `200 OK`.

Does that prove the new page is live?

Not always.

The request may have been accepted while a downstream process later fails. A public page may still display an older cached version. A deployment may start successfully but fail during rollout.

For meaningful side effects, verification should be explicit.

A workflow record might contain:

That gives `COMPLETED` a stronger meaning.

It means the system observed the intended result, not merely that it sent a request.

Separating reasoning from execution also makes the system much easier to test.

The executor should be testable independently from the model.

You can submit:

Then assert the expected result and state transition.

Unauthorized proposal

→ rejected before execution

Approved but stale proposal

→ returned for revalidation

Duplicate operation

→ not executed twice

Execution succeeds, verification fails

→ not marked COMPLETED

The reasoning layer can remain probabilistic.

The side-effect controls do not have to be.

Before allowing an AI agent to change a real system, check:

The core idea is simple:

**Let the model decide what it wants to do. Let deterministic application logic decide whether that action is valid, authorized, approved, safe to execute, and actually completed.**

That execution boundary is what turns tool use into a controlled system rather than a direct path from model output to real-world side effects.

Where would you place that boundary in your current agent architecture?

AI disclosure: This article was created with AI assistance. The human author is responsible for validating the technical content before publication.
