Forschung ·

Weniger Code für dieselbe Arbeit.

Coding-Agenten schreiben mehr als nötig: Sie schreiben neu, was das Projekt schon hat, und jeder Durchgang fügt ein wenig hinzu. Sens legt um jeden Durchgang von Claude Code einen Kreislauf, den das Modell nicht abschalten kann. Nach 30 verketteten Aufgaben war das Projekt bei denselben Funktionen 12 % kleiner, mit 18 % weniger Tokens.

12 %
weniger Code für dieselben 30 Funktionen
18 %
weniger Tokens über die ganze Sequenz
90/90
Aufgaben angenommen, mit und ohne Sens
0
Tests früherer Aufgaben kaputt, in keinem Arm

Claude Sonnet 5.5 bei mittlerem Aufwand · drei Sequenzen pro Arm · Kriterium vor der Messung festgelegt

Das Problem

Ein Agent, der an einem echten Projekt arbeitet, sieht nicht das ganze Projekt. Er sieht, wonach er sucht, und er sucht, was ihm einfällt. Liegt die benötigte Hilfsfunktion in einem anderen Modul unter anderem Namen, schreibt er sie neu. Lässt eine Aufgabe eine kurze und eine lange Lösung zu, schiebt ihn nichts zur kurzen.

Die übliche Antwort sind geschriebene Regeln: eine CLAUDE.md, ein Skill, der Systemprompt. Sie helfen, aber sie sind Ratschläge. Das Modell lädt sie vielleicht nicht, vergisst sie mitten im Durchgang oder hält sie für nicht zutreffend. Die Gewichte des Modells können wir nicht ändern, aber drei Dinge steuern: was das Modell sieht, was es tun darf und wann es fertig sein darf. Sens nutzt alle drei zugleich.

Der Kreislauf

Claude Code nimmt Hooks als Callbacks im eigenen Stream-Protokoll an. Sens beantwortet fünf davon in seinem Prozess, mit einer Invariante: Eine Änderung entsteht ungeprüft. Freigeben kann sie nur eine bestandene Prüfung oder ein Mensch.

  1. 01

    Du sendest eine Nachricht

    UserPromptSubmit

    Sens legt einen Prüfpunkt des Projekts an und gibt Claude bis zu acht Dinge, die es schon gibt und zur Anfrage passen, jeweils mit Signatur, Datei:Zeile und Zahl der Verwendungen.

  2. 02

    Vor jedem Schreiben

    PreToolUse · Write, Edit

    Sens baut die entstehende Datei im Speicher nach und wendet die Änderungsregeln an. Es kann das Schreiben verweigern, bevor es geschieht, mit dem Grund und dem wiederzuverwendenden Code.

  3. 03

    Vor jedem Befehl

    PreToolUse · Bash, PowerShell

    Sens schützt seine eigenen Pfade und die Konfiguration und behandelt git commit und git push als Ende eines Durchgangs: Nichts Ungeprüftes wird committet.

  4. 04

    Nach jedem Werkzeug

    PostToolUse

    Egal welches Werkzeug: Sens sucht die auf der Festplatte geänderten Dateien und wendet dieselben Regeln an.

  5. 05

    Am Ende des Durchgangs

    Stop · SubagentStop

    Sens prüft den ganzen Diff seit dem letzten freigegebenen Punkt: Änderungsregeln, verwaisten Code und, wenn sich Code geändert hat, den Prüfer. Bei blockierenden Befunden arbeitet Claude weiter; nach drei Runden wird der Durchgang für dich angehalten.

Nichts zu umgehen

Bevor wir etwas bauten, haben wir live geprüft, dass der Mechanismus einem Modell standhält, das ihn umgehen will: Ein mitten in der Sitzung geschriebenes disableAllHooks stoppt die Callbacks nicht, Subagenten laufen hindurch, und ein verweigertes git commit lässt das Repository, wie es war. Für jede Abkürzung gibt es etwas, das sie schließt:

