Governed AI Agents: Architecture for Long-Running, Durable and Auditable Autonomy
Last Updated: October 2026
A demo agent runs for ninety seconds, calls three tools and prints a tidy answer. A production agent runs for ninety minutes, sometimes ninety hours, across dozens of tool calls, a deploy that restarts its host, two policy checks and one human approval. Most agentic projects stall in the gap between those two worlds, and they stall for the same reason: the demo had no durable state, no authority model and no brake.
Governed AI agents are agents whose every consequential action passes through infrastructure that can persist it, authorize it, bound it, and later explain it. This is not a prompting problem. It is the old distributed-systems problem of long-lived, side-effecting workflows, with one new twist: the component choosing the next step is probabilistic and can be steered by text it reads along the way.
This article gives you a reference architecture you can map onto your own stack, a state machine for the agent loop, an approval and policy flow, and a runaway-control design with concrete budgets. It also says where each piece breaks.
What this covers: why long runs change the engineering problem, the plane-by-plane reference architecture, durable execution and replay safety, policy enforcement and agent identity, human-in-the-loop approvals, audit logging, budgets and kill switches, observability, standards mapping (OWASP, NIST, EU AI Act), failure modes, and a rollout checklist.
Context and Background
Short agents hide their weaknesses. Stretch the run time and four pressures arrive together: state, failure, cost and trust. Each one has an established answer in distributed systems, and the useful move is to borrow those answers rather than invent agent-specific ones.
State. A chat assistant can forget between turns. An agent reconciling invoices across a three-day window cannot. The agent’s working memory, its plan, the tool results already obtained and the approvals already granted are all state that must survive process death. Frameworks have converged on two ways to hold it: checkpointing graph state after every node (the LangGraph model) and recording an event history that is replayed on recovery (the Temporal model). Our deeper comparison of those engines lives in durable execution architecture with Temporal, Restate and DBOS.
Failure. If a naive agent process dies at step 47 of 100, it restarts at step 1 and repeats every side effect: the email goes out twice, the refund is issued twice. Durable execution fixes the control flow, but it cannot fix a tool that is not idempotent. That distinction, between resuming correctly and replaying safely, is the most common source of production incidents in this space.
Cost. Every loop iteration is a model call, and loops are hard to bound. A task you budgeted at ten calls can become eighty when the agent hits an unexpected state and starts self-correcting. Anthropic’s engineering write-up on its multi-agent research system reported that agents use substantially more tokens than chat interactions, and multi-agent setups more still; treat the exact multiples as workload-specific rather than universal. The architectural conclusion does not depend on the multiple: spend must be a first-class, enforced quantity.
Trust. Autonomy without authority control is the failure regulators and security teams worry about most. The OWASP GenAI Security Project published its Top 10 for Agentic Applications in December 2025, naming risks such as agent goal hijack, tool misuse, identity and privilege abuse, memory and context poisoning, cascading failures and rogue agents. The NIST AI Risk Management Framework (AI RMF 1.0, January 2023) supplies the Govern, Map, Measure and Manage functions that most enterprise programs use to organize this work. Regulation adds pressure: Article 14 of the EU AI Act requires human oversight measures for high-risk systems, although the application dates for those obligations have been subject to proposed adjustment, so confirm the current timeline with counsel rather than relying on any single date quoted in the press.
An industry pattern has emerged from these pressures, and it is the subject of this article. Separate the agent into planes. Let one plane own durability, one own reasoning, one own authorization, and one own observation. Then make each plane independently testable and independently failable. We have covered adjacent layers elsewhere: tool-level isolation in AI agent sandboxing with Firecracker, gVisor and Kata, and the forensic side in AI agent audit logging and identity. This post is the connective tissue between them.
The Reference Architecture for Governed AI Agents
The architecture has six planes: orchestration, reasoning, governance, execution, identity and observation. The orchestrator owns durable state. The planner proposes. The governance gate decides. The executor acts through scoped tools. Identity is issued per agent run, and everything emits to an append-only audit log and a trace pipeline.

