Die Intelligenz sitzt nicht mehr NEBEN dem Coden, sondern DRIN. Alles auf der Box gemessen, nicht angenommen. Stufe 1 — Speicher-Haushalt (llama-swap-Config, nicht im Repo): Coder dauerwarm statt ttl 600 (Kaltstart 23 s -> 491 ms), Devstral als 'kritiker' verdrahtet, Swap 11 GB -> 0. Zwei Befunde: Kontext 131k->65k spart bei Qwen3-Next 0 GB (Hybrid-Attention), und llama-swap haelt nur EINE Gruppe resident -> alles Ko-Residente in dieselbe Gruppe. `persistent: true` verhindert dabei das Freiraeumen vor grossen Modellen -> ausgeloester Kernel-OOM, behoben durch persistent:false + TTLs (Vision laedt jetzt in 10 s statt 117 s + Absturz). Stufe 2 — Governor v2 (deploy/governor/): Steht jetzt IM Pfad (:8100 -> MC2 :9001) statt daneben. Zaehlt den GANZEN Anfragekoerper inkl. tools/tool_calls und kalibriert sich aus den echten usage.prompt_tokens jeder Antwort nach: Schaetzfehler 200 % -> 0,3 %. Soft-Einschub nur noch, wenn die Nachrichtenkette es erlaubt (kein Dazwischen- funken in offene tool_calls). Neuer Status-Endpunkt + systemd-Unit. Lucys Alltagsmodelle sind vom Schnitt ausgenommen. Stufe 3 — OpenCode-Plugin (deploy/opencode/plugin/mc2-governor.ts): Werkzeug-Zaun (git push, rm -rf, sudo, curl|sh — bewiesen), Pruef-Tor auf session.idle mit Selbstreparatur, Savepoint statt Kompression, Meldungen an Lucys Briefkasten mit eigenem Absender 'loop'. Stufe 4 — Mannschaft (opencode.json): plan+build -> coder (51,5 t/s) · explore -> hermes (69,6 t/s, warm, gratis) · review -> Devstral (15,0 t/s, FREMDE Modellfamilie gegen blinde Flecken). Der 63-GB-Planer faellt aus der Tagesrolle raus. Stufe 5 — ein Regelwerk, zwei Ausloeser: deploy/opencode-lauf.sh faehrt dieselbe Bau-Pruef-Schleife unbeaufsichtigt (die Schleife liegt hier UND im Plugin: bei `opencode run` endet der Prozess, bevor session.idle fertig ist — gemessen). Bricht ab, wenn der Governor fehlt. gitea-repo-create.sh saet jetzt VERIFY neben der CI-Ampel: jedes neue Repo wird mit Innen- UND Aussen-Pruefung geboren. Oberflaeche: Token-Waechter-Kachel im Cockpit (Fuellstand, Marken, Ehrlichkeits-Nachweis), /api/governor als gleichursprüngliches Fenster, Devstral im Modellkatalog, Rollen-Texte auf die neue Mannschaft aktualisiert. .gitattributes: deploy/**/*.py auf LF (deploy/*.py greift nur eine Ebene tief). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Governor — Phase 0
Dünner, zustandsloser Token-Wächter-Proxy zwischen einem Off-the-shelf-Coding-Agenten
(Aider) und dem lokalen Modell-Endpoint (llama-swap :8080). Er erzwingt
Session-Hygiene per hartem Schnitt statt Auto-Compaction: wenn die Anfrage (= ganze
Sitzungshistorie, die jede Runde mitkommt) eine Schwelle übersteigt, schiebt er eine
Anweisung ein, SAVEPOINT.md zu finalisieren und zu stoppen — damit Wissen in
SAVEPOINT.md + git lebt, nicht im degradierenden Chat-Kontext.
Das ist Phase 0 des Ablöse-Plans „Lucy IDE-Modus + Governor": den Kern beweisen, ohne eine Zeile Lucy-Code. Kein bespoke Editor, kein Aider-Fork, kein Modelltausch.
Bausteine (dieses Verzeichnis)
| Datei | Zweck |
|---|---|
governor.py |
Der Proxy. Nur Standardbibliothek (läuft mit System-python3), zustandslos. |
CONVENTIONS.md |
Aiders schreibgeschützte Arbeitsregeln: SAVEPOINT.md zuerst lesen, laufend pflegen, keine Fassade. |
SAVEPOINT.template.md |
Anfangs-Savepoint für ein frisches Projekt. |
driver.py |
Treibt eine akkumulierende Aider-Sitzung über die Scripting-API (eine Zeile = eine Runde). |
gov-ctl.sh |
Governor sauber starten/stoppen/status (detached via setsid). |
run-driver.sh |
run-driver.sh <msgs> [repo] — Aider-Sitzung durch den Governor. |
reset-repo.sh |
Wegwerf-Test-Repo frisch aufsetzen. |
hardstop-test.sh |
Direkte curls für die drei Pfade (passthrough / soft / hart). |
msgs-*.txt |
Nachrichtenskripte für die Testläufe. |
Verhalten des Governors
Pro /v1/chat/completions-Anfrage schätzt er die Tokenzahl (Zeichen / GOV_CHARS_PER_TOKEN,
kalibriert auf CPT 3.5 → est ≈ echte prompt_tokens auf ~1–3 % bei echten Sessions):
- est < Soft → unverändert durchreichen.
- est ≥ Soft (
GOV_THRESHOLD, Default 25000) → hängt die SAVEPOINT-Stopp-Anweisung als letzte User-Nachricht an, leitet weiter, loggtFIRED. Das Modell schreibt EINEN ehrlichen Abschluss-Savepoint. - est ≥ Hart (
GOV_HARD_CEILING, Default 0 = aus) → der Governor antwortet SELBST mit einer kurzen Stopp-Nachricht, ohne das Modell zu fragen; loggtHARDSTOP. Verhindert, dass über die Grenze hinaus weitergearbeitet wird (siehe Befund unten).
Alle anderen Pfade (/v1/models etc.) werden roh durchgereicht. Streaming (SSE) wird
byteweise durchgereicht; die echten prompt_tokens aus der Antwort werden zur Kalibrierung
mitgeloggt.
Sprach-Signal an Lucy (Phase 2)
Beim Feuern (soft ODER hart) POSTet der Governor — best-effort, gedrosselt (Default 300 s,
damit die Pro-Runde-Feuerung nicht spammt) — eine Meldung an Lucys vorhandene Announce-Pipeline
(POST :9001/api/voice/announce, source:governor, priority:normal). Lucy pollt diese Queue
ohnehin, dedupliziert per Cursor und spricht sie über ihr lokales TTS — gated durch ihren
„Box-Meldungen laut"-Schalter. Kein Lucy-Code nötig. Abschalten: GOV_ANNOUNCE_URL="".
Umgebungsvariablen
GOV_PORT (8100) · GOV_HOST (0.0.0.0) · GOV_UPSTREAM (http://127.0.0.1:8080) ·
GOV_THRESHOLD (25000) · GOV_HARD_CEILING (Default Soft+5000; 0=aus) · GOV_CHARS_PER_TOKEN (3.5) ·
GOV_LOG · GOV_DIRECTIVE · GOV_HARDSTOP_MSG · GOV_ANNOUNCE_URL (:9001/api/voice/announce; ""=aus) ·
GOV_ANNOUNCE_THROTTLE (300 s) · GOV_ANNOUNCE_TEXT.
Auf der Box laufen lassen (wie in P0 aufgesetzt)
# Aider (einmalig, unter isoliertem Python 3.12 — System-Python 3.14 bricht Aiders Pins):
pipx install uv && uv tool install --python 3.12 aider-chat
# Dateien liegen in ~/governor-p0/. Governor starten (Hart-Deckel default AN = Soft+5000):
~/governor-p0/gov-ctl.sh start 25000 # Soft 25k, Hart 30k (auto)
# ~/governor-p0/gov-ctl.sh start 25000 0 # Hart AUS (nur weicher Schnitt)
# Aider-Sitzung durch den Governor:
~/governor-p0/run-driver.sh ~/governor-p0/msgs-todo.txt
Aider zeigt mit OPENAI_API_BASE=http://127.0.0.1:8100/v1 und Modell
openai/Qwen3-Coder-Next auf den Governor.
Wichtig: Aiders eigene Zusammenfassung MUSS aus
Der Treiber setzt coder.summarizer.max_tokens auf ~1e9. Sonst fasst Aider die Historie
selbst zusammen (Auto-Compaction) und die Anfrage wächst nie bis zur Schwelle — der
Governor wäre ausgehebelt, und man bekäme genau die über-komprimierte Halluzination, die
der Plan verwirft. Der Governor soll die alleinige Sitzungsgrenze sein.
Ergebnisse & Befunde (24.07.2026)
Akzeptanz — alle vier Kriterien bewiesen (Box, Qwen3-Coder-Next)
- Governor zählt + feuert an der Schwelle — 12-Runden-Todo-Lauf (Soft 8000): Runden 1-6
ok, ab Runde 7FIRED(est 8546 / echt 8652). Hart-Deckel: Anfrage mit est 11429 ≥ 10000 →HARDSTOP, Governor antwortet selbst (kein Modell-Call). Alles im Log. - Aider pflegt SAVEPOINT.md — über den ganzen Aufbau hinweg strukturiert gehalten
(Ziel/Erledigt/Nächster Schritt/Stolpersteine/Dateien) gemäß
CONVENTIONS.md. - An der Grenze: ehrlicher Abschluss + Stopp — beim ersten Feuern (Runde 7) schrieb das Modell einen ehrlichen Savepoint (nur real Gebautes unter „Erledigt", Tests als nächster Schritt) und verweigerte neuen Code.
- Frische Sitzung macht sauber weiter — keine Fassade — neue Aider-Sitzung las den
Grenz-Savepoint, baute
test_todo.py(der exakte nächste Schritt), und alle 9 unittest- Tests laufen grün gegen die echte API. Kein Erfinden.
Kalibrierung
CHARS_PER_TOKEN = 3.5 → est traf die echten prompt_tokens bei realen Sessions auf ~1-3 %.
(Nur künstlicher, extrem repetitiver Fülltext bricht die Heuristik — irrelevant für echten Code.)
Der Coder läuft mit 128k Kontext (-c 131072), also keine Modell-Kappung bei 25k.
Wichtigster Befund: Soft reicht nicht allein → Hart-Deckel nachgerüstet
Der weiche Schnitt erzeugt genau EINEN ehrlichen Grenz-Savepoint — solange die Grenze
respektiert wird. Schickt man aber über die Grenze hinaus weiter Aufträge (wie im Stresstest),
verweigert das Modell zwar den Code, schreibt die Absichten aber fortschreitend als „erledigt"
in SAVEPOINT — genährt von Aiders irreführenden Commit-Nachrichten (die aus dem SAVEPOINT-
Absichtstext geschöpft werden). Ergebnis: eine Fassade (behauptete test_todo.py/README, die es
nicht gab). Deshalb der optionale Hart-Deckel (GOV_HARD_CEILING): oberhalb davon antwortet
der Governor selbst, das Modell kann keine degradierenden Savepoints mehr schreiben. Der Hart-
Deckel ist jetzt Default AN (GOV_HARD_CEILING unset → Soft+5000; explizit 0 schaltet ihn
aus): ein Finalisier-Zug Luft, dann harter Riegel — das schliesst die Fassaden-Lücke.
Weitere Befunde / Fallen
- Aiders eigene Zusammenfassung MUSS aus (
summarizer.max_tokenshoch) — sonst compactet Aider selbst und der Governor greift nie. Siehe oben. - Commit-Nachrichten überzeichnen in der Abschluss-Phase (aus SAVEPOINT-Absicht). Der Code
ist die Wahrheit; git-Nachrichten sind es hier nicht. Der Hart-Deckel (jetzt Default) begrenzt
das auf ~1 Zug; wer es ganz sauber will, startet Aider mit
--no-auto-commits(Commits von Hand). - Python 3.14 auf der Box bricht Aiders Pins (numpy 1.24.3) → Aider via
uvunter isoliertem Python 3.12 installiert. - Aider-Scripting-API (
coder.run) hängt in einer Datei-Hinzufügen-Reflexion (Edits landeten nicht). Für Einzel-Rundenaider --messagenutzen (sauberer, unterstützt). Derdriver.pytaugt für Mehr-Runden-Akkumulation (Governor-Test), nicht als Produktions-Treiber.
Bekannte Grenzen des Governors (aus adversarialer Review, für später)
- Chunked Request-Bodies ohne
Content-Lengthwerden verworfen (Aiders httpx sendet immerContent-Length→ schlummernd, aber ein Proxy-Hop mit Chunking bräche). - Tool-/Function-Calling: der Soft-Einschub als letzte
user-Nachricht kann die Nachrichten- reihenfolge stören, wenn Aider ein Tool-Calling-Edit-Format nutzt (Aiders diff/whole sind reiner Text → schlummernd).estimate_tokenszählttools/tool_callsnicht mit. https://-Upstream wird nicht unterstützt (nurhttp.client.HTTPConnection). Für den lokalen:8080-Endpoint irrelevant. Behoben aus derselben Review: inkrementelles Streaming (read1()stattread()— vorher puffernd), Config-Crash bei{ }inGOV_DIRECTIVE(sichere Substitution), Query-String umging die Erkennung, Socket-Leak im Fehlerpfad, doppelteDate/Server-Header.
Nächste Schritte (Phase 1+)
Terminal in Lucy einbetten (xterm.js + node-pty, MC2-Muster kopieren) → Voice-Hook auf das Governor-Signal → Feinschliff + Aider/Pi-Finalentscheid. Governor evtl. später in mc2-gateway. Kandidat für Phase 1-Härtung: Auto-Commit-Zügelung + Hart-Deckel als Default.