Dev

Ein Prompt ist keine Invariante

Eine Regel, die du in einen Agenten-Prompt oder eine CLAUDE.md schreibst, ist unverbindlich: Das Modell liest sie auf jedem Pfad, wägt sie aber nur ab, und Abwägen ist kein Verweigern. Also hält sie meistens, und meistens ist nicht das, wofür eine tragende Regel da ist. Damit eine wirklich hält, muss sie dorthin, wo Befolgung nicht optional ist: zu einer Prüfung, die die Harness selbst ausführt und durchsetzt, unabhängig davon, wie das Modell entschieden hat. Mit einer Grenze: Ein Gate bindet nur über die Pfade, die es abdeckt, und manche Regeln lassen sich an keinem Gate klären, weil ihr Verstoß in der Welt auftaucht und nicht in der Aktion, die es prüfen würde.

Jeder Agent, den ich betreibe, ist größtenteils durch Regeln definiert, die in Prosa geschrieben sind, und diese Regeln sind nicht alle von derselben Art, auch wenn sie in derselben Datei im selben Ton stehen. Manche sind Geschmack: nimm die kleinere Abhängigkeit, halte eine Funktion kurz genug, um sie auf einen Blick zu lesen, benenne Dinge so, dass niemand nachfragen muss. Manche sind tragend: niemals ein zerstörerisches Löschen außerhalb der Sandbox ausführen, niemals direkt auf main pushen, niemals ein Secret ins Log schreiben. Die erste Art kann verrutschen und kostet ein bisschen Feinschliff. Verrutscht die zweite Art, ist es der Vorfall. Und an dem Tag, an dem ich anfing, die zweite Art aus den Dateien herauszunehmen und in etwas zu verlegen, das die Harness ausführt, egal was das Modell entscheidet, sah ich, was die Dateien die ganze Zeit getan hatten, und es war weniger, als ich angenommen hatte. Sie hatten die Regeln genannt. Durchgesetzt hatten sie sie nie.

Der Fehler ist leicht gemacht, denn ein „immer" oder „niemals" in einen Prompt zu schreiben fühlt sich an, als setze man eine Bedingung. Es liest sich so und es ist so geformt. Aber die Datei nennt einem Leser eine Absicht, und dieser Leser fügt sich aus Disposition, und Disposition ist eine Wahrscheinlichkeit, kein Versprechen. Das Modell gewährt der Regel meistens ihren Vorrang, und meistens ist eine andere Eigenschaft als jedes Mal. Für Geschmack ist das in Ordnung. Für eine Regel, deren einzige Aufgabe es ist, in dem einen Moment zu halten, in dem sie geprüft wird, ist meistens keine schwächere Garantie. Es ist das Fehlen einer Garantie.

Was echte Durchsetzung ausmacht

Borge dir die Idee aus dem Teil der Technik, der sie schon hat. Eine echte Bedingung tut zwei Dinge, die ein Satz nicht kann. Sie bindet: Den verbotenen Zustand zu erreichen ist kein verfügbarer Zug, kein bloß unerwünschter. Und sie deckt ab: Sie sitzt auf jedem Pfad zu diesem Zustand, sodass nichts an ihr vorbei dort ankommt. Ein Typ bindet und deckt ab, der Compiler wendet ihn auf jede Zuweisung an und weist den falschen Wert zurück. Ein Datenbank-Constraint tut beides ebenfalls, denn jeder Schreibvorgang im System läuft durch ihn hindurch. Eine Assertion bindet, deckt aber kaum ab: Sie verweigert an der Zeile, wo du sie hinsetzt, und sieht nichts auf den Pfaden, die diese Zeile nie erreichen.

Eine Regel in einem Prompt hat das umgekehrte Profil, und es ist das schlechtere. Sie deckt alles ab, denn das Modell liest sie auf jedem Pfad, und es gibt keine Route, auf der die Regel einfach fehlt. Was sie nicht tut, ist binden. Sie wird gelesen und gegen alles andere im Kontextfenster abgewogen, und Abwägen ist kein Verweigern. Eine Regel, die genug umgebender Kontext beiseite argumentieren kann, war nie bindend; sie war eine starke Präferenz mit guter Statistik. Die Abdeckung war nie das Problem. Das Problem ist, dass unter der Abdeckung nichts ist, das Nein sagt.

Dieselbe Regel als Satz und als Gate

Nimm „niemals direkt auf main pushen" und setze es an zwei Stellen. In einer CLAUDE.md ist es eine Zeile, die das Modell liest und meistens einhält. Gib ihm eine plausible Geschichte, dieser Push ist die Ausnahme, der Fix ist dringend, die Regel ist das Einzige, das im Weg steht, und es führt den Befehl aus, nicht aus dem Wunsch, sich dir zu widersetzen, sondern weil du ihm einen Satz gereicht hast und es den Satz abgewogen hat.