AbkürzungWas sie schließt
Schreiben über das Terminal, Python oder einen anderen MCP-ServerDie Prüfung der Festplatte nach jedem Werkzeug und die Prüfung am Ende des Durchgangs
Subagenten und HintergrundaufgabenSie laufen durch dieselben Hooks; der Durchgang wird nicht freigegeben, solange sie laufen
Hooks abschalten oder die Konfiguration ändernDie Hooks leben im Prozess von Sens; Regel R7 blockiert diese Dateien und stellt sie wieder her
Einen eigenen Worktree öffnenWorktree-Werkzeuge werden verweigert, und R7 deckt git worktree ab
Die Arbeit für fertig erklärenÜber das Ende eines Durchgangs entscheidet die Prüfung, nicht das Modell
Einen neuen Durchgang beginnen, um zu entkommenDie Prüfung beginnt beim letzten freigegebenen Punkt: Offenes wird übernommen
Ungeprüfte Arbeit committenEin Commit gilt als Ende eines Durchgangs
Endlos weitermachenDrei Runden, dann wird der Durchgang angehalten

Die Grenze ist ausdrücklich: Der Kreislauf schließt die Fehler und Abkürzungen eines Modells, nicht die eines feindseligen Programms auf demselben Rechner.

Ergebnisse

Einzelne Aufgaben beginnen mit einem sauberen Projekt, und der Schaden eines Agenten, der nicht wiederverwendet, liegt nicht in einer Aufgabe, sondern in der Summe. Horizonte misst die Summe: eine TypeScript-Kommandozeile für Haushaltsausgaben mit anfangs 88 Zeilen und 30 Produktanfragen in fester Reihenfolge, jede auf der vorigen aufbauend. Acht Konzepte sind eingestreut, die mehrere Aufgaben brauchen, ohne es zu sagen: Datumsangaben, Monate und Wochen, Summen, Akzente, Beträge, CSV, Befehlsoptionen. Beim ersten Mal schreibt der Agent sie; danach wäre es richtig, das Geschriebene wiederzuverwenden.

Das Kriterium wurde vor der Messung schriftlich festgelegt: Sens macht das Projekt nur dann kleiner, wenn alle drei Sequenzen mit Sens unter allen drei ohne Sens enden. Ohne echten Unterschied passiert das zufällig einmal in zwanzig Fällen.

Projektgröße nach jeder Aufgabe

  • Ohne Sens
  • Referenz
  • Mit Sens
0200400600051015202530AufgabeOhne Sens · 496Referenz · 455Mit Sens · 436

Codezeilen im Projekt nach jeder der 30 Aufgaben. Dünne Linien sind die einzelnen Sequenzen, dicke ihr Median. Die gestrichelte Linie ist eine auf Wiederverwendung angelegte Referenzlösung, die ihre gemeinsamen Module früh anlegt.

Daten anzeigen
Nach AufgabeOhne SensReferenzMit Sens
0888888
1929393
2102113103
3113150109
4121161118
5145188137
6162202161
7178209177
8223234195
9232243206
10232243206
11258276231
12277282247
13296307265
14304309269
15316315271
16346345301
17354357309
18367369326
19370377330
20381390341
21398404357
22415413373
23426422384
24432422388
25452434401
26453436402
27476453418
28485455426
29487455427
30496455436

Größe bei Aufgabe 30, je Sequenz

400440480520560Referenz · 455Ohne SensOhne Sens: 496 Zeilen496Ohne Sens: 564 Zeilen564Ohne Sens: 484 Zeilen484Mit SensMit Sens: 436 Zeilen436Mit Sens: 456 Zeilen456Mit Sens: 424 Zeilen424

Alle drei Sequenzen mit Sens enden unter allen drei ohne Sens. Das Kriterium ist erfüllt: Median 436 Zeilen gegenüber 496, 12 % kleiner, mit einem 95-%-Intervall von −140 bis −28 Zeilen.

Verbrauchte Tokens, aufsummiert über die 30 Aufgaben

  • Ohne Sens
  • Mit Sens
0,0M2,5M5,0M7,5M10,0M12,5M051015202530AufgabeOhne Sens · 11,3MMit Sens · 9,3M

Mit einem kleineren Projekt, das bei jeder Aufgabe zu lesen ist, verbraucht Sens weniger: 27,7 Millionen Tokens über seine drei Sequenzen gegenüber 33,7 Millionen. Die Tokens enthalten Cache-Lesezugriffe und messen den Arbeitsumfang, nicht die genauen Kosten.

Daten anzeigen
Nach AufgabeOhne SensMit Sens
00,0M0,0M
10,3M0,3M
20,5M0,6M
30,9M0,8M
41,2M1,1M
51,6M1,3M
61,8M1,7M
72,0M1,9M
82,5M2,4M
93,4M2,7M
103,7M3,0M
114,4M3,4M
124,7M3,6M
135,2M4,0M
145,4M4,2M
155,9M4,5M
166,2M5,1M
176,6M5,3M
186,9M5,7M
197,1M6,1M
207,5M6,4M
218,1M6,7M
228,5M7,1M
238,8M7,4M
249,0M7,7M
259,4M7,9M
269,8M8,2M
2710,2M8,5M
2810,7M8,8M
2911,0M9,1M
3011,3M9,3M

