Agentic Development Part 5: Agent Verification and Guardrails
Part 2 discussed observation and self-verification as one of the core agent components — how an agent evaluates its own action results before moving to the next iteration. Part 3 discussed the definition of done as the criteria every task must meet. This article brings both together from a more systemic angle: how to formalize verification into real, independent automated mechanisms, not just an agent that “feels” its work is correct. The more autonomy given to an agent — as covered in Part 1 — the more important guardrails become for limiting the impact when something goes wrong. This article covers guardrail layers from the most deterministic to those involving humans, the independent reviewer agent pattern, strategies for limiting blast radius through sandboxing, and the criteria for determining when humans must step in.
Why Agent Self-Verification Isn’t Enough
The observation discussed in Part 2 — an agent reading and interpreting the results of its own actions — is an important component but has a structural limitation that can’t be solved just by making the model better. The problem isn’t capability but position: an agent evaluating its own work uses the same reasoning process that produced the work, and is prone to confirmation bias — the tendency to treat the approach already taken as correct, because evaluation and execution come from the same chain of reasoning.
This isn’t a problem unique to AI agents — humans have a similar limitation, which is why code review by someone else remains a standard practice even though the developer who wrote the code already tested their own work. The assumption errors that make someone write wrong code tend to also keep that same person from noticing the error when re-evaluating the result — the same perspective produces the same blind spots.
flowchart LR
A[Agent Writes Code] --> B[Same Agent Evaluates Its Results]
B --> C{Confirmation Bias}
C -- Wrong Assumption from the Start --> D[Evaluation Still Fails to Detect the Problem]
E[Agent Writes Code] --> F[Independent Verification: Separate Tests/Reviewer]
F --> G{Different Evaluation Source}
G -- Doesn't Share the Same Assumptions --> H[Problems More Likely Detected]The implication: the self-verification from Part 2 remains important as the first layer — an agent that doesn’t even check its own results is clearly worse than one that does. But self-verification must not be the only layer for work with meaningful consequences. An evaluation source independent of the process that produced the code is needed — whether automated tests written separately from the implementation, a different reviewer agent, or human review — one that doesn’t inherit the same assumptions that produced the work.
Self-verification and independent verification aren’t an either/or choice — they complement each other. Self-verification catches clearly visible errors quickly without waiting for the next layer; independent verification catches errors invisible from the same viewpoint that produced the work.
Guardrail Layers: From Deterministic to Probabilistic
Effective guardrails work as a layered stack, not a single mechanism. Each layer catches a different type of failure, and the layers should be ordered from the cheapest and most reliable first, to the most expensive, reserved for cases that truly need it.
| Layer | Nature | Catches |
|---|---|---|
| Automated tests & linters | Deterministic, fast, cheap | Functional regressions, code style violations, syntax errors |
| Static analysis & type-checking | Deterministic, catches a broader error class | Type inconsistencies, risky code patterns, unsafe dependencies |
| Contract tests against the spec | Deterministic, verifies contract conformance | Deviations from the agreed API/data schema (see Part 3 of the Spec-Driven Development series) |
| Independent reviewer agent | Probabilistic but independent from the execution process | Logic errors, deviations from intent not caught by explicit tests |
| Human review | Most expensive, slowest, but most contextual | Architectural decisions, business trade-offs, risks needing human judgment |
flowchart TD
A[Agent Change] --> B[Automated Tests & Linters]
B -- Pass --> C[Static Analysis & Type-Check]
B -- Fail --> Z[Return to Agent for Fixes]
C -- Pass --> D[Contract Test Against Spec]
C -- Fail --> Z
D -- Pass --> E[Independent Reviewer Agent]
D -- Fail --> Z
E -- No Significant Findings --> F{High Risk?}
E -- Findings --> Z
F -- Yes --> G[Human Review]
F -- No --> H[Pass, Continue]
G --> HThis layered pattern is effective because each layer has different costs and reliability levels. Deterministic layers (tests, linters, type-checks) are cheap to run and their results are certain — there’s no ambiguity about whether a test passed or failed. These layers should filter out as many problems as possible before reaching the more expensive layers. Independent reviewer agents and human review are reserved for what can’t be caught deterministically — subtle logic errors, trade-off decisions, or risks requiring broader context than automated verification can provide.
The best investment for improving guardrail reliability is usually not adding new layers, but strengthening the deterministic layers that already exist — better test coverage, stricter contract tests. A strong deterministic layer reduces the load on the more expensive, slower probabilistic layers.
Guardrails as Fences, Not Obstacles
There’s a common misconception that good guardrails mean restricting the agent as tightly as possible. In practice, well-designed guardrails function as fences that limit the impact of errors, not obstacles that kill genuinely useful autonomy. The difference lies in where the boundaries are placed — on the types of actions allowed in each work phase, not on how often the agent gets interrupted.
One practical pattern: tool permissions are limited by work phase, not granted uniformly throughout the session. Recalling the planner/executor separation from Part 2 — the planning phase should ideally only have read-only, exploratory tool access, while access to actually change things (writes, executing state-changing commands) is only granted after the plan is approved and execution begins.
Planning Phase:
Allowed tools: read files, search/grep, read documentation
NOT allowed tools: write files, run destructive commands,
call state-changing external APIs
Execution Phase (after the plan is approved):
Allowed tools: write files within the approved task scope,
run tests, commit to a working branch
NOT allowed tools: push directly to the main branch, access
production credentials, modify outside the task scope
This phase-based restriction gives full autonomy for exploration (which is low-risk because it changes nothing) while still holding risky actions (those that change state) behind approval gates. This is fundamentally different from the “ask approval at every step” approach that eliminates the autonomy benefit entirely — phase-based guardrails limit when risky actions may happen, not how much work the agent may do autonomously.
A production agent security review report found that the combination of private data access, exposure to untrusted content, and the ability to perform outward actions — called the high-risk combination — appeared in nearly all agents studied. Effective guardrails usually target breaking one of these three elements, rather than trying to manually control all three at every moment.
Automated Gates Before Moving to the Next Task
Part 4 of the Spec-Driven Development series and Part 3 of this series both discuss cross-task-group review checkpoints as an important practice. An automated gate is the formalized version of that checkpoint — explicit, automatic conditions that must be met before the agent is allowed to move to the next task, not merely “manual review if there’s time”.
sequenceDiagram
participant Agent
participant Gate as Automated Gate
participant NextTask as Next Task
Agent->>Gate: Task Group N Done
Gate->>Gate: Run full test suite
Gate->>Gate: Run linter & type-check
Gate->>Gate: Verify contract tests against spec
alt All Gates Pass
Gate->>NextTask: Allow Continue
else Something Fails
Gate->>Agent: Return with Failure Details
Agent->>Agent: Fix Before Trying Again
endA good agentic system treats these gate failures as part of the normal loop, not an exceptional event — the agent is expected to fix and retry, rerun tests, and resubmit results for evaluation, without human intervention on each retry. Humans only need to step in when repeated fixes still fail to reach a gate-passing state — a signal that the problem likely isn’t a small bug, but a more fundamental misunderstanding of the task or spec given.
What must be ensured: this gate is genuinely mandatory, not optional and skippable when in a hurry. Once an exception of “let’s skip the gate this time because we’re in a rush” appears, the practice tends to repeat, and eventually the guardrail loses its function as a consistent fence.
Independent Reviewer Agents
One effective pattern for overcoming the self-verification limitation discussed at the start of this article is using a second agent, separate from the one doing the implementation, specifically to review its results. Because this reviewer agent doesn’t share the same reasoning chain as the implementer agent — its context starts fresh, seeing only the final result and the spec, not the thought process behind the implementation decisions — this reviewer doesn’t inherit the same confirmation bias.
flowchart LR
A[Implementer Agent] -->|Result + Diff| B[Reviewer Agent<br/>Separate Context]
C[Spec & Acceptance Criteria] --> B
B --> D{Findings?}
D -- No Significant Findings --> E[Pass]
D -- Findings --> F[Return to Implementer]
F --> AThis pattern is effective but has a trap to watch for: a reviewer asked generally to “look for problems” tends to always find something to report, even when the work under review is actually good — because that’s what it was asked to do. Chasing every reviewer finding without consideration actually pushes toward over-engineering: unnecessary extra abstraction layers, excessive defensive code, or tests for scenarios that realistically can’t happen.
ANTI-PATTERN (chasing all reviewer findings):
The reviewer reports 12 "potential issues". The implementer tries
to address all of them, including ones that are actually irrelevant
to correctness or the stated requirements, producing code that is
more complex than needed.
CORRECT (filter by relevance to requirements):
Instruct the reviewer to only flag findings that affect correctness
or requirements explicitly stated in the spec, and treat the rest
as optional — not obligations that must be handled before passing.
Another limitation of this pattern: a reviewer agent, though independent in context, remains a probabilistic system with the same limitations as any agent — it can miss errors, or flag something that isn’t actually a problem. A reviewer agent is a useful additional layer, not a full replacement for human review on high-risk changes.
Detecting and Limiting Blast Radius
The term blast radius — how wide the impact can spread if something goes wrong — becomes a central concept in designing guardrails for agents with growing action autonomy. The more capable an agent is at acting, the larger its potential blast radius when an error or misuse occurs, so limiting blast radius needs to be an explicit design consideration, not an assumption that the agent will always act as expected.
The most effective strategy for limiting blast radius is execution isolation — running the agent in an environment completely separate from production systems and developer systems:
- Restricted filesystem — the agent only has access to the relevant project directory, not the whole home directory or a broader file system
- Network isolation — the domains the agent can reach are explicitly restricted (allowlist), preventing unwanted outbound communication to unknown domains
- Separate working environment (worktree/isolated branch) — changes are made on a separate branch or worktree, not directly on the main branch, so problematic changes can be discarded without affecting stable code
- Least-privilege credentials — the agent is given tokens with short lifetimes and the minimum access rights needed for that task, not full-access credentials used for everything
flowchart TD
A[Agent Acts] --> B{In an Isolated Environment?}
B -- Yes: Separate Sandbox/Worktree --> C[Errors Confined to the Sandbox]
C --> D[Easy Rollback: Discard the Sandbox]
B -- No: Directly on the Main System --> E[Errors Can Spread Widely]
E --> F[Rollback Hard & Risky]The principle underlying all these strategies is the same: treat agent output as untrusted by default, and enforce that restriction structurally through technical isolation — not heuristically by hoping the agent “will behave” because it was instructed not to do certain things. Instructions like “don’t access directory X” can be ignored or bypassed; an actual filesystem restriction can’t.
Relying on instructions alone (“please don’t touch this file”) as the only guardrail is a fragile practice. Truly reliable boundaries are enforced structurally — via system permissions, filesystem isolation, or network controls — not via polite requests hoping the agent complies consistently in every condition.
An additional benefit of execution isolation: changes made in a separate environment are far easier to roll back than changes that have already spread across various interconnected parts of the system. If a task turns out to produce the wrong approach, discarding the whole sandbox or worktree and starting over is far simpler and safer than trying to undo part of changes already mixed with other valid changes.
Determining When Humans Must Step In
Not every decision can or should be fully delegated to automated layers. Some signals should trigger mandatory escalation to humans, regardless of how mature the automated guardrail layers are:
Changes touching security or compliance constraints. Recalling the constraints discussion in Part 2 of the Spec-Driven Development series — changes touching sensitive areas like authentication, encryption, or personal data handling deserve explicit human review, regardless of whether automated tests already pass.
The work scope expands beyond the agreed task. If the agent discovers that completing the task correctly actually requires changes outside the already-approved scope — recalling the scope boundary discussion in Part 3 — this is a signal to stop and confirm with a human, not to continue the scope expansion unilaterally.
Ambiguity that can’t be resolved from available information. When the spec, context, and existing exploration results still aren’t enough to determine the correct approach with adequate confidence, continuing with self-made assumptions risks producing work that must be torn down and redone. Escalating at this point — asking for clarification instead of guessing — is almost always cheaper than continuing with a wrong assumption.
Automated gates failing repeatedly without progress. As mentioned in the automated gate section — if the agent has tried several times to fix results that fail the gate and still can’t succeed, this is a signal that the problem is likely more fundamental than a small bug fixable with additional iterations.
| Escalation Signal | Why It Can’t Be Left to Automation |
|---|---|
| Touching security/compliance constraints | High error consequences, needs contextual judgment |
| Scope expanding beyond the agreed task | A decision about priorities and work scope, not purely technical |
| Ambiguity unresolved from available information | Continuing with a wrong assumption costs more than waiting for clarification |
| Automated gates failing repeatedly without progress | Likely a fundamental misunderstanding, not a small bug |
Define these escalation criteria explicitly as part of the guardrail, not left to the agent’s judgment in the moment about “whether this is important enough to ask”. Explicit, consistent criteria prevent the agent from continuing risky work just because it “feels confident enough” to proceed at that moment.
Anti-Patterns in Guardrails
Several patterns weaken guardrail effectiveness even though they look like sensible practices on the surface:
Guardrails too loose — everything verified by the same agent. Relying entirely on self-verification without an independent layer, exactly the problem discussed at the start of this article. Confirmation bias makes this layer insufficient for work with meaningful consequences.
Guardrails too strict — approval at every line until autonomy disappears. The opposite of the problem above: asking for human approval at every small step eliminates the main benefit of delegating to an agent. As discussed in the “fence, not obstacle” section, effective boundaries target the types of risky actions at the right phase, not interrupt every action regardless of risk.
Depending 100% on automated tests with no human review at all for high-risk items. Passing tests give confidence in what those tests cover, but don’t guarantee there are no problems outside what’s covered. For changes touching sensitive areas, relying on passing tests as the only “safe” signal ignores the type of risk that genuinely needs human judgment, as discussed in the escalation criteria section.
Instructions as the only form of restriction, without structural enforcement. Already discussed in the blast radius section — asking the agent “please don’t do X” without actually preventing it technically is a fragile, inconsistent guardrail.
Allowing “skip the gate this time” exceptions because of rushing. Once one exception is made, the next becomes easier to justify, and eventually the supposedly mandatory gate loses its function as a consistent fence.
The latest production agent security survey found that only a small fraction of the agents evaluated actually met adequate security control standards, even as their capabilities keep growing rapidly. The gap between how capable agents are at acting and how well those actions are controlled is a real challenge in the field, not merely a theoretical concern.
Summary
- Self-verification alone isn’t enough — an agent evaluating its own work is prone to confirmation bias because it shares the same reasoning chain that produced the work; an independent evaluation source is needed
- Effective guardrails work as a layered stack: automated tests and linters (deterministic, cheap) filter out as many problems as possible before reaching reviewer agents or human review (more expensive, reserved for cases that truly need them)
- Good guardrails function as fences that limit impact, not obstacles that kill autonomy — phase-based tool permission restrictions (read-only during planning, writes during execution) give a concrete example of this approach
- Automated gates formalize cross-task-group checkpoints into explicit, mandatory conditions (tests passing, clean lint, contract tests matching the spec) before the agent is allowed to continue — gate failures are a normal part of the loop, not an exceptional event
- An independent reviewer agent is effective because it doesn’t inherit the implementer agent’s confirmation bias, but needs direction to focus on findings relevant to requirements, not chase every potential issue that could drive over-engineering
- Blast radius is best limited through structural isolation — restricted filesystems and networks, separate working environments, least-privilege credentials — not through instructions hoping to be obeyed
- Mandatory escalation to humans for: changes touching security constraints, scope expanding beyond the agreed task, unresolved ambiguity, and repeated gate failures without progress
- Avoid two opposite extremes: guardrails too loose (only self-verification) and too strict (approval at every line) — both equally weaken the autonomy benefit agentic development is supposed to provide