Jetzt setze die Regel dorthin, wo die Harness sie ausführt. Die Hooks von Claude Code sind das nächstliegende Beispiel, und das Wort, das das Gewicht trägt, steht in der Definition:

Hooks are user-defined shell commands, HTTP endpoints, MCP tool
calls, LLM prompts, or subagents that execute automatically at
specific points in Claude Code's lifecycle.

Automatisch. Das Modell entscheidet nicht, den Hook zu konsultieren, und kann nicht entscheiden, ihn zu überspringen; die Harness führt ihn aus, weil das Ereignis ausgelöst wurde. Das ist die Bindung, die der Datei fehlte, und sie kommt von außerhalb des Modells, nicht aus dem Inneren seiner Lektüre. Die Verweigerung, wenn der Hook sie einmal ausspricht, ist auch keine Stimme, die eine lautere überstimmen kann:

Exit 2 means a blocking error. On events that can block, exit 2
blocks whether or not you print JSON: even a JSON permissionDecision
of "allow" can't override it.

Eng gelesen regelt dieser Satz einen Vorrang innerhalb des Hooks, seinen Exit-Code gegen sein eigenes ausgegebenes Urteil, und der Exit-Code gewinnt. Eng genügt. Die Blockade ist das Ergebnis, keine Präferenz mit einer Zahl daran, und das, was sie erzeugt hat, lief, ob das Modell es wollte oder nicht. Dieselbe Regel wie die Zeile in der CLAUDE.md, aber eine andere Art von Objekt: Die eine wird von dem gelesen und abgewogen, das dann handelt, die andere läuft neben diesem und hat bereits entschieden.

Nicht jede Regel will ein Gate sein

Nichts davon ist ein Argument dafür, alles hinter ein Gate zu stellen. Die meisten Regeln sollten Sätze bleiben. Geschmack hat kein Gate: Nichts Mechanisches entscheidet, ob ein Name gut ist oder eine Abstraktion ihren Platz verdient, und obwohl die Liste der Hook-Typen in der Definition selbst einen LLM-Prompt enthält, du also ein Modell ins Gate hängen könntest, um zu urteilen, verlegt das nur das Abwägen nach drinnen und nennt es Durchsetzung. Die Regel, die es wert ist, befördert zu werden, ist die enge, gefunden durch eine einzige Frage: Welche deiner Anweisungen ist so, dass ein einziger stiller Verstoß ein Vorfall ist und keine raue Kante? Das sind die, die man verlegt. Der Rest ist Anleitung, und Anleitung gehört in Prosa, gelesen und abgewogen, und das ist das, worin Prosa gut ist.

Der Fehler, auf den ich achte, geht in die andere Richtung. Es ist eine tragende Regel, die in einer Datei sitzt und die ruhige Autorität einer Bedingung trägt, während sie sich wie ein Vorschlag verhält, und diese Autorität täuscht niemanden so sehr wie den, der sie geschrieben hat und sie als erledigt zurückliest.

Was ein Gate nicht erreicht

Selbst die Regeln, die du verlegst, halten weniger fest, als die Blockade aussehen lässt, denn ein Hook deckt nur den Pfad ab, auf den er gesetzt ist, und ein Pfad ist nicht jeder Pfad. Blockiere den Push am Shell-Tool, und ein Agent unter demselben Druck streitet nicht mit der Blockade; er erreicht main auf einem anderen Weg, einem anderen Tool, einem API-Aufruf, einem Skript, das den Push für ihn ausführt. Der Matcher, der den Weg auswählt, ist nach dem eigenen Eingeständnis der Dokumentation best-effort, also überwacht er sogar den Weg, den er überwacht, nur unvollständig. Eine Prüfung bindet nur über die Pfade, die sie abdeckt, und das ist der frühere Punkt noch einmal auf der Ebene der Aktion: Um eine Regel zu halten, musst du auf jeder Route zur Wirkung sitzen, und ab einem Punkt tut man das, indem man aufhört, Befehle zu inspizieren, und die Reichweite entzieht, sodass keine Route mehr zu bewachen bleibt.

Darunter liegt eine härtere Grenze. Manche Regeln lassen sich an keinem Kontrollpunkt auf keiner Route klären, weil der Verstoß nicht im Aufruf liegt, sondern in den Folgen, die der Aufruf nicht mit sich trägt. Eine Migration, die gültiges SQL ist und eine Spalte streicht, die ein nachgelagerter Job noch liest, passiert jede Prüfung am Gate. Eine Änderung an der Wiederholungslogik, die sauber parst und still den Backoff fallen lässt, passiert sie ebenfalls und zeigt den Schaden erst später, unter Last, in der Produktion. Nichts am Gate sieht das Falsche an beiden, weil das Falsche nicht in der Aktion geschrieben steht. Diese Regeln lassen sich gar nicht verlegen, und ein Satz in einer Datei, der vorgibt, sie zu halten, ist wieder der erste Fehler, in der Form, die keine Reparatur kennt. Was sie hält, ist ein Mensch, der die Änderung liest, und das ist der Grund, warum der frühere Schnitt zählt: Setze Gates sparsam, befördere nur die wenigen tragenden Regeln, und die Warteschlange, die ein Mensch tatsächlich lesen muss, bleibt kurz genug, um etwas zu bedeuten, statt zu der Reflex-Zustimmung zu verfallen, zu der ein Gate aus tausend Einträgen immer wird.