Figure 1: Reference architecture for governed AI agents. The governance gate sits between deciding and doing, and every branch writes to the audit log.
Figure 1 shows the shape. The operator submits a goal to a durable orchestrator, which records it as the first event in the run’s history. The planner reads current state and returns the next proposed action. That proposal does not go to the tools; it goes to the governance gate, which consults policy and risk tier, and either allows it, denies it, or routes it to a human approver. Only allowed actions reach the executor, which calls tools using credentials scoped to that action. Results flow back to the orchestrator as new events. A budget controller watches the loop from the side and can terminate it.
The insight worth stating plainly is that the gate is placed between planning and execution, not inside the model. A prompt that says “never delete production data” is a request. A gate that refuses the call is a control. Everything in this architecture follows from preferring controls to requests.
Why Separate the Planner from the Executor
Splitting the planner and the executor gives you three things at once. It gives you a natural interception point, because every action is a discrete, inspectable object before it runs. It gives you a natural unit of checkpointing, because one step is one durable event. And it gives you deterministic replay, provided the planner is treated as a pure function of recorded state.
That last condition is where teams slip. If the planner holds hidden mutable state, such as an in-process cache of what it “already tried”, recovery reconstructs a different planner than the one that crashed, and the replay diverges. Keep planner inputs explicit: the goal, the event history, the current budget, and the policy context. Anything else is a nondeterminism bug waiting for a restart.
There is a subtler point about the model itself. A model call is not deterministic even at temperature zero across provider updates, so durable systems do not re-invoke the model during replay. They record the model’s output as an event and feed the recorded result back on recovery. In Temporal terms, model calls are Activities, and their results are part of the history. In LangGraph terms, they are node outputs captured in a checkpoint. In both cases the discipline is the same: never re-ask a question you already have a recorded answer to.
The Six Planes in One Table
| Plane | Owns | Typical implementation | Failure if missing |
|---|---|---|---|
| Orchestration | Durable state, retries, timers, waits | Temporal, Restate, DBOS, LangGraph with a persistent checkpointer | Restart at step 1, duplicated side effects |
| Reasoning | Plan and next-action proposal | LLM planner, pure function of state | Hidden state, divergent replay |
| Governance | Policy decisions, approval routing | Policy engine plus approval service | Prompt-only safety, unreviewed high-risk actions |
| Execution | Tool calls with scoped credentials | Sandboxed tool runners, MCP servers | Over-privileged blast radius |
| Identity | Who the agent is and acts for | Workload identity, delegated OAuth tokens | Shared service accounts, no attribution |
| Observation | Traces, cost, audit trail | OpenTelemetry, append-only log | Unexplainable incidents, surprise bills |
Control Plane versus Data Plane
It helps to borrow a networking frame. The planner and executor are the data plane: they do the work and handle untrusted content such as web pages, emails and tool outputs. The governance gate, identity issuer, budget controller and audit log are the control plane: they must not be reachable or modifiable by anything the data plane reads. A prompt injection that arrives through a retrieved document can persuade the planner of nearly anything, but it should not be able to edit a policy, mint a credential or truncate the audit log. If your design lets the model’s output change policy, you have collapsed the planes, and every guarantee downstream becomes advisory.
This is also why the gate belongs outside the agent process. If the same runtime hosts both the planner and the code that enforces policy, a compromised or confused planner and the enforcement share a fate. A separate service, or at minimum a separate process boundary with its own credentials, makes enforcement independent of the thing being enforced.
Durable Execution: Resuming Correctly and Replaying Safely
Durable execution means a workflow survives crashes, deploys and multi-day waits by persisting progress and resuming from it. Two mechanisms dominate: event-history replay, where a log of completed steps is replayed to rebuild in-memory state, and graph checkpointing, where state snapshots are saved after each node and loaded on resume.