Woher der Unterschied kommt

Nicht davon, weniger zu kopieren. Keiner der beiden Arme kopierte ernsthaft Blöcke: jscpd fand ohne Sens 0, 6 und 6 doppelte Zeilen und mit Sens keine, und die Sonden für jedes eingestreute Konzept zeigen in beiden gleiche oder fast gleiche Werte. Der Unterschied kommt davon, für dasselbe weniger zu schreiben. Mit Sens schreibt der Agent mehr und kürzere Funktionen: im Median 28 statt 20. Im Pilotlauf schrieb der Agent ohne Sens für Beschreibungen in Anführungszeichen einen ganzen CSV-Leser mit 99 Zeilen; mit Sens erkannte er, dass die Beschreibung das letzte Feld ist, und kam mit zwei einzeiligen Funktionen aus.

Tokens insgesamt: 33,7M ohne Sens · 27,7M mit Sens

Einzelne Aufgaben

Zwölf Aufgaben in drei Sprachen an zwei echten Projekten, Sens selbst in TypeScript und Rust sowie die Python-Bibliothek click bei festen Commits, jede mit versteckten Tests und einer Referenzlösung geprüft. Drei Bedingungen mit demselben Modell: Claude Code allein (C0), der Kanon als Text im Systemprompt ohne Kreislauf (C1) und Sens vollständig (C2).

MessgrößeC0 · alleinC1 · Kanon als TextC2 · Sens
Gültige Läufe32/3631/3667/72
Läufe mit neuen Tests23/3636/3672/72
Nutzt plain, fern der Änderung0/33/36/6
Nutzt titleOf, fern der Änderung1/31/36/6
Löst py-progress-final0/30/33/6

Der Text allein erreicht schon viel Wiederverwendung, wenn die Hilfsfunktion nahe liegt. Nicht erreicht er die Fälle, in denen sie weit weg liegt und anders heißt, titleOf, 1 von 3 gegenüber 6 von 6, und auch nicht die Aufgabe, die eine gemeinsame Ursache statt eines einzelnen Pfads zu beheben verlangt, py-progress-final, 0 von 3 gegenüber 3 von 6. Bei einzelnen Aufgaben sind Codezeilen Rauschen: C2 schreibt etwa zwei Zeilen weniger pro Aufgabe, aber das Intervall berührt die Null. Wegen dieser Schwankung gibt es Horizonte.

Läufe, die mindestens eine Testzeile hinzufügten

Kanon 1.0 · Pilot und schwere Aufgaben

Ohne Sens (C0)14/18
Der Kanon als Text (C1)9/18
Sens (C2)2/18

Kanon 1.1 · Kalibrierung

Ohne Sens (C0)23/36
Der Kanon als Text (C1)36/36
Sens (C2)36/36

Mit Kanon 1.0 schrieb der Agent fast keine Tests mehr: Er las „tu, worum gebeten wird, und nicht mehr“ als Verbot und hielt die Freigabe von Sens für einen Testlauf. Kanon 1.1 sagt beides, was fehlte: Ein Test, der die Änderung beweist, gehört zur Änderung, und die Freigabe von Sens ist kein Testlauf. Claude Code allein bekommt den Kanon nicht; seine Balken sind die Basis jedes Durchlaufs.

Die Regeln

Die Änderungsregeln sind deterministisch. Sie vergleichen Fingerabdrücke jeder Funktion, Methode und Klasse und jeder Folge von vier Anweisungen, erstellt von einem Rust-Index auf tree-sitter, der das Projekt im Speicher hält: Das Repository von Sens selbst, 556 Dateien und 10.000 Einheiten, ist in unter zwei Sekunden indiziert, und die Suche nach Kopien einer Einheit dauert etwa eine Mikrosekunde. Exakte Kopien und solche mit umbenannten Namen werden per Hash erkannt, Kopien mit hinzugefügten oder entfernten Zeilen per MinHash über normalisierte Tokens. Die Schwelle von 0,80 und die Untergrenze von 80 Tokens fürs Blockieren stammen aus der Bearbeitung von 400 Funktionen eines echten Repositorys und der Prüfung jedes Treffers von Hand.

