Esoteric AI · Issue 2

Prompts advise, types describe, gates enforce

A rule written in a prompt holds until the model has a good enough reason not to follow it. Long runs supply plenty of reasons.

Viable Agents · Part 2
  • agent harnesses
  • guardrails
  • mechanism hierarchy
  • regulator
  • coding agents

Open the instruction file in almost any repository that uses coding agents (AGENTS.md, CLAUDE.md, .cursorrules) and you'll find a paragraph like this:

## Rules
- Never edit a migration that has already shipped. Add a new one.
- Always run the full test suite before saying you're done.
- Don't touch anything under vendor/.
- Keep the public API backwards-compatible.

Every line is reasonable, and most of them are followed most of the time. Last week I argued that agents amplified the variety of the changes reaching a codebase without amplifying anything that regulates them. This week's question follows directly: what is that paragraph, as a regulator? How much variety can it absorb?

The answer is less than it looks. The reason isn't that prompts are bad. It's that a prompt is a particular kind of regulator, and most of the rules in that paragraph need a different kind.

A prompt is an open loop

Recall the law from last week: to hold outcomes in bounds, a regulator needs a distinct response for each distinct disturbance, and a way to tell which disturbance it is facing.

Now look at what the rules paragraph actually is. It is a set of responses written before the run starts, delivered once and applied to everything the run will meet. It doesn't observe anything. It never compares what happened with what should have happened. In control terms it's open-loop: instructions sent forward with no sensor and no comparator behind them.

Open-loop control works when the system being steered is predictable. A thermostat-less heater set to "medium" keeps a room comfortable on a mild day. A language model in a long run is not that system. A rule in context competes with everything else in context: the task, the transcript, a failing test, a tool result that says "the fastest fix is in vendor/". The rule holds until something in the run makes a good enough case against it. A compaction that summarizes it away, a hundred turns of unrelated work, or a persuasive error message is often enough.

The useful way to put it: a rule that holds four times in five is not a rule. It's a tendency. You can't build on a tendency, and you can't review your way out of one at the volume agents produce.

None of this is a criticism of prompts. It's a count. A prompt absorbs as much variety as it has distinct, followed instructions for, and it can't tell you which ones were followed.

The hierarchy

regulator, the harness I'm building alongside this series, has a three-sentence prime directive:

Prompts advise. Types describe. Gates enforce.

Behind it is an ordering. When you need a rule to hold, reach for the highest level that can express it, and only move down when the level above genuinely can't:

1. type / compile-time invariant    the wrong value cannot be built
2. deterministic runtime check      the harness refuses, every time
3. typed tool with a schema         the model cannot ask for it
4. model judgment                   the model decides, and leaves evidence
5. prompt / context                 the model is advised

The levels are ranked by reliability under pressure. A type holds whatever the prompt says. So does a gate. A sentence in a context file holds until the run produces a reason not to follow it.

Take two rules from the paragraph and walk them down the ladder.

"A deployment is in exactly one state." This one can live at level 1. Last week's Deployment with a status enum and four orthogonal flags became a sum type with eight variants, and the 56 unintended combinations stopped being representable. No agent can add cancel_requested beside the status without changing the type, and changing the type is a visible, reviewable act. That's what "types describe" means. Yaron Minsky's old maxim, make illegal states unrepresentable, is a level-1 rule.1

"Never edit a migration that has already shipped." Files aren't types, so this can't live at level 1. But it can live at level 2: a check that compares every migration on main with its hash at release and fails the build if one changed. Better still, run the same check before the write, in the harness's tool-call hook, so the agent is refused at the moment it tries rather than at the pull request. Level 3 is an alternative: give the agent a create_migration tool and no write access to the migrations directory, so the only thing it can ask for is a new one. Level 4 is asking the model, when a migration edit seems necessary, to stop and justify it on the record. Level 5 is the sentence in AGENTS.md.

All five are real options. They aren't equally reliable, and for this rule levels 2 and 3 are clearly available. That gives the rule of thumb I now apply to every instruction file I review:

If you can write the check, don't write the paragraph.

What the lower levels are for

The hierarchy is easy to misread as "prompts bad, gates good." It says something narrower.

Levels 4 and 5 are legitimate and necessary. They carry everything a gate can't know: intent, taste, the shape of a good commit message, which of two correct designs this codebase prefers, why the team cares about a convention. Model judgment (level 4) is a genuine decision point. Some questions can't be resolved mechanically, like whether a change is "backwards-compatible" in the sense your users mean. Even then the answer should leave evidence that something downstream can check.

What the hierarchy rules out is solving a level-2 problem at level 5. "Don't touch vendor/" is a level-2 problem: the harness can see every write and refuse the ones under that path. Putting it in a paragraph doesn't make it wrong. It makes it a tendency.

It also doesn't say "always go to level 1." Some rules can't be types, and pretending they can produces type gymnastics nobody maintains. The discipline is to ask, for each rule, what is the highest level that can express this? When you settle lower, write down why.

Guides and sensors, with a ranking

