Imported from ysamjo/CLIScade (
AGENTS.md). Install upstream withnpx skills add ysamjo/CLIScade. Copyright stays with the author.
CLIscade
Browser-Oberfläche und Orchestrator, die mehrere KI-Coding-Harnesses (claude, codex, opencode, cline, codebuddy, qodercli, antigravity, cursor, grok, kiro) parallel über die Projektordner eines Workspace dispatcht — inklusive Telegram-Relay.
Projekt-Kontext
| Modul | Pfad | Beschreibung |
|---|---|---|
| Services | services/ |
Dispatch, transaktionaler TaskStore, ContextService, LAN-Zugang und optionaler Beads-Adapter |
| Server | server.js |
Express 5 + ws: /api/*, Run-Pool, Dispatch-Queue, Scheduler, Telegram, Einstellungen, Task-Historie |
| Entscheidung | routing.js |
Reine Logik ohne IO: dispatchSlotDecision, knownBrokenBlocker, armIdleWatchdog, startupRefusal, gatewayEnvFromShell |
| Runtime | runtime/ |
Feste Harness-Registry, gemeinsamer Process Runner, runHarness(), Ereignisse, Fehlerklassen, Sessions und CLI-Adapter |
| Oberfläche | public/ |
Vanilla JS ohne Bundler: app.js (Zustand + Rendering), konsole-schichten.js (Leseschichten der Konsole, reiner Text ohne DOM), index.html, style.css, icons.js, sw.js |
| Tests | test/ |
ui-smoke.mjs (jsdom), runtime/*.test.js (Adapter, Runner, Sessions, Kind-Umgebung, Sicherheit), routing.test.js (Entscheidungen), dispatch_chain.test.js (echte Kind-Prozesse gegen Stub-CLIs), sw.test.js, konsole_queue.test.js, konsole_schichten.test.js |
Laufzeitumgebung: Node-Prozess auf Port 3000, bindet 0.0.0.0 (im LAN sichtbar).
Zustand liegt außerhalb des Repos unter ~/.harness-dispatch/ — config.yaml
(Prioritätskette, Modelle, Kappe), studio.sqlite (Aufträge, Request-IDs, Versuche und Ereignisse inkl. archived; einmalige Migration von studio-tasks.json),
AGENTS.md (globaler Richtlinientext), studio.log.
Konventionen
- Entscheidungen gehören nach
routing.js,server.jsverdrahtet nur. Ein Gate, das sich nicht ohne Kind-Prozess testen lässt, ist an der falschen Stelle. - CLI-Wissen gehört nach
runtime/.server.jsdarf keine harness-spezifischen Argumentlisten, Ausgabeparser oder Resume-Regeln enthalten. Jeder Lauf geht ausschließlich überrunHarness(). Konfiguration speichertharnessId, nie ein frei gewähltes Executable. - Test zuerst schreiben und scheitern lassen.
ui-smoke.mjszähltpruefe()-Behauptungen und am Ende aus; die Ketten-Tests fahren einen echten Server in eigenemHOMEmit Stub-CLIs. public/wirkt nach einem Browser-Reload,server.jsundrouting.jserst nach einem Prozess-Neustart — kein Build-Schritt, keine Bundler-Dateien anlegen.- Deutsch für UI-Texte, Kommentare, Meldungen und Commit-Messages; englische Code-Bezeichner.
- Erscheinung: kurze Zeilen, Gruppen, Zähler statt Erklärtext, kein Anbieter-Jargon. UI-Varianten bauen und screenshoten statt sie zu beschreiben.
- Ein Lauf endet in
done,errorodercancelled— nie alsdonemit Fehlercode.cancelledist ein eigener Meldungstyp (Exit-Code 130), damit die Oberfläche ihn nicht grün malt und der Baum ihn nicht als Erfolg führt; ein Abbruch wird zweistufig gemeldet (abbruch_laeuftquittiert,cancelledschließt ab). Wer einen terminalen Zustand auswertet — Queue, Wartezelle, Feldwahl, Test-Helfer —, muss alle drei kennen. - Browser-Prüfungen über Ego Lite (
ego-browser), siehe globaleDeveloper/AGENTS.md§2.
Commands
npm start # Server auf http://localhost:3000, hängt an dieser Shell
HOST=127.0.0.1 npm start # nur lokal erreichbar, nicht im LAN
python3 tools/start-detached.py # Dauerbetrieb: setsid + gesäuberte Umgebung
node test/ui-smoke.mjs # Oberfläche im jsdom (Struktur + Verhalten)
node test/konsole_schichten.test.js
# 40 Behauptungen: Schichten aus echten Protokollen
npm run test:routing # Node-Tests inklusive runtime/ und Dispatch-Ketten
npm test # Gesamtsuite inklusive UI-Smoke
# Wegwerf-Instanz für Browser-Prüfungen — NIE die Instanz auf 3000 anfassen:
mkdir -p /tmp/hrg/bin && printf '#!/bin/sh\necho stub\n' > /tmp/hrg/bin/stub-run && chmod +x /tmp/hrg/bin/*
HOME=/tmp/hrg PATH=/tmp/hrg/bin:/usr/bin:/bin PORT=3921 node server.js
Grenzen & Sicherheitsregeln
- Port 3000 gehört dem Nutzer. Dort läuft sein Server. Vor jedem Neustart zählen:
pgrep -P $(lsof -nP -iTCP:3000 -sTCP:LISTEN -t)— ein laufender Agent-Task wird sonst mitgetötet. - Dauerbetrieb nur über
tools/start-detached.py, nie aus der Agent-Shell. Aus einer WorkBuddy-Session geerbt kommtNODE_OPTIONS=--require=…/node-language-shim.cjsmit, dasnode-brokered-fs-shim.cjslädt und jedenfs-Aufruf über den Sandbox-Broker der App schickt. Endet der Agenten-Zug, wirft der nächste DateizugriffConnection refusedals unbehandelte Ausnahme — der Server stirbt mitten im Betrieb, auch beim Ausliefern einer statischen Datei. Im Log sieht das aus wieENOSPC: no space left on deviceoderBrokered file token refused. Ebenso zu entfernen:BASH_ENV,PYTHONPATH,CODEBUDDY_*,WORKBUDDY_*,SANDBOX_CENTER_*,SERVER__PORT/SERVER__HOSTund die Shim-Einträge inPATH(cli/vendor/shim). Der Launcher filtert das und warnt, wenn noch etwas durchkommt. - Zwei Ebenen gegen App-Gerüst in der Umgebung.
SERVER__PORTbenennt den Web-UI-Server der aufrufenden WorkBuddy-App. Erbt ihn ein Lauf, bindet der Harness denselben Port und stirbt vor dem ersten Token mitlisten EADDRINUSE: address already in use 127.0.0.1:54968. Deshalb filtert der Launcher den Start des Servers undruntime/harness-runtime.jsjeden Spawn (childEnv()), damit auch ein von Hand gestarteter Server sauber dispatcht. - Neustart nur ohne
QODER_*-Umgebung. Der Launcher erledigt das per Präfix; von Hand scrubben als Array (env "${scrub[@]}" node server.js) — eine per$(...)gebaute Zeichenkette zerlegt zsh nicht, der Server läuft dann trotzdem und vergiftet jedesqoderclimitsdk_invalid_args. Nachprüfen:ps eww -p <PID> | tr ' ' '\n' | grep -cE '^(QODER|CODEBUDDY|WORKBUDDY|NODE_OPTIONS)'muss0sein. - Service Worker:
public/sw.jsarbeitet network-first und hältcliscade-v<N>als Rückfall. Ändern sichindex.html,app.jsoderstyle.css, die Nummer hochziehen — sonst kann bei totem Server die alte Fassung erscheinen, und die Seite sieht heil aus, obwohl sie mit einem toten Backend spricht. - LAN-offen: jeder Spawn-Pfad bleibt über die feste
HARNESS_REGISTRYbeziehungsweise derenTESTABLE_COMMANDSauf eingetragene CLIs beschränkt. Modell-Tests laufen in einem Wegwerfverzeichnis (harness-modeltest-…unter/tmp), Dispatches arbeiten direkt im gewählten Projektordner — dort gibt es keine Isolation, der Auftrag schreibt im Original. - Secrets nie ausgeben oder übertragen: der
ANTHROPIC_API_KEY-Wert in~/.zshrc. Von der Gateway-Umbiegung dürfen nur Variablennamen geloggt werden. .workbuddy-ai/ist das Gedächtnis eines anderen Agenten — untracked lassen, nie committen.originist das öffentliche GitHub-Repo (github.com/ysamjo/CLIScade). Vor einem Push prüfen, was mitgeht (git status --short), und keine Schlüssel aus dem Laufzeitverzeichnis.- Das GUI dispatchet auch in dieses Repo: vor
git checkout/reset/Neustart prüfen, ob ein zweiter Agent gerade am Arbeitsbaum schreibt.
Architekturvertrag seit 11. Oktober 2026
-
Node.js mindestens 22.13 für
node:sqlite. Keine neue Datenbankbibliothek und kein Bundler. -
SQLite ist die Quelle für Aufträge; die alte JSON-Datei wird einmalig gesichert und importiert. Beschädigte Daten nicht als leere Historie behandeln. Request-ID-Deduplizierung gilt auch nach Neustart.
-
public/task-state.jsdefiniert Abschlussmeldungen für Server und UI:donenur fürcompleted,errorfürfailed/incomplete,cancelledfür Abbruch mit 130.abbruch_laeuftquittiert den Abbruch sofort. -
Jeder Start und jede Konsensphase verwendet den ContextService. Regeln und Bildhinweise bleiben bei Fallback erhalten; Agentenaussagen sind unbestätigter Arbeitsstand. Keine automatische Änderung von AGENTS-Regeln.
-
LAN-Zugang ist angemeldet, lokaler Zugriff mit gültigem Host/Origin bleibt möglich.
lan-access-codeniemals ausgeben oder committen. API-Antworten nicht cachen. Keine lokale Identität aus Forwarded-Headern ableiten. -
Codex-Sandbox ist standardmäßig
workspace-write; nurexecution.codexUnsafe === trueerlaubt den bestehenden Bypass. Die anderen Adapter behalten ihre bestehenden Berechtigungen. -
Beads ist optional: vor jedem Auftrag automatisch Workflow (
bd prime --full --no-memories --readonly), Projektwissen (bd memories --json --readonly) und Aufgaben (bd ready --json --readonly) laden. Aufgabenwahl ergänzt Details; Fortsetzung liest frisch. Pro Projekt serialisieren und lokale Daten pinnen. Ladefehler sichtbar stoppen; nur ausdrücklicheswithoutBeadsüberspringt Lesen und Speichern. -
Autorisierte Wissensextraktion: strukturierter Abschlussblock
project-memory, stabile Schlüssel, Quellen und Git-Revision; Agentenaussagen bleiben unbestätigt. Erkennbare Geheimnisse verwerfen. Keine automatische AGENTS-Änderung, fachliche Übernahme, Erstellung oder Schließung. Projekt-Lock und Abschluss erst nach Wissensspeicherung freigeben. -
Prüfbelege ausschließlich aus gepaarten Werkzeugereignissen mit Exit-Code; Befehl, Zeit, Ergebnis und Git-Stand speichern. Ein erfolgreicher Lauf und behauptete Tests sind keine fachliche Abnahme.
-
Kontextbudget 64.000 Zeichen: Regeln, Auftrag und Bild erhalten; optionale Abschnitte nur vollständig übernehmen. Relevante Erinnerungen höchstens zwölf / 12.000 Zeichen, fehlende Inhalte sichtbar kennzeichnen.
-
Beads-Backups: täglicher nativer Stand plus Änderungen, Prüfung alle 30 Minuten, sieben lokale Archive außerhalb Git. Wiederherstellung im Wegwerfprojekt und Vergleich aller Aufgaben/Erinnerungen vor Erfolg. Nur lokale Sicherungen; keine automatische NAS-Übertragung.
node tools/backup-beads.js --all /Users/family/Developerprüft einmalig alle Projekte; keinen laufenden zweiten Backup-Prozess starten. -
Skills-Inventar bleibt lesend; nur ausdrückliche Synchronisierung/Installation erzeugt Links.
-
Vor einem Restart aktive Prozesse und
/api/runsprüfen. Unterbrochene Aufgaben benötigen ausdrückliche Fortsetzung; niemals automatisch erneut dispatchen. -
Bild-Einsetzen:
public/image-composer.jsverwaltet je Konsole ein Bild (PNG/JPEG/GIF/WebP, 10 MB). Upload ausschließlich beim Senden über den angemeldetenPOST /api/images; Ablage unter~/.harness-dispatch/uploads, anschließend bestehender Attachment-Pfad. Fehler erhalten den Entwurf. Mac-App:mac-app/,npm run build:mac/npm run install:mac; native Zwischenablage-TIFFs werden bei ⌘V nach PNG gewandelt..beadsnie ins Bundle aufnehmen. -
Das App-Bündel ist eine eingefrorene Kopie.
mac-app/build.shlegtserver.jsundpublic/perrsyncnachContents/Resources/app, undServerManager.findProjectRoot()liest ausschließlich von dort (erst nachCLISCADE_DIR, dann Bündel). Eine Änderung anpublic/wirkt in der installierten App nur nachnpm run install:mac— Reload, Cache-Nummer oder Neustart der App ändern nichts.build/ist in.gitignore, zieht also nie von selbst nach. Wer „altes Design" gemeldet bekommt, prüft zuerstgrep -oE 'style.css\?v=[0-9]+' /Applications/CLIScade.app/Contents/Resources/app/public/index.htmlgegenpublic/index.html. Installation mitrsync -a --deletestattrm -rf— das Sicherheitsgate der Agentensitzung blockiert ein rekursives Löschen in/Applications. Der WebView hält dauerhaften Zustand unter~/Library/WebKit/de.cliscade.gui(Service-Worker-Registrierung, HTTP-Cache,CacheStorage/cacheslist). Er heilt sich selbst, sobald der Server ein geändertessw.jsausliefert: der neue Worker aktiviert sich,cacheslistspringt auf die neue Nummer. Caches müssen nicht von Hand geleert werden — der Nachweis iststrings ~/Library/WebKit/de.cliscade.gui/WebsiteData/Default/*/*/CacheStorage/cacheslist | grep -oE 'cliscade-v[0-9]+'gegenpublic/sw.js. -
Nutzerkonfiguration:
runtime/user-environment.jsliest ausschließlich freigegebene Provider-/Nutzer-Variablen der Login-Shell, filtert Shim-Pfade und erhält Startumgebungs-Vorrang.POST /api/user-environment/reloadaktualisiert nur zukünftige Läufe und gibt keine Werte aus. Bei Fehler bleibt die letzte erfolgreiche Konfiguration erhalten. -
Portable Laufzeit: Launcher erkennt Node >=22.13 über PATH/nvm oder
HARNESS_NODE; Mac-App erkennt Python über Nutzer-PATH/Standardpfade oderCLISCADE_PYTHON. Keine persönlichen Entwicklerpfade voraussetzen. -
POST /api/context/previewbleibt lesend und verwendetbuildContextwie die Ausführung; Workspace-Grenzen, Beads-Ausnahme, Quellen und Budget gelten auch für die Vorschau. Mobile Dateiauswahl verwendet denselben Bildpfad wie Paste.
Weitere Harnesses seit 11. Oktober 2026
- Registry enthält 13 Harnesses: bestehende acht plus
junie,kilo,copilot,kiro,vibe. Keine neuen Routen automatisch aktivieren. CLI-Argumente bleiben ausschließlich in den Adaptern. - Kiro verwendet
--trust-all-toolsund Kilo--autofür headless Werkzeug- und Bash-Ausführung (analog zu OpenCode); Junie, Copilot und Vibe nutzen keine pauschalen Flags. Junie vertraut Einmalauftragsprojekten nativ: Grenze in Registry, Installer und Laufwarnung anzeigen. - Vibe-Modellwahl über Kindprozess-
VIBE_ACTIVE_MODEL; kein--model. Junie Lite über native Modellauswahl, keinen unbelegten Alias vorgeben. Keine festen Freiquoten erfinden. - Kiro V3/stream-json: bestätigtes Headless-Envelope
sessionUpdate.dataundrunFinished.data(CLI 2.28.0). Junie bewusst Textmodus ohne belegtes JSON-Schema; neue strukturierte Adapter dürfen unbekannte/malformed Ausgabe nicht als Antwort werten. - Alle fünf derzeit
resumable: false: Fortsetzung über ContextService, keine globale/zuletzt aktive Hersteller-Session erraten. Echte Werkzeug-Exit-Codes werden strukturiert erfasst (z. B. aus Kiro ACPrawOutput.exitCodeoder Kilometadata.exit); fehlende Werkzeug-Exit-Codes bleibennull. - Zusätzliche Prüfungen:
node --test test/runtime/new-clis.test.js test/new_clis_server.test.js; letzterer startet isolierten Server auf freiem Port und ausschließlich Stub-CLIs. Echte Modelltests verbrauchen ggf. Kontingent.
Headless-Autonomie seit 12. Oktober 2026
-
runtime/headless-prompt.jsergänzt die fachliche Standardinstruktion zentral inrunHarness()unmittelbar voradapter.build(), auch bei Resume und Fallback. Originalkontext nicht verändern; feste Instruktion zusätzlich zum ContextService-Budget. Keine harness-spezifischen Promptkopien. -
Keine fachlichen Rückfragen/Menüs: sinnvolle Entscheidung treffen, wesentliche Annahmen begründen, implementieren und testen. Explizite Nutzer-/Projekt-/AGENTS.md-Regeln haben Vorrang; vorgeschriebene Bestätigungen niemals erfinden.
-
Autonomie erteilt keine Rechte. Adapterflags, gespeicherte Policies und ausdrückliche Einstellungen erhalten; keine neuen Trust-/Freigabeflags, Tool-Erweiterungen oder Sandbox-Umgehung. STDIN geschlossen halten, keine automatischen Menüantworten und kein Interaktionsprotokoll ergänzen.
-
Eindeutige Interaktionsverweigerung als
interactive_requiredmitnext_harnessklassifizieren, auch bei Exit 0. Sonst bestehende Fristen: 180 s ohne Ausgabe, 30 min insgesamt, 5 s SIGTERM-Gnadenfrist. Allgemeine Antworttexte nicht als Auswahlmenüs interpretieren; Abbruch behält Vorrang. -
Prüfungen:
node --test test/runtime/headless-prompt.test.js test/runtime/harness-runtime.test.js test/runtime/errors.test.js test/runtime/process-runner.test.js test/new_clis_server.test.js, danachnpm test. Stub-Belege nicht als Live-Modellabnahme ausgeben. -
Konsolen-Composer: mehrzeilige Eingabe über volle Breite, darunter Ziel/Routing und Icon-Aktionen für Bild und Kontext. Icon-Buttons behalten
aria-label, Tooltip und sichtbaren Tastaturfokus; Bild-/Kontextpfade bleiben unverändert. -
Seitenleisten-Zustand liegt in localStorage (
hrg_collapsed_projects,hrg_show_taskless_folders); defekte Speicherwerte dürfen den Start nicht verhindern. AGENTS-Marken öffnen ausschließlich den Projekteditor. Archivaktionen nur bei feinem Hover-Zeiger ausblenden; Fokus und Touch bleiben bedienbar. -
Oberflächengestaltung: Farb- und Radiusvariablen in
public/style.csszentral halten. Konsolen und Composer bilden ruhige Karten; Desktop-/Mobil-Screenshots über Ego Lite prüfen.100dvhhält die Arbeitsfläche innerhalb der sichtbaren Browserhöhe. -
Beads-Bedienung ausschließlich im Einstellungsbereich
#settings-sec-memory(data-section="memory"): je Konsole eigene Referenzen über#memory-pane-<slot>, die Zustandszeile#memory-summarysteht im Kopf der Karte. Der Arbeitsbereich#dispatch-panelträgt keine Beads-Leiste — sie kostete dort eine Zeile und sagte im Regelfall nur, dass alles läuft. Fehler sind dadurch erst nach dem Öffnen der Einstellungen sichtbar; wer das ändert, baut das Zeichen bewusst in den Arbeitsbereich. Keine automatische Fehlerumgehung. Composer-Werkzeugleiste gruppiert Ziel/Routing und die Icon-Aktionen (Kopieren, Abbrechen, Bild, Kontext und Senden) separat; Senden darf nicht allein umbrechen. -
Sichtbarkeit der zweiten Konsole: initial
hidden, erstopenRunPane()oder bewusster neuer Task ruftrevealPane()auf. Ordnerauswahl im Kopf; Aufgabenunterzeile bleibt erhalten. Gedächtniszusammenfassung berücksichtigt nur sichtbare Felder. -
Konsolenschichten: strukturierte Denk-/Werkzeugereignisse tragen
data-console-layerauch in gespeicherten HTML-Ausgaben. Laufende Bereiche offen; bei nachfolgender Antwort oder Laufende einmalig automatisch schließen und frühere Faltwünsche löschen. Erneutes manuelles Öffnen danach bleibt erhalten. -
Archivaktionen im Aufgabenbaum verwenden
TaskState.terminal()für alle Abschlusszustände, einschließlichfailed,cancelledundincomplete; laufende und wartende Aufgaben bleiben ohne Archiv-Button. -
Sichtbare Produktschreibweise exakt
CLIscade; technische Repo-/Executable-Pfade bleiben kompatibel. Task-Icons liegen lokal inpublic/harness-icons/, Quellen inSOURCES.md; aktuelle Executables haben bei der Zuordnung Vorrang vor historischen Harness-IDs. Unbekannte CLIs erhalten ein neutrales Icon. -
Geöffnete Ausgabedetails zeigen keine wiederholte Vorschau/Kopfzeile. Das native
summarybleibt als beschrifteter 24-Pixel-Pfeil mit Tastaturfokus bedienbar; geschlossen erscheint die Vorschau wieder. -
Lange Modellnamen: Task-Status, CLI-Icon, Modell und Uhrzeit bleiben in einer Zeile; das Modell wird bei Platzmangel gekürzt und ist im Tooltip vollständig lesbar. Im Konsolenkopf erhält die Ordnerauswahl die volle Breite, CLI-Icon und Modell stehen darunter. Desktop und Mobil mit zwei Konsolen prüfen.
-
Folgeprompts nach einem Live-Lauf bleiben ohne Historienklick in derselben Konsole und übernehmen CLI, Modell und den jüngsten Vorgänger für den Kontext. Die Serverantwort wird über
requestIdzugeordnet; nur ältere Antworten ohne Anfrage-ID verwenden den Prompt als Rückfall. Ein bewusst neuer Task oder anderer Zielordner verwendet weiterhin die gewählte Route. -
Übergaben: doppelte Task-Bestätigungen sind idempotent. Wartende Folgeprompts bleiben beim laufenden Auftrag; beim Start werden Ordner und aktueller Vorgänger übernommen. Verdrängte Streams nehmen späte Ereignisse auf, dürfen aber Inhalt, Status, Tooltip oder Scrollposition eines anderen sichtbaren Tasks nicht ändern. Ein bewusst neuer Task bleibt auch bei nachträglichem Abschluss des alten Laufs ohne Vorgänger; bereits gesendete Anfragezuordnungen bleiben erhalten.
-
Ruhige Detaildarstellung: Denk-/Werkzeugbereiche ohne gebogene farbige Seitenlinie oder Pillenrahmen; dezente horizontale Trennung. Aktive Navigation und Tasks verwenden die Hintergrundfläche statt einer seitlichen Akzentklammer. Klapppfeil, Fokus und automatische Faltung bleiben erhalten.
Erscheinungsbild hell/dunkel seit 13. Oktober 2026
- Farbe existiert nur in zwei Blöcken in
public/style.css::root, :root[data-theme="dark"]und:root[data-theme="light"]. Beide tragen denselben Variablensatz; außerhalb steht kein Farbliteral (kein#hex, keinrgba()). Nicht-Farb-Token (Schrift, Radien) liegen im gemeinsamen:root-Block davor.test/theme.test.jserzwingt beides und schlägt sonst fehl. - Der dunkle Satz gilt ohne JavaScript (die dunkle Auswahl ist der Basis-Selektor).
index.htmlsetztdata-themein einem Inline-Skript vor dem Stylesheet, damit der erste Aufbau nicht flackert; Wahl auslocalStorage-Schlüsselcliscade_theme, sonstprefers-color-scheme. Beide Modi setzencolor-scheme, damit Formularelemente und Scrollbalken mitgehen. - Umschalter: Knopf im
.sidebar-footerund einer in der mobilen.studio-bar;data-iconbenennt das Ziel (sun= hell wird gewählt), nicht den Zustand. TastenkürzelTwirkt nur außerhalb von Eingabefeldern.meta[name=theme-color]folgt dem Modus (#0c0d10/#f7f8fa). - Änderungen an
index.html,app.jsoderstyle.cssziehen die Cache-Nummer inpublic/sw.jsund den Cache-Busterstyle.css?v=<N>inindex.htmlhoch.test/theme.test.jsvergleicht beide Zahlen. - Dichte: Seitenleiste 228 px, Projektzeile 20 px, Aufgabenzeile 33 px, Konsolenkopf 32 px Mindesthöhe, Eingabefeld 36 px Mindesthöhe (zwei Zeilen, wächst beim Tippen nach), Werkzeugknöpfe 26 px (grobzeigend 44 px), 4–6 px Rand um die Arbeitsfläche. Der leere Konsolenkörper beginnt oben links, wo die Ausgabe erscheint — mittig gesetzt wirkte die Fläche leerer, als sie ist. Keine Unschärfe-Effekte, keine Pulsanimation, keine harten Schatten außerhalb der Variablen.
test/dichte.test.jshält die Obergrenzen fest. Achtung: die wirksame Regel steht am Ende vonstyle.css, nicht an der ersten Fundstelle — dasselbe Selektoren-Paar kommt dort mehrfach vor. Wer eine Zahl ändert, prüft sie mitgetComputedStyleim Browser nach; zwei Ausnahmen bleiben absichtlich groß (16 px Schrift im Auftragsfeld am Telefon gegen das Hineinzoomen, 24 px Plus-Knopf am Finger). - Der Kopf der Seitenleiste trägt nur den Root-Ordner und den Neuladen-Knopf. Die Marke „AGENTS.md aktiv“ daneben ist entfernt (13. Oktober 2026); die Richtlinien öffnen sich weiterhin über den
AGENTS-Knopf im Projektbaum (project-agents-btn) und den Einstellungsbereich „AGENTS.md Richtlinien“.test/ui-smoke.mjshält HTML, Stil und Skript frei von den alten Kennungenroot-agents-badge,root-agents-textundworkspace-agents-badge. - Die Mac-App darf kein Erscheinungsbild erzwingen.
window.appearancelegt auchprefers-color-schemeim WebView fest: ein festes.darkAquasetzte die Seite auf Dunkel, der Hellmodus war nie zu sehen, und die App sah aus wie vor der Überarbeitung (gemessen am 14. Oktober 2026: macOS hell, Seite dunkel, keincliscade_themeimlocalStorage). Das Fenster startet deshalb mitappearance = nilund folgt der Oberfläche:public/app.jsmeldet jede Wahl über die WebKit-Brückeerscheinungsbildals{theme, folgtSystem},MainWindowController.userContentControllersetzt danachNSAppearance. BeifolgtSystembleibt das Fenster beim System — sonst käme ein späterer Systemwechsel nicht mehr durch. Ladeanzeige und Fensterhintergrund nutzenNSColor.windowBackgroundColor/.labelColor(KlasseThemenhintergrund), keine festenNSColor(calibratedRed:).test/ui-smoke.mjsAbschnitt 19 prüft die Meldung, eine scheiternde und eine fehlende Brücke. - Ein Neubau ist erst nach echtem Beenden sichtbar.
windowShouldCloseblendet das Fenster nur aus (orderOut), die App läuft weiter. Ein erneutes „Öffnen“ zeigt dann die alte Seite, obwohl das Bündel neu ist — ⌘Q und Neustart, oder ⌘⇧R („Ohne Cache neu laden“).
Konsolen-Leseschichten seit 14. Oktober 2026
- Die Schicht setzt der Server, nicht die Oberfläche.
renderRuntimeEventinserver.jsentscheidet anhand des Ereignistyps:thinking→denke,tool_start→werkzeug,tool_result→ausgabe,question→ Fragekarte, sonst keine Schicht. Die Kennung steht alsdata-console-layeram<div>;public/konsole-schichten.jsliest sie und macht daraus Ordner, Einzelzeilen und Flächen. Wer eine neue Schicht braucht, ergänzt sie an beiden Stellen: Regex ininZeilen, Eintrag inART, dazu die Regeln instyle.css. - Die Ausgabe ist keine Protokollzeile mehr. Vorher lagen Aufruf und Ergebnis im selben Werkzeugkasten und unterschieden sich vom Gedankengang nur durch den Titel. Jetzt hat
ausgabeeine eigene Fläche:--bg-sunken, linke Kante in--border-focus, Monospace, bis 360 px hoch scrollend. Der Gedankengang tritt dagegen zurück (gedämpft, kursiv, gestrichelte Trennung) — er ist Selbstgespräch, die Ausgabe ist das, was passiert ist. - Einzeilige Blöcke werden nicht eingeklappt. Ein Ordner mit dem Zähler „1 Zeile“ behauptet etwas, das er nicht hat: das Aufklappen zeigt genau die Zeile, die im Kopf schon steht.
faltbar = art.ordner && lineCount > 1; alles andere steht inline als.ko-einzeln ko-<schicht>. Der Zähler und der Kurzauszug entstehen nur noch für klappbare Blöcke. Ein wachsender einzeiliger Block trägtko-wachsendund atmet weiter. Wer Klappverhalten prüft, braucht eine mehrzeilige Vorlage — an einem einzeiligen Block lässt sich nichts klappen. - Kein Objekt darf als Text in die Konsole. cline liefert sein Werkzeugergebnis als
[{query, result, success}]; einString()darauf macht aus jedem Aufruf[object Object]— und cline tut das bei jedem Werkzeugaufruf.runtime/adapters/cline.jsmacht daraus „Aufruf über Ausgabe“;canonicalEventinruntime/events.jsist das Netz darunter und wandelt jedestext,message,questionin Text (Objekte als JSON) undoptionsin[{label, description}]. Wer einen Adapter ergänzt, verlässt sich nicht auf das Netz, sondern kennt seine Form. - Auswahlabfragen sind anklickbar, aber ohne Rückkanal.
ask_questionwird im cline-Adapter einquestion-Ereignis ({question, options});renderFrageinserver.jsmalt daraus.ko-fragemit einem<button class="ko-frage-option" data-antwort="…">je Option. Läufe sind headless — eine Antwort kann nicht in den laufenden Prozess zurück, und der fragende Lauf ist längst terminal. Der Klick übernimmt deshalb den vollständigen Auftragstext (Frage + Option + Beschreibung) in das Eingabefeld des Feldes; gesendet wird erst mit Enter, damit ein Klick keinen Lauf startet, den niemand abgeschickt hat. Die Fortsetzung derselben Sitzung besorgt der bestehende Weg überpreviousTaskId. - Alte Protokolle behalten den Platzhalter. Die Schichten stehen fertig gerendert in
tasks.record.outputHtml; die 1192[object Object]-Stellen in 23 Aufgaben ließen sich nicht nachträglich füllen, weil dieevents-Tabelle nicht so weit zurückreicht (Zuordnung stimmt nur bei 2 von 23 Aufgaben). Nicht raten, nicht überschreiben — neue Läufe sind richtig. - Prüfungen:
test/runtime/events.test.js(Trichter und Optionen),test/runtime/adapters.test.js(cline-Ergebnis, Frage),test/konsole_schichten.test.js(58 Behauptungen, u. a. einzeilige Blöcke und die Ausgabeschicht),test/new_clis_server.test.js(echte Kindprozesse: Schichttrennung und Fragekarte),test/ui-smoke.mjs(Klickpfad der Frage, Einzelzeile ohnedetails).
Konsolen-Gefühl seit 14. Oktober 2026
- Der Verlauf wird nicht neu gebaut.
maleVerlaufinpublic/app.jsvergleicht die Abschnitte des Formatierers mit dem letzten Stand und malt nur ab dem ersten geänderten Block. Vorher setzte jeder Chunkpane.body.innerHTMLauf den ganzen Puffer: bei bis zu 219 Chunks je Lauf und 1,1 MB größtem Puffer hieß das quadratisch wachsende Arbeit, und jede Textauswahl im Verlauf starb beim nächsten Textstück. Die Zusage, auf der das ruht, ist gemessen: in 37 echten Aufgaben mit 35.804 Blöcken bleibt beim Anhängen jeder frühere Block Zeichen für Zeichen gleich. Wer am Formatierer etwas ändert, was frühere Blöcke nachträglich umschreibt, bricht diese Annahme — der eine erlaubte Fall ist der Auto-Zuklapp (autoGeschlossen), und dafür wird ab dort neu gemalt. - Der Verlauf ist ein eigener Kasten.
.ko-verlaufin.run-pane-bodyist der einzige Ort, an dem gemalt wird; Platzhalter, wartende Aufträge (.ko-wartend) und die Sprungmarke stehen daneben.leereVerlaufleert ihn, wenn ein neuer Auftrag ins selbe Feld zieht (pane.malstand.taskId), sonst bliebe die alte Ausgabe stehen. - Ein Block ist eine Zeichenkette.
KonsoleFormatierer.abschnitte()liefert[{schluessel, html}],HTML()ist nur noch deren Verkettung. Die beiden dürfen nicht auseinanderlaufen —test/konsole_schichten.test.jsprüft, dass Zusammensetzen genauHTML()ergibt. - Der Cursor läuft über CSS.
.run-pane-body.ko-lebt .ko-verlauf::afterblinkt, solangestream.statusrunningoderqueuedist. Kein DOM-Element, damit die Versöhnung der Blöcke davon unberührt bleibt undpane.body.innerText(der Kopieren-Weg) keine Cursor-Zeichen einsammelt. - Die Schlusszeile sagt, wie es ausging.
schlussHtmlinpublic/app.jsersetzt das frühere eingefärbte[Fertig]:Code 0 · 0,4 s, bei Fehlschlag mit dem Grund, bei Abbruchabgebrochen · Code 130 · …. Sie wird instream.buffergehängt und ist damit ein normaler Block. Die Dauer kommt ausstream.startedAt, dasopenRunPanesetzt. - Die Sprungmarke holt einen zurück. Wer hochscrollt, verliert die Verfolgung (
runPaneFollow[slot]);.run-pane-jumperscheint dann und springt ans Ende. Sie sitzt in.run-pane(das dafürposition: relativeträgt), nicht im scrollenden Körper. Die Höhe über dem Eingabebereich wird gemessen (pane.composer.offsetHeight), nicht geraten. display: flexschlägt dashidden-Attribut..run-pane-jump[hidden] { display: none }ist deshalb Pflicht, nicht Kosmetik.- Was offen bleibt: der Formatierer liest weiterhin den ganzen Puffer je Chunk. Gemessen kostet der größte Lauf damit 2,9 s reine Rechenzeit über 219 Chunks — im Mittel 1,4 ms, am Ende etwa 40 ms. Das ist über die Laufzeit verteilt verkraftbar; ein Umbau auf schrittweises Zerlegen bräuchte den Gruppierungszustand über Aufrufe hinweg und ist bewusst nicht gemacht.
- Kein Fortschrittsbalken. Ein Wagenrücklauf vor dem Umbruch wird in
alsText(runtime/events.js) zu einem Umbruch normalisiert — das war in 2 von 82 Aufgaben zu sehen und erzeugte inpre-wrapje eine Leerzeile. Ein bloßes\rmitten in der Zeile bleibt stehen: das richtig zu stellen hieße, Spalten zu führen und die Zeile zu überschreiben. In den vorliegenden Protokollen kommt es nicht vor.