RegelErkenntAntwort
R1 WiederverwendenEine neue Funktion, Methode oder Klasse mit demselben Fingerabdruck vom Typ 1 oder 2 wie eine vorhandeneBlockiert ab 80 Tokens; darunter soll Claude noch einmal nachdenken
R2 Beinahe-KopieÄhnlichkeit vom Typ 3 über der Schwelle oder eine kleine Funktion, die einer anderen in Form und Wortschatz gleichtWie R1; in Tests ein Hinweis
R3 Neue AbhängigkeitEin Manifest bekommt eine Abhängigkeit, in zehn FormatenFragt dich
R4 VerwaisteEin neues Symbol, das nichts erreicht, oder ein vorhandenes, das der Durchgang ungenutzt ließBlockiert, wenn intern; Hinweis, wenn exportiert
R6 ProjektregelnRegeln, die du festlegst; die erste: keine KommentareBlockiert
R7 IntegritätSchreiben in .sens/, .git/, .claude/settings*.json oder .mcp.json oder git worktreeBlockiert immer; wiederhergestellt, wenn es über das Terminal kam
R8 Geschützte TestsDer Durchgang entfernt Tests oder Assertions, die Sens schon freigegeben hatteFragt dich

Regeln sehen keine Urteilsfehler. Dafür liest ein Prüfer, wenn ein Durchgang mit Codeänderungen die Regeln besteht, den Diff zusammen mit den Kandidaten des Index. Seiner Ausgabe wird nicht blind vertraut: Jeder Befund, dessen Zitat nicht wörtlich im Diff steht, wird verworfen, und nur hohe Sicherheit blockiert.

HinweisErkennt
S1Eine Abstraktion ohne zweite Verwendung
S2Eine Korrektur am Symptom statt an der Ursache
S3Nachbauen, was die Plattform oder eine Abhängigkeit bietet
S4Spekulation: Optionen oder Zweige, um die niemand gebeten hat
S5Raffiniert, wo das Offensichtliche gereicht hätte
S6Ein gefährlicher Schnitt: Validierung, Fehlerbehandlung oder Sicherheit entfernt
S7Nachbauen, was das Projekt schon hat, mit Verweis auf einen Kandidaten

Was nicht funktioniert hat

Jede Blockade des Kreislaufs wurde von Hand geprüft, mit Diff und Gespräch. Blockaden sind selten, sieben in 228 Läufen von Sens, daher wiegt eine einzige unberechtigte schwer. Unser Ziel waren unter 5 % unberechtigte Blockaden; in keinem Durchlauf mit Blockaden haben wir es erreicht. Jede unberechtigte hatte eine konkrete Ursache, die jetzt mit einem Test behoben ist, der sie festhält.

DurchlaufBlockadenUnberechtigtUrsacheBehebung
Schwere Aufgaben, C2 v310, 1 strittigDer Prüfer meldete eine Redewendung, die das Projekt wiederholtEin S7 zu etwas Privatem ist nur ein Hinweis
Kalibrierung, C222R8 verglich mit der Datei vor jedem SchreibenR8 vergleicht mit dem zuletzt freigegebenen Stand
Kalibrierung, C2 nach der Behebung00——
Horizonte, Pilot10——
Horizonte, Bestätigung31R8 hielt eine Hilfsfunktion in einer Testdatei für einen TestAls Test zählt nur, was etwas prüft

Eine falsche Liste ist schlimmer als keine. Die erste Version von Sens schlug acht Symbole ohne Bezug zur Anfrage vor; das Modell las sie, suchte nicht weiter und schrieb die Akzent-Hilfsfunktion dreimal von Hand neu, während der Kanon als Text ohne Liste sie dreimal importierte. Mit der neu gebauten Suche erscheint die Funktion unter den Vorschlägen, und Sens nutzt sie jedes Mal, ohne etwas zu blockieren.

