In March I wrote about a 30-line shell hook that turned my coding agent into a self-improving system. The hook re-injects four rules on every prompt; the agent stops repeating mistakes; the loop closes. I stand by every word of that post. It is true.
It is also half the story.
What I didn’t say — because I hadn’t quite seen it yet — is that the PID controller in that hook can be perfect, and the system can still stabilise at the wrong place. Because the controller is only half of a control loop. The other half is the setpoint. And the setpoint, in everyone’s agentic workflow including ours, is usually a mess.
A perfect thermostat, set wrong
Imagine a perfect thermostat. The sensor is accurate to a hundredth of a degree. The control law is tuned. The actuator is strong. You install it in your home and the customer sets the dial to “comfortable.”
The thermostat will hold the room at exactly whatever value it decided “comfortable” meant. Maybe 22°C in summer, 18°C in winter, 25°C the day after a fight with the spouse. The room is consistently at a temperature. Just not the right one. The complaint will not be that the temperature wobbles. It will be that the temperature is wrong.
This is the failure mode AI coding agents exhibit constantly. Not a noisy controller. Not a slow controller. Not a forgetful one. A vague setpoint.
You hand the agent a one-line prompt — “fix the form so it saves correctly” — and it works confidently, decisively, for an hour, and lands somewhere. The somewhere it landed is a solution. It is not necessarily the one you wanted. The hour was not wasted in the sense that it produced output. It was wasted in the sense that the output describes a different goal than the one you held silently in your head.
The PID hook does not help here. The PID hook is the controller. It can stabilise around any setpoint; it cannot improve the setpoint.
What a setpoint actually has to be
Control theory recognises three forms a setpoint can take, in increasing order of dimensionality:
| Form | When it works | Example |
|---|---|---|
| Scalar | 1-DOF system | Thermostat → 21°C |
| Trajectory / vector | n-DOF system | Drone → path through 3D space |
| Cost function (predicate) | Complex-goal system | Chess → minimise material loss while maximising king safety |
Software systems are massively multi-degree-of-freedom and the goal is almost always a complex predicate. A piece of software is “correct” if and only if a long list of conditions hold simultaneously: the form saves, the validations fire, the email goes out, the audit row is written, the existing tests still pass, the new edge case is covered, the database column is the right type, no PII leaks into the log.
A one-sentence user prompt is a scalar setpoint. Telling a multi-DOF system “be comfortable” is provably insufficient — there is more than one configuration that satisfies a scalar interpretation of comfort. The system will pick one. You will not get to choose which.
This is not a critique of language. Language is fine. It’s a critique of the implicit assumption that a sentence is enough information to drive an autonomous loop. It is not. It cannot be, by counting argument alone.
Setpoint Evals are the setpoint definition language
In a companion piece I describe Setpoint Evals (SEs) — shell scripts that submit a job to a real running system, poll its state, assert on what it ended up doing, and exit PASS or FAIL. We open-sourced a working implementation; you can clone it and run it.
This pattern isn’t new — it has industrial precedent. Back in 2013 I worked on the payment-routing engine at MoneyBookers (now Skrill, owned by Paysafe), where we tested routing decisions through banks as Fitnesse acceptance tables. Each row was an (input, expected route) tuple — pay €X from country A with card-type B, expect routing through bank C — and there were hundreds of such rows. The Fitnesse runner exercised the production code paths, compared actual vs expected, and turned each row green or red. The setpoint was the table; the controller was QA spotting newly-red rows and engineers writing fixes until the table went all-green again. Setpoint Evals are the same idea, port-scaled for an autonomous agent: shell-driven instead of wiki-driven, and run by a coding agent that can also propose new rows as the system grows.
I want to recast that pattern in control-theoretic terms, because the recast is the point of this article.
Each SE is a one-bit assertion about a system property. “After this request, the job status should be COMPLETED.” True or false. “The retry counter should be at least 2.” True or false. “No row should be left in the queue.” True or false.
A passing eval suite of N SEs is a vector of N ones — that is, a high-dimensional binary statement of “the system, right now, is in the goal state.” A run produces a measurement vector — [1, 1, 0, 1, 0, 1, …]. The difference between the goal vector and the measurement vector is the error vector. The agent reads it and acts.
That is a PID setpoint. Lifted out of scalar space and into high-dimensional binary space, but mathematically the same object. The controller compares; the agent corrects.
graph LR
Plan["Plan / SE READMEs<br/>(written first by human)"] --> Eval["SE suite<br/>(executable)"]
Eval --> Run["Run against system"]
Run --> Measure["Measurement vector<br/>[1, 0, 1, 1, 0, ...]"]
Goal["Goal vector<br/>[1, 1, 1, 1, 1, ...]"] --> Diff["Error vector"]
Measure --> Diff
Diff --> Agent["Agent decides next change"]
Agent --> Code["Code change"]
Code --> Run
style Plan fill:#1f2937,stroke:#3b82f6,color:#e5e5e5
style Eval fill:#1f2937,stroke:#3b82f6,color:#e5e5e5
style Diff fill:#1f2937,stroke:#3b82f6,color:#e5e5e5
style Agent fill:#1f2937,stroke:#3b82f6,color:#e5e5e5There is a beautiful corollary. This works for any backend. Almost everything we build is, formally, a state machine. State machines admit state predicates. Predicates compile to assertions; assertions compile to evals; evals compile to bits. The dimensionality of the setpoint is exactly as large as you need it to be to disambiguate the goal. You don’t have to argue about whether the agent “understood” — you can run the suite and read the vector.
(Frontends are harder, because UI state is less crisp. Playwright assertions, screenshot regressions, accessibility-tree snapshots — these are workable approximations, but they’re less precise than backend SEs. That’s a real footnote, not a deal-breaker. The pattern still applies; the assertions just ride on weaker signals.)
The full control loop, composed
The PID hook article gave us the controller — re-injected on every prompt, holding the agent to a measurement-and-correction discipline. The SE article gave us the setpoint — high-dimensional, executable, falsifiable. Together with a few other pieces, the loop now composes into a real control system, not a metaphor.
| Control component | Implementation | Purpose |
|---|---|---|
| P (proportional) | A per-prompt context-injection hook re-asserting a small set of standing rules | “How wrong are we right now?” |
| I (integral) | Persistent project rule files holding promoted gotchas | Past corrections that survive across sessions |
| D (derivative) | A self-monitoring rule: stop if the last few turns kept failing on the same sub-goal | “Is the error growing?” — catches runaway loops |
| Setpoint | Executable evals (SEs), plans with checkable acceptance criteria, or an explicit done = X statement | The goal vector |
| Sensor (measurement) | A structured issue log (free-form) + eval run results (structured) | What is the system actually doing? |
| Actuator | Bounded scripts that wrap dangerous operations (deploys, force-pushes, mass-merges) | Apply the correction safely |
| Saturation guard | Model-tier downgrade rules, max-turn caps, context-budget signals | Detect when output is at its limit |
What used to be “a coding agent with a hook” is now a complete cybernetic loop: every term named, every term implemented, every term composable with the others. None of this requires a smarter model. The model has been good enough for a while. What was missing was the plumbing.
The Setpoint Gate
There is a rule we have been missing, and it is the one I most want to give you. We call it the Setpoint Gate.
Before starting code work, the agent must verify that a sufficient setpoint exists. Sufficient means at least one of:
- A plan in
plans/with checkable acceptance criteria- One or more SEs in
setpoint-evals/that can be run to verify done- An explicit user statement of the form “done = X happens.”
If none of these are present, the agent does not invent the setpoint silently. It asks.
This is a hard rule. Not a hint. Not a polite suggestion. The agent refuses to enter the implementation loop until the setpoint is expressible.
The first reaction to this rule is that it sounds like friction. “Now I have to write a plan or some evals every time I want to ask my agent to fix a typo?” No — the trivial cases have a trivial setpoint (an explicit one-line done = X is sufficient, and most prompts already contain it). The cases that need a real setpoint are the cases that already need it; the rule only forces you to say it out loud. The cost lands almost entirely on prompts that were going to be ambiguous anyway, and the cost is the small one of writing the goal down before writing the code.
The second reaction is that the rule sounds counterintuitive. We were building agents that do more; now I am proposing we build agents that do less, until clearly told. But there is a precise control-theory analog. A real thermostat, when its setpoint sensor breaks, fails safe — it turns off. It does not guess that the customer probably wanted 21°C and run the loop on the guess. The customer is much better off with no heat than with confidently delivered wrong heat. We want our agents to behave the same way. An agent that produces a confident wrong solution is worse than an agent that asks; the wrong solution will be debugged for hours, the unanswered question is debugged in seconds.
The third reaction is that the rule is hard to enforce. Surprisingly, it isn’t. The hook re-injects it on every prompt. The pieces this depends on are simple: a way to write down a plan, a way to write down a few executable evals, a way for the agent to read both. None of that needs a framework. What’s new — and what’s surprisingly powerful — is the refusal posture: the explicit “I will not start until I have a setpoint.” That’s three lines of standing instructions.
The bottleneck has moved
Once you have all five terms wired — controller, integral, derivative, setpoint, actuators — something interesting happens to the human work.
It used to be that the human’s job, in agentic engineering, was to review the agent’s output — read the diff, run the tests, catch the bullshit, send it back for round two. That work was real. It was where the day went. Most posts about “what’s it like to use AI to code” are really posts about what reviewing AI output is like.
With the loop closed properly, that work shrinks dramatically. Not because the agent is smarter — because the measurement is structured. You don’t review the diff to see if it’s correct; you run the eval suite. The eval suite either passes or it doesn’t. The agent does the round-two work itself, against the same evals. Your review work is no longer “did this code do the right thing”; it’s “did this PR do something I want” — a much shorter review.
But the work that grows is the work of expressing the setpoint precisely. Before the agent runs. The day shifts from “check the output” to “specify the input”. From line-by-line code review to predicate-by-predicate goal articulation. This is a strict net win — articulating goals is the work humans are uniquely good at, and reviewing line-by-line is the work humans are uniquely bad at — but it is a different shape of day.
The implication for the field is sharp: the next frontier of agentic engineering is goal-articulation tooling, not bigger models. Most teams are still trying to buy capability from the model side. The capability is already there. What is missing is the disciplined act of writing the goal down precisely enough that a machine can verify it. SEs are one shape of that. Plans with acceptance criteria are another. Either is dramatically more useful than another point on a benchmark.
What this looks like in practice
If you want to try this in a single afternoon:
- Pick one feature that is currently waiting on agent work. Something concrete enough to fit on a whiteboard.
- Write three to seven SE READMEs for it (or, if you can’t yet — write three to seven plan items with checkable acceptance criteria). Each one is one paragraph: “When X happens, the system should end up in state Y.”
- Hand it to your agent with a prompt that names the setpoint and the gate explicitly. Something like: “Setpoint: every SE in
setpoint-evals/feature-x/must pass. Don’t start coding until you’ve read every README and asked any clarifying questions. When the suite is green, stop.” - Watch the first response. It will probably be questions, not code. That is the loop closing. Answer the questions. Then walk away.
The rule, written down once, becomes the gate. It is the same shape as the original PID hook — three lines of standing instruction that the agent cannot forget because the instruction is being re-asserted into context on every turn.
Closing: from regulator to cybernetic system
The PID hook gave us a controller. SEs give us a setpoint. The Setpoint Gate keeps the loop honest by refusing to run with a missing reference signal. Memory gives us the integral term that survives across sessions. A small self-monitoring rule gives us the derivative term that catches runaway loops.
What we are looking at, when all of these are wired together, is no longer “a coding agent with a clever hook.” It is a working cybernetic system, with a sensor, a controller, an integral memory, a derivative watchdog, a high-dimensional reference signal, bounded actuators, and a failsafe posture. None of the parts require a vendor. None require a framework. None require a bigger model. They require the discipline to say what done means precisely, and to wire that statement into a loop that closes on every prompt.
The model isn’t the bottleneck. It hasn’t been for a while. The bottleneck is whether you can say what done means precisely enough that a machine can verify it.
Build that. Everything else follows.
The PID hook article — the prequel to this one — is The PID Regulator for AI Agents. The Setpoint Evals article — the implementation of the setpoint pattern — is Setpoint Evals: Giving AI Coding Agents a Long Horizon. The companion repo for SEs is at inctasoft/setpoint-evals-for-agentic-engineering-example.
🤖 Built with Valko — voice-driven AI coding.
Drafted with Claude Opus 4.7 in a working session about agentic-engineering practice. The Setpoint Gate is being added to our team’s standing instructions as we publish this. If you’d like help wiring this pattern into your own workflow, reach out at valko.ai.