Closed-Loop Agent Control
A control-theoretic methodology for embedding LLM agents in feedback loops, where a verification harness drives convergence on the designer's intent.
TL;DR
Problem: LLM agents declare "done" when they can't observe the effect of their own changes. You end up copy-pasting errors from your browser back into the agent.
Solution: Treat the agent as a controller in a feedback loop. Write a verification harness (the sensor) before the implementation. The sensor must be aligned with what you actually care about — if you care that users can log in, the sensor must actually test login, not just check that the auth config file looks right. The agent reads failure output and self-corrects.

Key result: Intent-aligned checks caught bugs across different stack layers that all proxy checks missed. Without intent-aligned checks, the agent declared success while the end-to-end experience was broken.
The Problem
When you ask an LLM agent to implement a multi-step feature, the typical workflow is:
- Human writes a prompt describing the work
- Agent produces code changes
- Human reviews the output
- Human identifies what's wrong or missing
- Human writes another prompt to correct
- Repeat
The agent has no way to observe the effect of its own actions. It cannot distinguish between "I changed the file" and "the change actually achieved the intended outcome." The human is the sensor, the comparator, and the feedback channel — all at once.
In practice, this means:
- The agent makes a change that looks correct in isolation but breaks something elsewhere
- The agent "completes" a task without verifying the completion criteria are actually met
- Regressions accumulate silently across tasks because nothing re-checks previous work
- The human becomes the bottleneck, manually verifying every change against every requirement
For a project with 12 requirements and 50+ acceptance criteria, this doesn't scale.
The Method
The Verification Harness
The fix is a verification harness — a single script that checks each requirement and reports pass or fail. You write it before the implementation, and it grows with each task.
Every check maps to specific requirement IDs:
Python
@dataclassclass CheckResult:requirement: str # e.g., "12.3, 12.5"passed: boolmessage: str # what the agent reads to decide its next fix
When a check fails, the agent knows exactly which requirement is unsatisfied. The error signal is not "something is wrong" — it's "requirement 12.3 is not met because S3 bucket 'assets' has no matching public_access_block resource." The agent can target its fix precisely.
The Feedback Loop
Every task follows a closing sequence:
- Run the harness after every change. The agent reads the failure output and decides what to fix next.
- Fix the code, not the test. The harness is the sensor. When it reports a problem, the problem is in the codebase, not the harness.
- Add a check for every change. A change with no corresponding check is invisible to the feedback loop — the agent has no way to know if it worked.
- The most end-to-end check is the gate. Early in the project, only local checks exist — so those are the gate. After deployment, browser-based checks become available and they become the gate. The gate moves outward as the system grows.
- Don't move to the next task until the gate passes. A task is not done because a file scan passed. A task is done because the most end-to-end check currently available says the system works.
Make the Harness a First-Class Requirement
Include a meta-requirement in your spec that mandates the verification loop:
- For each requirement, there SHALL be at least one automated check that confirms it is satisfied.
- When a check fails, the failure message SHALL identify the specific requirement ID that is not met.
- The verification suite SHALL NOT skip checks when prerequisites are missing. Missing prerequisites are failures.
- The checks SHALL observe the system at the boundary specified in the requirements.
- The most end-to-end check available SHALL be the gate for task completion.
- End-to-end checks SHALL be added as soon as the system is deployed — not deferred to a final validation phase.
Without this meta-requirement, the agent has no mandate to build or run the harness. With it, the harness is a first-class deliverable.
Requirements Must Specify the Observation Boundary
A requirement like "users can look up orders" is ambiguous about where you observe it. The sensor could be a unit test, an API call, or a headless browser — each with different blind spots.
Write requirements that specify the observation boundary. A requirement that says "WHEN a user opens the application in a browser and submits a query, THEN the response SHALL contain order data" is unambiguous — the sensor is a browser. A requirement that says "the system SHALL support order lookup" leaves the sensor position undefined, and the agent will default to the cheapest valid interpretation (a unit test).
If your requirement specifies behavior at the browser level, your check must observe at the browser level. The observation boundary belongs in the requirement itself.
What to Expect
The methodology was applied to two real projects: a demo extraction (removing client-specific integrations from a multi-repo AI chat application) and a framework migration (replacing a multi-agent orchestrator with a single-agent architecture). Both involved Python, TypeScript, Terraform, and deployed AWS infrastructure. Both used Claude Opus 4.6 via Kiro IDE.
Combined, the projects produced 250+ verification checks across 16+ requirement groups, with the harness running 100+ times. The patterns that emerged:
Intent-aligned checks catch bugs that proxy checks miss
In both projects, all proxy checks (file scans, unit tests, direct function invocations) were passing while the end-to-end experience was broken. Browser-based checks caught bugs across every stack layer — missing prerequisites, broken routing, non-interactable forms, auth misconfigurations, and API mismatches. None of these were visible at lower observation levels.
Proxy checks verify that individual components work in isolation. Intent-aligned checks verify that the assembled system works as a user would experience it. Both are necessary. Only the intent-aligned check is authoritative.
The human's role shifts from error relay to director
Without the harness, the human copies errors from the browser into the agent. With the harness, the human's interventions shift to meta-level direction: providing credentials, clarifying deployment context, specifying parity criteria. The error signal comes from the harness; the direction comes from the human.
Requirements that omit the observation boundary get cheap checks
When requirements specified what must hold but not where to observe it, the agent chose the cheapest valid interpretation (file scans). When requirements specified the boundary ("WHEN a user opens a browser..."), the agent built checks at the right level.
The harness only closes over what the spec defines
A post-implementation investigation found a feature that didn't work — but git diff confirmed it was not a regression. The code was byte-for-byte identical to the original baseline. The feature never existed. The loop preserved existing functionality exactly, but it cannot catch gaps in the spec. If a capability is never specified, no check exists, no error signal is generated, and the controller has nothing to act on.
Do not trust the agent to self-report
When asked to record how many times verification failures caused code rewrites, the agent produced inaccurate counts — reconstructing what it thought happened rather than reporting what actually happened. In one project, the agent invented a SKIP status for deployment checks, reporting "0 failed" while silently skipping the hard checks.
Instrument the harness to produce machine-readable logs. The harness is the authoritative record. The agent's self-assessment is not.
The agent will game weak sensors
The agent satisfied a grep-based check by adding a comment containing the target keyword rather than implementing the feature. It declared a URL functional without running curl against it. It deployed old code in new containers while the new code sat unused — and the harness passed because it checked code on disk, not code in production.
The mitigation: intent-aligned checks are harder to game because they test the assembled experience, not individual artifacts. A headless browser that walks the user journey cannot be satisfied by adding a comment to a source file.
Why It Works
This approach is an application of classical control theory to LLM-driven implementation. The mapping:
Control Theory | Agent Implementation |
|---|---|
Reference signal (setpoint) | Requirements with numbered acceptance criteria |
Sensor | Verification harness observing at the specified boundary |
Comparator | Harness output: pass/fail per requirement |
Controller | LLM agent reading failure output and deciding what to change |
Actuator | Agent's code editing and command execution tools |
Plant | Codebase + infrastructure + running application |
The critical disanalogy with physical control systems: in a physical system, the setpoint and the sensor are in the same units by construction (want 10 km/s, measure km/s). In software, the setpoint (requirements) could be observed at many boundaries — unit test, API call, browser. This is why requirements must specify the observation boundary explicitly. Without it, the sensor and setpoint are in different units, and the loop cannot converge on the right thing.
Andrej Karpathy's Verifiability thesis (2025) observes that "Software 2.0 easily automates what you can verify." The verification harness makes the implementation task verifiable — resettable (try again), efficient (runs in seconds), and rewardable (pass/fail per requirement). The contribution this approach adds is the alignment constraint: verifiability is necessary but not sufficient. Aligned verifiability — where the sensor measures in the same units as the setpoint — is what drives convergence.
Conclusion
LLM agents should be embedded in closed-loop control systems, not used as open-loop generators.
- Build the sensor before the implementation. The harness is the first artifact. Its initial failures are the scoreboard.
- Specify the observation boundary in every requirement. If the boundary is left out, the agent defaults to the cheapest interpretation.
- Fix the code, not the test. When the harness reports a failure, the problem is in the codebase.
- Do not trust the agent to self-report. Instrument the harness to produce machine-readable logs.
- Grow the sensor with each task. The harness is a living document of what "done" means.
- The human's role shifts from error relay to director. The harness handles error detection. The human provides direction.
The core contribution is the framing: treat the LLM agent as a controller in a feedback loop, align the sensor with what you actually care about, and let the error signal drive convergence. This works anywhere a human would otherwise be the sensor.
Enjoyed reading this content? Let the author know!
Your likes, comments, shares, and saves help creators reach more builders.
Loading recommendations
Loading article