{"slug": "why-ai-agents-need-an-execution-boundary", "title": "Why AI Agents Need an Execution Boundary", "summary": "A developer argues that AI agents capable of changing external systems require an \"execution boundary\" — a deterministic application layer that validates, authorizes, and audits proposed actions rather than letting model intent directly trigger side effects. The proposed architecture has the model emit structured action proposals, such as a typed publish_page object with an operationId, while application code owns schema validation, authorization, policy enforcement, approvals, idempotent execution, and verification. The design aims to make agent behavior easier to test, audit, and reason about by separating intent from authority.", "body_md": "Imagine an AI agent is reviewing a page before publication.\n\nIt decides the page is ready, calls `publish_page`, and the request succeeds. But the response times out.\n\nThe agent cannot tell whether publication happened, so it tries again.\n\nNow imagine something else changed between those attempts: the page was edited, the user's permissions changed, or an approval was revoked.\n\nThe 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.\n\nThat is why AI agents that can change external systems need an **execution boundary**.\n\nThe model should produce intent. Application code should control authority and side effects.\n\nA useful architecture looks like this:\n\nAI reasoning\n\n↓\n\nStructured action proposal\n\n↓\n\nExecution boundary\n\n↓\n\nExternal system\n\nThe 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.\n\nA simple agent prototype often looks like this:\n\nUser request\n\n↓\n\nLLM\n\n↓\n\nTool call\n\n↓\n\nExternal system\n\nThe model decides that `publish_page` is appropriate, and the application immediately performs the action.\n\nThat is convenient during prototyping, but several different responsibilities have now been collapsed into one decision.\n\nBefore a page is actually published, the system may still need to ask:\n\n`publish_page` a supported operation?\nThose are not questions the model should resolve by itself.\n\nThey belong to deterministic application logic.\n\nInstead of allowing the agent to invoke privileged side effects directly, let it propose an action.\n\nFor example:\n\n```\n{\n  \"type\": \"publish_page\",\n  \"resourceId\": \"page_284\",\n  \"reason\": \"draft_ready_for_publication\",\n  \"operationId\": \"op_8f219\"\n}\n```\n\nThis object represents what the agent wants to happen.\n\nIt does not prove that the action is allowed.\n\nA safer flow is:\n\nAgent proposal\n\n↓\n\nSchema validation\n\n↓\n\nAuthorization\n\n↓\n\nPolicy evaluation\n\n↓\n\nApproval if required\n\n↓\n\nPre-execution validation\n\n↓\n\nExecution\n\n↓\n\nVerification\n\n↓\n\nAudit record\n\nThat middle layer is the execution boundary.\n\nThe model remains useful for reasoning. The application remains responsible for deciding whether the proposed action may affect the outside world.\n\nFree-form output is difficult to validate reliably.\n\nA bounded action vocabulary gives the application something predictable to inspect:\n\n```\ntype AgentAction =\n  | {\n      type: \"publish_page\";\n      resourceId: string;\n      operationId: string;\n    }\n  | {\n      type: \"create_ticket\";\n      projectId: string;\n      title: string;\n      operationId: string;\n    };\n```\n\nThis example is illustrative rather than production-tested, but the design principle matters.\n\nThe agent can select from known actions. It cannot invent a privileged operation simply by describing one convincingly.\n\nApplication code can then own the control path:\n\n```\nasync function processAgentAction(\n  action: AgentAction,\n  actor: Actor\n) {\n  validateSchema(action);\n  await authorize(actor, action);\n  await enforcePolicy(action);\n\n  if (requiresApproval(action)) {\n    return queueForApproval(action, actor);\n  }\n\n  return executeIdempotently(action, actor);\n}\n```\n\nThe important separation is:\n\n**The model produces intent. The application grants authority.**\n\nThat makes the boundary easier to test, audit, and reason about.\n\nSuppose the agent proposes:\n\n```\n{\n  \"type\": \"publish_page\",\n  \"resourceId\": \"page_284\",\n  \"operationId\": \"op_8f219\"\n}\n```\n\nThe application still needs to decide whether publication is allowed.\n\nThat may depend on:\n\n`page_284`;\nAn agent may understand how publishing works without having authority to publish.\n\nThat distinction is useful across agent roles.\n\nA 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.\n\n`request publication` does not have to mean `publish immediately`.\n\nCapability and permission are separate concerns.\n\nIf an action needs human approval, approval should be represented in application state rather than only as an instruction in a prompt.\n\nFor a publishing workflow, the states might look like this:\n\nPROPOSED\n\n↓\n\nVALIDATED\n\n↓\n\nAWAITING_APPROVAL\n\n↓\n\nAPPROVED\n\n↓\n\nEXECUTING\n\n↓\n\nVERIFYING\n\n↓\n\nCOMPLETED\n\nFailure or exception states might include:\n\nREJECTED\n\nVALIDATION_FAILED\n\nEXECUTION_FAILED\n\nRETRY_PENDING\n\nCANCELLED\n\nThis gives the application explicit answers to operational questions:\n\nIt also prevents \"approval required\" from becoming a vague behavioral suggestion to the model.\n\nApproval itself should not automatically make an action safe forever.\n\nImagine `page_284` is approved for publication at 10:00.\n\nBefore the executor runs, one of these things changes:\n\nThe executor should not assume that an earlier approval proves the current action is still valid.\n\nFor important side effects, recheck authorization, relevant state, and approval validity immediately before execution.\n\nAn approval should authorize a specific action under specific conditions, not create unlimited future authority.\n\nNow return to the original publishing example.\n\nThe executor sends a request to publish `page_284`.\n\nThe request succeeds.\n\nThe response times out.\n\nFrom the application's point of view, the result is ambiguous.\n\nRetrying blindly may cause the same side effect twice.\n\nThat is where idempotency becomes part of the execution boundary.\n\nThe proposal may contain an operation identifier:\n\n```\n{\n  \"type\": \"publish_page\",\n  \"resourceId\": \"page_284\",\n  \"operationId\": \"op_8f219\"\n}\n```\n\nBefore execution, the application checks whether `op_8f219` has already completed or is already in progress.\n\nThere is one important detail here: an identifier should not automatically become trustworthy just because the model supplied it.\n\nIdeally, trusted orchestration or application code should create the `operationId`, or at minimum validate it before use.\n\nThe model should not control the transactional identity of privileged operations without checks.\n\nOnce the operation is tracked by trusted code, the execution layer can safely handle:\n\nThe model does not need to remember transactional state. The system does.\n\nEven successful execution is not necessarily the end of the workflow.\n\nSuppose the publishing API returns `200 OK`.\n\nDoes that prove the new page is live?\n\nNot always.\n\nThe 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.\n\nFor meaningful side effects, verification should be explicit.\n\nA workflow record might contain:\n\nThat gives `COMPLETED` a stronger meaning.\n\nIt means the system observed the intended result, not merely that it sent a request.\n\nSeparating reasoning from execution also makes the system much easier to test.\n\nThe executor should be testable independently from the model.\n\nYou can submit:\n\nThen assert the expected result and state transition.\n\nUnauthorized proposal\n\n→ rejected before execution\n\nApproved but stale proposal\n\n→ returned for revalidation\n\nDuplicate operation\n\n→ not executed twice\n\nExecution succeeds, verification fails\n\n→ not marked COMPLETED\n\nThe reasoning layer can remain probabilistic.\n\nThe side-effect controls do not have to be.\n\nBefore allowing an AI agent to change a real system, check:\n\nThe core idea is simple:\n\n**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.**\n\nThat execution boundary is what turns tool use into a controlled system rather than a direct path from model output to real-world side effects.\n\nWhere would you place that boundary in your current agent architecture?\n\nAI disclosure: This article was created with AI assistance. The human author is responsible for validating the technical content before publication.", "url": "https://wpnews.pro/news/why-ai-agents-need-an-execution-boundary", "canonical_source": "https://dev.to/ranknod/why-ai-agents-need-an-execution-boundary-4797", "published_at": "2026-09-18 18:38:45+00:00", "updated_at": "2026-09-18 18:52:56.613015+00:00", "lang": "en", "topics": ["ai-agents", "ai-safety", "ai-tools", "developer-tools"], "entities": [], "alternates": {"html": "https://wpnews.pro/news/why-ai-agents-need-an-execution-boundary", "markdown": "https://wpnews.pro/news/why-ai-agents-need-an-execution-boundary.md", "text": "https://wpnews.pro/news/why-ai-agents-need-an-execution-boundary.txt", "jsonld": "https://wpnews.pro/news/why-ai-agents-need-an-execution-boundary.jsonld"}}