Zwei Verben, die der eine Satz verbirgt

Das ist nicht die Regel, die aus dem Takt gerät: das Problem, dass ein deklarierter und ein laufender Zustand auseinanderdriften, das Reconciliation zu schließen sucht; eine Regel kann perfekt abgeglichen sein, genau so laufen, wie sie geschrieben steht, und trotzdem nur beratend bleiben. Es ist nicht die Frage, zu welcher Schicht die Regel gehört oder wer sie schreiben darf; Adressierung klärt, wessen Wort eine Regel ist, und das Wort des Betreibers rangiert immer noch nur als Gewichtung über dem des Repositorys, bis etwas dahintersteht. Und es liegt vor den beiden Essays, die ausarbeiten, wie dieses Dahinterstehen aussieht: dass eine entscheidbare Naht dir erlaubt, eine ganze Klasse zu verweigern, während eine semantische dich zwingt, stattdessen die Fähigkeit selbst hinter ein Gate zu stellen, und dass eine unbeaufsichtigte Aktion auf der Reichweite beruht, die die Harness gewährt hat, nicht auf einer Vermutung darüber, was der Befehl tun wird. Die handeln von der Aktion. Dies handelt von der Datei, wo die Garantie als bereits vorhanden angenommen wird, weil der Satz im Imperativ geschrieben ist.

Der Satz und die Bedingung lesen sich gleich, eine Anweisung so wie so, und diese Ähnlichkeit ist es, die den ersten für die zweite einstehen lässt, bis etwas ihn prüft. Die Regel, die ich mir selbst jetzt setze, ist kleiner als die, die ich früher schrieb: Bevor ich ein tragendes „niemals" in eine Datei schreibe, frage ich, ob ich es nur genannt oder auch gedeckt habe, und wenn ich es nicht decken kann, sage ich das im selben Atemzug, statt den Imperativ so tun zu lassen, als ob. Die Regeln, die ich nie decken konnte, die, deren Schaden in der Welt lebt und nicht im Aufruf, erwiesen sich als genau die, von denen ich am meisten wollte, dass die Datei sie hält, und das konnte sie nie. Eine Datei ist ein Ort, um zu sagen, was wahr sein soll. Sie war nie der Ort, der es wahr macht.

Diskussion

Hier gibt es keine Kommentarspalte. Diskussionen laufen auf X.

Max Nardit

Max Nardit

@mnardit

Weitere Artikel

Deine Agent-Konfiguration ist jetzt Infrastruktur

Sobald du ein paar Agents betreibst, hören ihre Definitionen auf, Konfiguration zu sein, die du bearbeitest, und werden zu Infrastruktur. Das Problem mit Infrastruktur ist: Sobald du sie nicht mehr im Kopf behalten kannst, driften ihr deklarierter Zustand und ihr laufender Zustand von selbst auseinander, und nichts meldet es. Die Lösung ist die Disziplin, die wir bei Servern gelernt haben: Deklariere die Menge als Dateien, vergleiche sie mit der Realität, halte fest, was du angewandt hast, und verweigere das Anwenden über eine hinter deinem Rücken passierte Änderung hinweg, statt einfach darüber hinweg zu konvergieren. Mit einem Haken, der leicht zu übersehen ist. Ein Reconciler erfasst immer nur das, was du zu deklarieren daran gedacht hast.

Der Connector ist ein nicht vertrauenswürdiger Autor

Wer einen Span geschrieben hat, ist eine Tatsache, die der Harness schon hält. Ob dieser Span sicher zu befolgen ist, ist es nicht. Die Lösung ist also kein clevererer Leser: Es geht darum, dem Tool und dem Peer den Rang des fremden Dings zu geben, das sie sind, statt den Rang der Leitung, durch die sie ankamen.

Der Agent greift zum Werkzeug, das er lesen kann

Du optimierst ein Werkzeug danach, was es kann. Ein Agent wählt ein Werkzeug danach, ob er das Ergebnis vorhersagen und die Antwort lesen kann, wenn sie leer zurückkommt. Das sind verschiedene Eigenschaften, und der Abstand zwischen ihnen ist der Grund, warum gerade das mächtigere Werkzeug so oft unangetastet bleibt.