Figure 2: The agent loop as a state machine. Waiting is a durable state, and Aborted is reachable from every active state.
Figure 2 gives the lifecycle. The agent moves from Planning to Executing, persists a Checkpointed state after each step, and can drop into Waiting while it holds for a human approval or an external event. On error it transitions to Failed, then Replaying from history, then back to Executing at the last good step. Two escape hatches matter: a budget or loop limit forces Aborted, and so does an approval timeout. Without those terminal edges, “resume forever” becomes “spend forever.”
Event history versus graph checkpoints
The two routes differ in what they guarantee, and the difference matters for governance.
In the event-history model, represented by Temporal, a workflow function is deterministic code, and each non-deterministic operation, such as calling a model or a tool, is an Activity whose result is recorded. On recovery, the engine re-executes the workflow code against the recorded history, short-circuiting completed Activities with their recorded results. You gain exactly-once-style semantics for workflow progress and strong support for timers, signals and long waits. You accept a constraint: workflow code must be deterministic, so you cannot read the clock, the network or a random number directly inside it.
In the checkpoint model, represented by LangGraph, an agent is a graph of nodes over a shared state object. A checkpointer saves state after each step into a store such as SQLite or Postgres; LangGraph documents in-memory, SQLite and Postgres checkpointers, and an interrupt mechanism that pauses a graph for human input and resumes with a Command. You gain a low-friction developer experience and natural fit for graph-shaped reasoning, plus time-travel inspection of earlier checkpoints. You accept weaker guarantees about side effects: a node that crashed after calling a tool but before its checkpoint was written will run again on resume, so the tool call must be idempotent.
Neither is universally better. If your agent coordinates many external systems with long timers and needs strong delivery semantics, an event-history engine is the safer spine. If it is mostly a reasoning loop with occasional pauses, graph checkpointing is often sufficient, and the two compose: teams run a LangGraph agent as an Activity inside a Temporal workflow to get both reasoning ergonomics and durable orchestration. Verify the specific integration support for your versions before committing, because both ecosystems are moving quickly.
Idempotency is the real durability guarantee
Durable execution makes your control flow crash-safe. It does not make your side effects crash-safe. Consider a refund tool. The executor calls the payments API, the API succeeds, and the host dies before the result is recorded. On replay the engine sees no recorded result and calls the tool again. Without an idempotency key, the customer is refunded twice.
The fix is mechanical and non-negotiable. Derive a deterministic idempotency key from the run identifier and the step identifier, pass it to every side-effecting call, and require downstream systems to honor it. Where a downstream system offers no idempotency support, wrap it with a small ledger: write an “intent” row keyed by the step, perform the call, then write the “result” row, and have the tool consult the ledger before acting. This is the outbox pattern applied to agents.
import hashlib
def idempotency_key(run_id: str, step_id: str, action: str) -> str:
"""Stable across replays: same run, step and action give the same key."""
raw = f"{run_id}:{step_id}:{action}"
return hashlib.sha256(raw.encode()).hexdigest()[:32]
def issue_refund(client, run_id, step_id, order_id, cents):
key = idempotency_key(run_id, step_id, f"refund:{order_id}:{cents}")
# Downstream API must treat repeated keys as the same operation.
return client.refunds.create(
order_id=order_id,
amount_cents=cents,
idempotency_key=key,
)
Long waits and versioning
Two operational realities catch teams late. First, long waits: an approval may sit for two days. The workflow must hold no thread or connection while waiting; it parks as durable state and is woken by a signal or a timer. Second, code versioning: if you deploy a new planner while a three-day run is parked, replay of the old history against new code can diverge. Event-history engines provide explicit versioning or patching mechanisms for exactly this; checkpoint-based systems need you to version the state schema and migrate or pin old runs. Decide your policy before the first long-lived run exists: either drain old runs, pin them to the old code, or write migrations.
Policy, Identity and Human-in-the-Loop Approvals
Governance is three questions answered in order for every proposed action: who is acting, is this action permitted, and does it need a human. The first is identity, the second is policy, the third is approval routing. Each should be answered by a component the model cannot influence, and each answer should be written to the audit log before the action runs.