Grenzen

  • Ein Modell. Alle Läufe nutzten Claude Sonnet 5.5 bei mittlerem Aufwand.
  • Ein Projekt, eine Sprache, drei Sequenzen pro Arm. Das Bestätigungskriterium ist streng, alle unter allen, aber die Größe des Effekts hat ein breites Intervall.
  • Wir haben die Aufgaben geschrieben. Damit sie das Ergebnis nicht verzerren, wurden Aufgaben, Tests und Referenz vor dem ersten Lauf committet und das Kriterium vor der Messung festgelegt.
  • Keine MCP-Werkzeuge im Benchmark. Sens wurde ohne die Index-Abfragen gemessen, die die App bietet; das Ergebnis ist eine Untergrenze.
  • Neunzehn Sprachen noch nicht im Benchmark. Vue, Svelte und die später hinzugekommenen Sprachen sind durch Tests abgedeckt, nicht durch Agentenläufe.
  • Tokens enthalten Cache-Lesezugriffe. Sie messen den Arbeitsumfang, nicht die genauen Kosten.
  • Der Prüfer ist ungenau. Von den sieben eigenen Hinweisen und Blockaden, die wir geprüft haben, waren fünf falsch. Seine Hinweise stoppen nichts, erreichen aber das Modell und dich.
  • Ungeschriebene Konventionen. Sens kennt die impliziten Regeln eines Projekts nicht, etwa schwere Importe innerhalb einer Funktion zu lassen.

Methode

456 Agentenläufe in fünf Durchläufen: ein Pilot, drei schwere Aufgaben an Sens selbst, zwölf Kalibrierungsaufgaben sowie Pilot und Bestätigung von Horizonte. Alle Bedingungen nutzten claude-sonnet-5-5 bei mittlerem Aufwand, mit Claude Code im --safe-mode, damit die eigene Konfiguration des Autors nicht in die Läufe gelangt. Jede Aufgabe wurde vor der Nutzung geprüft: Zu Beginn bestehen die Projekttests und die versteckten schlagen fehl, mit der Referenz bestehen beide. Eine Regression muss zweimal hintereinander fehlschlagen, um zu zählen. Unterschiede sind Mediane mit einem 95-%-Bootstrap-Intervall, 10.000 Stichproben mit festem Seed; das Kriterium von Horizonte ist ein exakter Permutationstest.

Selbst nachmessen

sens-bench validate --tasks bench/tasks
sens-bench run --tasks bench/tasks --condition C0,C1,C2 --reps 3 --out bench/results/<batch>
sens-bench sequence validate bench/sequences/cuentas
sens-bench sequence run bench/sequences/cuentas --condition C0,C2 --reps 3 --out bench/results/<batch>
sens-bench sequence report bench/results/<batch>

Die Daten jedes Laufs, sein Diff und die Aufgaben liegen im Ordner bench/ des Sens-Repositorys.

Der Kanon

Der Text, den jede Sitzung erhält, Wort für Wort, auf Englisch, wie das Modell ihn liest. Erst der Kreislauf macht ihn zu mehr als einem Ratschlag.

# Sens Canon v1.1

You are working inside Sens. Sens indexes this project and judges every change you make before your turn can end. What Sens tells you about this project, in its messages, denials and reviews, is a fact about the code, not a suggestion. When Sens names something to reuse, reuse it.

## Before you write

Go down this ladder and stop at the first step that answers the need:

1. Is it needed? Do what the person asked and nothing more: no speculative options, parameters, flags or branches. A test that proves the change is part of the change, not something extra.
2. Does the project already have it? Reuse the existing function, component, type or constant. Ask Sens with `already_exists` or `find_symbol` when unsure.
3. Does the standard library or the platform give it? Use that.
4. Does an installed dependency give it? Use that. A new dependency needs the person's approval, and Sens asks them for it.
5. Only then write new code: the smallest version that is correct.

## While you write

- Fix the cause in the shared code, not the symptom in each caller.
- No abstraction without a second real use: no interface, factory, wrapper, layer or configuration for a single consumer.
- Boring over clever. Match the names, patterns and style of the code around you.
- If you would copy a block, extract it once and call it from both places.
- Delete what your change leaves unused.

## Never cut

Less code never means removing validation at trust boundaries, error handling that prevents data loss, security checks, accessibility, or anything the person asked for.

It never means skipping tests either. When your change alters behaviour and the project has tests, add or extend one that fails without your change, in the style of the tests around it, and run the tests you touched before you finish.

## Working with Sens

- A denied write comes with the reason and what to use instead. Change the approach. Retrying the same thing through the shell, another tool or a subagent does not help: Sens judges what lands on disk, however it got there.
- When you finish, Sens audits the whole turn. If it blocks, fix what it found and finish again.
- Sens judges the shape of the code, not whether it works. Its approval is not a test run: that part is yours.
- Never edit `.sens/`, `.claude/settings*.json` or `.mcp.json`.