If this sounds familiar, it should. Birgitta Böckeler's recent pieces on harness engineering make a closely related argument: surround the agent with guides that steer it before it acts and sensors that detect problems after, and mix deterministic checks with inferential review.2

In cybernetic terms, guides are feedforward and sensors are feedback, and you need both. The hierarchy adds two things to that picture.

First, a ranking. Guides and sensors are not interchangeable at a given level of trust. A guide is mostly level 5 or level 3; a deterministic sensor is level 2; an inferential sensor (a reviewer model) is level 4. Knowing which level a mechanism lives at tells you how much weight it can bear.

Second, where the loop closes. A sensor is only as useful as how soon it reports. A check in CI catches a shipped-migration edit when the pull request opens, possibly hours of agent work later. The same check in a tool-call hook catches it at the write, before anything else is built on top of it. The cost of an error is set less by the error than by how long it takes the loop to see it. That's feedback delay, and it's the reason regulator's gates sit inside the turn wherever they can.

Every gate is a claim

Here's the part that keeps the hierarchy honest, and it's the part most "guardrails" writing skips.

Suppose you write the gate: every write and edit under vendor/ is refused. Now ask the agent to make the change anyway. If its shell is available, sed -i walks straight past the gate, because the gate covered the tools it covered and not the one the agent used instead.

A gate protects the routes it covers. An honest harness documents the routes it doesn't.

regulator turns that sentence into a requirement. Every regulator in it, gate or check or typed tool, has a registry record, and the definition check refuses any record without at least one limitation: a stated route around it. The record also names the mechanism's level on the hierarchy, the evidence that it works, the switch that turns it off for an evaluation, and the condition under which a person would retire it.

The registry also keeps the history of a gate that wasn't good enough. regulator's first write gate matched protected paths by string. It was retired and replaced by an identity write gate that checks the real path, through any spelling, ../ traversal or symlink. That still doesn't cover the shell, because no hook can sandbox a shell. So a second layer snapshots the protected files before every shell command, restores them afterwards and records the change as a finding. A third layer diffs the unit's branch against its base at closeout and refuses to land anything that touched them, by any route. Each layer catches what got past the one before, and each layer's record says what it misses.

That's what level 2 looks like when it's taken seriously. It isn't one gate that "enforces" a rule. It's a stack of mechanisms, each with a published boundary, arranged so the boundaries don't line up.

Where the analogy fails

The ranking describes mechanisms, not implementations. A buggy gate is worse than a good prompt, because it fails confidently. Level 2 is more reliable than level 5 only when the check is correct, and checks have bugs like any other code.

Gates have costs, and some of them are invisible. Every refusal is variety pointed at the agent. Point it at the wrong thing and you get a harness that blocks correct work, burns budget on retries and teaches its users to switch it off. Over-regulation is a real failure mode. Issue 21 is about how regulator found one in itself.

The agent can argue with a gate by changing it. A model that can't satisfy a check can sometimes edit the check instead: delete the test, loosen the schema, add an exception. That's why the gates and the definitions behind them need protection of their own. Who may change the rules is a different question from who must follow them, and it gets its own issue in February.

Some rules are irreducibly judgment. "Keep the API backwards-compatible" can be partly mechanized (signature diffs, contract tests), but the part that depends on what your users rely on stays at level 4. The goal isn't to push everything up the ladder. It's to stop leaving at the bottom what could have climbed.

One exercise for this week

Open your instruction file. For every sentence containing never, always, must or don't, write the number of the highest level that could express it. Most teams find several level-5 sentences that could be level 2 with an afternoon's work, and a few that genuinely belong at level 5 and should say why they're there.

Then pick one and move it. Write the check, delete the sentence, and see whether you miss it.

Next week: back to the Deployment. Its four unanswered questions have an answer. It just isn't in the code.


Lab note. regulator is an open-source agent harness on Pi that runs Beer's Viable System Model as explicit functions, typed channels and gates. Its registry has 44 records (two of them retired), each stating its level on this hierarchy and at least one route around it.

If you read my last essay, you'll remember I recommended gsd-pi. I still think it's one of the best-structured harnesses around, and regulator borrows a good deal of vocabulary from it. The difference is one of placement. GSD builds its workflow (milestones, slices, phases, verification) into the harness itself. regulator keeps the control loop deliberately small and generic, and declares everything workflow-specific in a separate workload definition. That's so the same loop can regulate a codebase or, as a later issue shows, a household's finances. Different bets, both worth studying.

Notes

  1. The phrase is Yaron Minsky's, from his "Effective ML" talks and Jane Street writing around 2010–2011. It has since become common currency well beyond ML. ↩
  2. Birgitta Böckeler, "Harness engineering for coding agent users" and "Maintainability sensors for coding agents", on martinfowler.com. Both are worth reading in full. The guide/sensor split is hers; the ranking by reliability is the addition this issue argues for. ↩
The ideas in this essay are built out in Viable Agents, a course in which you write your own agent harness as a control system. Published here first; the Esoteric AI newsletter carries it to your inbox.