Figure 3: Sequence of one governed call. The gate records the request, the decision, the approval and the outcome as separate audit events.
Giving agents an identity
The weakest pattern in the field is the shared service account: one API key, used by every agent, with broad scope. When something goes wrong you cannot say which run, which agent version or which delegating user caused it. The stronger pattern gives each agent run its own workload identity, and records on whose behalf it acts.
Three layers compose well. At the workload layer, attested identity such as SPIFFE and SPIRE issues short-lived X.509 or JWT SVIDs to the agent’s runtime, so services can authenticate the agent without static secrets; see our guide to SPIFFE and SPIRE workload identity. At the delegation layer, OAuth-style token exchange lets the agent present a token that states both the agent and the human it acts for, with a narrow scope and a short expiry. At the tool layer, the gate mints a per-call credential limited to the one resource and operation approved.
The Model Context Protocol’s authorization model, which builds on OAuth, is relevant if your tools are MCP servers, and our MCP architecture deep-dive covers how tool servers and clients negotiate it. The governance principle is protocol-independent: the credential an agent holds should be the smallest one that lets the approved action succeed, and it should expire quickly enough that a leaked token is a short incident.
Policy as code at the gate
Policy should be expressed declaratively and evaluated outside the model. General-purpose engines such as Open Policy Agent with Rego, or Cedar, let you write rules like “refunds above a threshold require approval” or “writes to the production database are denied outside a change window”, test them in CI, and version them alongside code. Our comparison of Kyverno and OPA Gatekeeper covers the operational trade-offs of such engines in a Kubernetes setting; the same ideas transfer to an agent gate.
A useful policy input is richer than the tool name. Pass the tool, the arguments, the agent identity, the delegating user, the run’s accumulated spend, the count of recent actions, and a data classification label for the resources touched. Then the policy can express contextual rules, such as denying an export when the run has already read data labelled restricted.
package agent.gate
default decision := {"effect": "deny", "reason": "no matching rule"}
decision := {"effect": "allow"} if {
input.tool == "search_docs"
}
decision := {"effect": "require_approval", "tier": "high"} if {
input.tool == "issue_refund"
input.args.amount_cents > 50000
}
decision := {"effect": "deny", "reason": "restricted data in run context"} if {
input.tool == "send_email"
"restricted" in input.run.data_labels
not endswith(input.args.recipient, "@example-corp.com")
}
Note the default. A default-deny gate fails closed: a tool nobody wrote a rule for is blocked, which is the right behavior for autonomous software. Default-allow gates are how an agent ends up calling a destructive endpoint nobody thought to list.
Risk-tiered approval routing
Blanket human review does not scale and it trains reviewers to click through. The dominant pattern is risk tiering: classify actions, automate the low tier, sample-audit the middle, and require synchronous human approval for the high tier. The tier should derive from properties of the action, not from the model’s own confidence, since a steered model can be confidently wrong.
| Tier | Example actions | Control | Latency cost |
|---|---|---|---|
| Low | Read-only search, internal drafts | Auto-allow, full logging | None |
| Medium | Writes to sandboxed or reversible targets | Auto-allow with sampled human audit and rate limits | Minimal |
| High | Payments, production writes, external communication, permission changes | Synchronous approval with scoped, expiring grant | Minutes to days |
| Prohibited | Disabling logging, editing policy, creating credentials | Hard deny, alert | Not applicable |
Make the approval itself a rich object. A reviewer deciding on a bare tool name is rubber-stamping. Show the intent in plain language, the exact arguments, the data the run has touched, the permission chain, the expected blast radius and the rollback plan. Then bind the grant: the approval authorizes this specific call with these specific arguments, and expires. An approval that authorizes “send_email” in general is a standing permission in disguise.
Approvals map onto the Waiting state from Figure 2. The agent parks durably; a signal carrying the decision resumes it; a timeout aborts it or escalates. Treat the approver’s decision as an event in the history, so replay never re-asks the human. Two failure modes recur. Approval fatigue sets in when too much routes to humans, so reviewers stop reading. Approval laundering happens when the agent decomposes a high-risk action into several low-risk ones that each pass the gate; defend against it with policies that look at accumulated effects across the run, not only the single call.
# LangGraph-style human gate (verify API against your installed version)
from langgraph.types import interrupt, Command
def approval_node(state):
proposal = state["proposed_action"]
decision = interrupt({
"question": "Approve this action?",
"action": proposal["tool"],
"args": proposal["args"],
"blast_radius": proposal["blast_radius"],
"rollback": proposal["rollback"],
})
if decision.get("approved"):
return {"approved_grant": {
"tool": proposal["tool"],
"args_hash": proposal["args_hash"],
"expires_at": decision["expires_at"],
}}
return {"aborted": True, "reason": decision.get("reason", "rejected")}
# Resumed later, possibly by another process, with:
# graph.invoke(Command(resume={"approved": True, "expires_at": "..."}), config)
The confused deputy and prompt injection
Agents read untrusted text, and text can contain instructions. If the same agent that reads an email can also send email with the user’s full authority, an attacker who writes the email has borrowed that authority. This is the confused deputy problem, and it is why OWASP lists goal hijack and tool misuse at the head of its agentic list. No prompt reliably prevents it. The structural mitigations are least privilege, separating the context that reads untrusted content from the context that holds powerful tools, requiring approval for actions that cross a trust boundary, and treating all tool output as data rather than instruction. Our write-up on LLM red teaming and jailbreak defense shows how to test these assumptions adversarially.
Audit Logging, Observability and Evidence
An audit log answers a different question from a trace. A trace helps an engineer debug performance and behavior; an audit log lets a third party reconstruct who authorized what and why. They overlap in data but differ in guarantees: audit records are append-only, tamper-evident, retained to policy, and written before the action they describe.
What belongs in an audit record
For each governed action, record the run and step identifiers, the agent identity and version, the delegating principal, the exact tool and arguments (with sensitive fields hashed or tokenized), the policy version and the decision with its reason, the approver identity and the grant scope if one was involved, the credential identifier used, the outcome, and timestamps. Record denials as carefully as approvals; a pattern of denied attempts is an intrusion or misbehavior signal.
Tamper evidence can be achieved by hash-chaining records so each entry includes the hash of the previous one, then anchoring periodic checkpoints in a separate system or write-once storage. If your finance or compliance teams already use an event-sourced ledger, reuse its machinery; see event sourcing and bitemporal audit trails for the pattern. Be careful with personal data: logs that capture full prompts and tool arguments can become a privacy liability, so pair logging with redaction, as in our PII detection and redaction pipeline.
Traces and cost as telemetry
Trace every plan, model call, guardrail decision, tool call and approval as a span, with run and step identifiers as attributes. OpenTelemetry has been developing generative AI semantic conventions for model and agent spans; they were still evolving at the time of writing, so pin the convention version you emit. Our article on OpenTelemetry GenAI semantic conventions goes into attribute naming. Attach token counts and estimated cost to each span so spend can be aggregated per run, per agent, per tenant and per tool.
Observability is also how you detect drift. Useful signals include the distribution of steps per run, the ratio of denied to allowed actions, approval latency, retry rates, dead-letter volume and the share of runs ending in each terminal state. A rising step count with flat task difficulty usually means the agent is thrashing. Offline, replay recorded trajectories through an evaluation harness before shipping planner changes; our guide to agent evaluation harnesses and trajectory evals covers this.
Separating the logs from the agent
The audit store must be writable by the gate and readable by auditors, and not modifiable by the agent runtime or the planner’s tools. If the agent can delete its own log, the log proves nothing. This sounds obvious, and it is violated routinely when logs go into a database the agent’s tool credentials can also reach. Put “disable logging” and “edit policy” in the Prohibited tier and enforce it with separate credentials, not with a prompt.
Budgets, Kill Switches and Failure Recovery
Autonomy needs brakes that do not depend on the agent’s cooperation. Every long-running agent should have bounded steps, bounded spend, bounded time, loop detection and an operator-triggered kill switch, all enforced by the orchestrator or gate rather than by the model.

Figure 4: Runaway controls evaluated before every step. Failures retry within a budget and then fall through to a dead-letter queue.
The control set
Figure 4 shows the checks. Before each step the loop evaluates a step cap, a spend budget and a repeated-action check. Crossing the first two terminates the run with an alert. A repeated action, such as the same failing tool call with the same arguments several times in a window, quarantines the run and escalates rather than letting it thrash.
Choose numbers from data, not folklore. A sensible start is to run the agent on a representative evaluation set, record the distribution of steps and cost per successful run, and set the hard cap at a comfortable margin above a high percentile of successful runs, such as three times the 95th percentile, then tighten it as you gain confidence. The figures here are a method, not a recommendation of specific values; your workload determines them. Set a soft threshold lower than the hard cap to warn operators, and a per-tenant or per-day budget above the per-run budget so one bad run cannot exhaust a shared quota.
from dataclasses import dataclass, field
from collections import deque
@dataclass
class RunGuard:
max_steps: int
max_cost_usd: float
dedupe_window: int = 6
steps: int = 0
cost_usd: float = 0.0
recent: deque = field(default_factory=lambda: deque(maxlen=6))
def check(self, action_sig: str, step_cost: float) -> str:
self.steps += 1
self.cost_usd += step_cost
if self.steps > self.max_steps:
return "abort:step_cap"
if self.cost_usd > self.max_cost_usd:
return "abort:budget"
if list(self.recent).count(action_sig) >= 3:
return "quarantine:repeat"
self.recent.append(action_sig)
return "ok"
Retries, dead letters and compensation
Retry tool failures with exponential backoff and jitter inside a bounded budget. Distinguish transient errors, which deserve retries, from semantic errors, such as a rejected argument, which do not; retrying a semantic error just burns tokens. When the budget is exhausted, send the step to a dead-letter queue with its full context, alert a human, and leave the run in a resumable, parked state rather than failed outright.
For multi-step side effects, design compensation. If step 5 of a booking workflow fails after steps 1 to 4 committed, the saga pattern says you run compensating actions in reverse: release the hold, cancel the charge. Agents make sagas harder, because the plan is not known in advance, so record each committed side effect with its compensator at the time it commits. Then a rollback is a replay of compensators from the log, not an improvisation by a model that is already confused.
The kill switch
A kill switch should be reachable by operators in seconds and should work at multiple scopes: a single run, all runs of one agent, all runs using one tool, and everything. Implement it as a flag read by the gate on every decision, so a flipped switch denies all further actions even if the planner keeps proposing them. Revoking the agent’s workload identity is the backstop: even a runaway process loses access when its short-lived credentials expire and are not renewed. Rehearse the kill switch in game days; an untested one often fails when needed.
Mapping to Standards and Frameworks
Governance programs are easier to defend when mapped to published frameworks. The mapping below is a design aid, not a compliance claim; confirm control wording against the current versions of each document.
| Framework | Relevant guidance | Where it lands in the architecture |
|---|---|---|
| OWASP Top 10 for Agentic Applications 2026 | Ten risks including goal hijack, tool misuse, identity and privilege abuse, supply chain, unexpected code execution, memory and context poisoning, insecure inter-agent communication, cascading failures, human-agent trust exploitation, rogue agents | Gate, scoped credentials, sandboxed execution, budget controls, approval design |
| NIST AI RMF 1.0 and the Generative AI Profile | Govern, Map, Measure, Manage functions; GenAI profile adds risks specific to generative systems | Policy ownership, risk tiers, evaluation harness, incident response |
| EU AI Act, Article 14 | Human oversight for high-risk systems, including the ability to intervene or interrupt | Approval gates, durable Waiting state, kill switch |
| ISO/IEC 42001 | AI management system requirements | Organizational controls around the technical architecture |
A few mappings deserve explanation. OWASP’s cascading failures risk is the multi-agent version of the runaway loop: one agent’s bad output becomes another’s input. Contain it with per-agent budgets, schema-validated handoffs and circuit breakers between agents. Its rogue agents risk is the reason for the kill switch and for monitoring behavioral drift. Its human-agent trust exploitation risk is the reason approvals must show raw arguments rather than the agent’s persuasive summary of them. For EU AI Act Article 14, the practical engineering takeaway is that oversight must be effective: a human who is shown too much, too fast, or only the agent’s own framing is not meaningfully overseeing.
Deployment Walk-through: A Refund Agent, End to End
A concrete trace makes the planes tangible. Suppose a support agent handles refund disputes that may take days because they wait on customer replies.
The run starts when a ticket arrives. The orchestrator creates a run record, issues a workload identity bound to the delegating support team, and writes the first audit event. The planner reads the ticket and proposes a lookup of the order. The gate evaluates it: a read-only tool, low tier, allowed. The executor calls the order API with a read-scoped, five-minute credential. The result is recorded as an event.
The planner next proposes asking the customer a clarifying question by email. The gate sees an external communication to an address from the ticket, classifies it as medium, and allows it with a rate limit and a template constraint. The run enters Waiting for the reply. It holds no thread. Two days later a webhook signals the workflow, which resumes from history, not from the beginning.
The planner now proposes a refund of a given amount. The amount exceeds the threshold, so the policy returns require_approval. The gate writes the request to the audit log, sends the approver a card showing the order, the arguments, the evidence from the ticket and the rollback path, and the run parks again. The approver approves a refund of exactly that amount, valid for one hour. The gate mints a credential scoped to that single refund operation, derives the idempotency key from run and step, and calls the payments API. If the host crashes right after the call, the replay finds the same key and the payments system returns the original result instead of paying twice.
Throughout, the budget controller tracked token spend against the per-run ceiling, and the trace shows each span with its cost. At the end, the audit log can answer the questions an auditor will ask: who or what acted, on whose behalf, under which policy version, who approved, and what changed.
Trade-offs, Gotchas, and What Goes Wrong
This architecture costs latency, engineering effort and operational surface. The failures worth planning for are mostly failures of discipline rather than of technology.
Durability theater. Adding a durable engine or a checkpointer does not make an agent durable if tool calls are not idempotent and the planner holds hidden state. Replay then reproduces side effects or diverges. Durability is a property of the whole system, not a library you import.
Policy sprawl and drift. Rules accumulate, interact and go stale. Without tests and ownership, nobody knows why a request is denied, and teams respond by adding broad allow rules to unblock themselves. Treat policy like code: review, test with fixtures of allowed and denied calls, and version it so audit records can name the exact version in force.
Approval fatigue and laundering. Over-routing teaches reviewers to approve by reflex; under-routing lets risky actions slip through; decomposition attacks evade per-call checks. Measure approval rates, time-to-decision and reversal rates, and revisit tiers with data.
Replay and versioning hazards. Changing planner code while long runs are parked can break replay. Decide up front whether you drain, pin or migrate, and test resumption of old histories in CI.
Logging as a liability. Rich audit data helps incident response and also stores sensitive content. Apply redaction, retention limits and access control to the audit store as seriously as to production data.
Latency tax. Every gate decision, credential mint and audit write adds milliseconds, and approvals add minutes or days. Keep the low tier cheap, evaluate policy locally with cached bundles where possible, and be honest with stakeholders that high-risk actions will be slower by design.
False confidence from guardrail models. Classifier-based guardrails help but are probabilistic and bypassable. Use them as one layer under deterministic controls, never as the only barrier.
Multi-agent amplification. When agents call agents, identity, budgets and approvals must propagate. An unbounded sub-agent can spend its parent’s budget or inherit privileges the parent never intended to delegate. Pass down attenuated, not equal, authority.
Practical Recommendations
Start by classifying your agent’s actions into tiers, because every other decision follows from it. Build the gate and audit log first, even if the first version is a thin wrapper with three rules, since retrofitting a control point into a running agent is far harder than starting with one. Choose the durability mechanism to match the workload: an event-history engine for long timers and multi-system coordination, checkpointing for reasoning-heavy loops, and a combination when you need both.
Treat identity as per-run and delegated, not shared. Treat budgets as hard limits enforced outside the model. Treat approvals as scoped, expiring grants with raw arguments shown. Treat the audit store as evidence, which means append-only, separated from the agent, and redacted. Test failure paths deliberately: kill the worker mid-step, expire an approval, flip the kill switch, and replay an old history against new code.
Rollout checklist
- Inventory every tool and assign a risk tier; mark irreversible and external actions explicitly.
- Run the gate in default-deny mode with policy in version control and tests for allowed and denied cases.
- Give each run its own short-lived identity and record the delegating user on every call.
- Require an idempotency key on every side-effecting tool, derived from run and step.
- Persist the plan, tool results and approvals as durable events; never re-invoke the model during replay.
- Show approvers the raw arguments, blast radius and rollback; bind grants to the call and expire them.
- Enforce step, spend, time and repeat limits in the orchestrator; route exhausted retries to a dead-letter queue.
- Implement a multi-scope kill switch and rehearse it.
- Write append-only, hash-chained audit records outside the agent’s reach, with redaction.
- Emit traces with cost attributes and review step-count and denial-rate dashboards weekly.
- Decide and document your policy for in-flight runs during planner deploys.
Frequently Asked Questions
What are governed AI agents?
Governed AI agents are autonomous agents that operate inside enforced controls: every proposed action passes a policy gate, high-risk actions require scoped human approval, identities and credentials are issued per run, spend and loop limits are enforced outside the model, and every decision is written to an audit log. Governance is implemented in infrastructure the model cannot modify, so it holds even when the model is confused or manipulated by untrusted input.
How is durable execution different from checkpointing for agents?
Durable execution records an event history of completed steps and replays it on recovery to rebuild state, which suits long timers, signals and strong delivery semantics. Checkpointing snapshots a state object after each node and reloads it on resume, which suits graph-shaped reasoning with pauses. Both need idempotent tools, because a step that crashed after its side effect but before its record was saved will run again. Many teams combine them.
Do all agent actions need human approval?
No. Blanket review causes approval fatigue and gives little extra safety. Use risk tiers: auto-allow read-only and reversible actions with logging, sample-audit medium-risk ones, and require synchronous approval for payments, production writes, external communication and permission changes. Derive the tier from properties of the action and its arguments, not from the model’s confidence. Make each approval a scoped, expiring grant tied to the exact call.
How do I stop a long-running agent from running away?
Enforce limits in the orchestrator or gate, not in the prompt. Cap steps, spend and wall-clock time per run, detect repeated identical actions and quarantine the run, retry transient errors with backoff inside a budget, and send exhausted retries to a dead-letter queue. Add a multi-scope kill switch and short-lived credentials so a runaway process loses access even if it ignores signals. Derive caps from evaluation data rather than guesses.
Which standards apply to agent governance?
Common references are the OWASP Top 10 for Agentic Applications 2026 for threats, the NIST AI Risk Management Framework and its Generative AI Profile for program structure, ISO/IEC 42001 for management systems, and the EU AI Act for human-oversight duties on high-risk systems. None prescribes an architecture. Use them to justify and organize controls, and verify current versions and application dates with your compliance team.
What should an agent audit log contain?
Record run and step identifiers, agent identity and version, the delegating user, the tool and arguments with sensitive fields redacted or hashed, the policy version and decision with reason, approver identity and grant scope, the credential used, the outcome and timestamps. Make it append-only and tamper-evident, for example with hash chaining, and keep it outside the agent’s write access. Log denials too, since they reveal misbehavior.
Further Reading
- Durable execution architecture with Temporal, Restate and DBOS for the orchestration layer in depth.
- AI agent audit logging and identity lessons for incident-driven logging requirements.
- AI agent sandboxing with Firecracker, gVisor and Kata for isolating the execution plane.
- AI agent evaluation harness and trajectory evals for testing planner changes before release.
- NIST AI Risk Management Framework and the OWASP GenAI Security Project for the primary framework documents.
- LangGraph documentation on persistence and human-in-the-loop and Temporal documentation for engine specifics; verify API details against your installed versions.
By Riju — about

Pingback: Meta Muse and Muse Code: Personal Agent Architecture and
Pingback: AI Agent Trajectory Evaluation: 2026 Patterns - IoT Digital Twin PLM