Leitplanken für Repos,
in denen eine KI mitschreibt.
Ein Assistent mit Schreibrecht auf deinem Arbeitsbaum ist kein Autocomplete. Er ist ein Prozess mit Werkzeugzugriff, ohne Gedächtnis über die Sitzung hinaus und ohne Gefühl für Scope. Das ist beherrschbar — aber nicht mit besseren Prompts, sondern mit Struktur, die auch dann hält, wenn der Kontext weg ist.
Hier liegt, was dabei entstanden ist. Fertig, benutzbar, Apache-2.0.
Werkbank
| zfdw-ki-leitplanken | Acht Methodentexte, drei Vorlagen, vier Slash-Commands, zwei Hooks mit Testsuite, ein Herkunfts-Gate. Keine Laufzeit, keine Dependencies, kein Installer. | Apache-2.0 |
| guard-geschuetzte-daten.sh |
PreToolUse-Hook. Misst mit git add --dry-run, was ein Befehl
tatsächlich stagen würde — statt aus dem Zustand daneben zu schließen.
Deckt git commit -am mit ab, fällt ohne jq closed.
19 Testfälle, 8 bewusste Nicht-Treffer.
|
im Repo |
| Sprint + Write-Scope |
Eine Datei pro Arbeitsabschnitt, die zugleich der Zustand ist. Kein zweiter
State-Store, der gegen das Repo driftet. Überlebt /clear.
|
im Repo |
| Methode 07 — Verortung | Einordnung gegen SpecKit, BMAD, OpenSpec, GSD Core und Kiro — samt der Frage, wann eines der fünf die bessere Wahl ist. Angaben aus den Original-Repositorien, mit Lesedatum im Kopf. | im Repo |
| Methode 08 — Spezifikationsgüte | Werkzeuge sagen, wie eine Spec auszusehen hat. Keines sagt, ob sie gut ist. Sechs Gütekriterien aus den Grundsätzen ordnungsmäßiger Modellierung (1995), übertragen auf Spezifikationen — weil eine Spec ein Informationsmodell ist. | im Repo |
| herkunft-check.sh | Grep-Gate gegen eine gepflegte Begriffsliste, bevor etwas aus Kundenarbeit öffentlich wird. Die Begriffsdatei ist gitignored und guard-geschützt — sie besteht aus genau den Namen, die nicht raus sollen. | im Repo |
Einordnung
Spec-driven Development kennt drei Reifegrade. Spec-first — einmal vor der Arbeit spezifiziert, danach liegt das Dokument still. Spec-anchored — die Spezifikation wird mitgeführt und beim Abschluss fortgeschrieben. Spec-as-Source — Menschen editieren nur noch die Spezifikation, nie den Code.
Das hier ist Spec-anchored, und zwar als Entscheidung, nicht als Zwischenstufe. Spec-first scheitert daran, dass das Dokument nach dem dritten Tag nicht mehr stimmt und es niemand merkt — der Fehlermodus hat einen Namen, Spec Drift. Spec-as-Source setzt voraus, dass generierter Code nie von Hand angefasst wird; in gewachsenen Kundenprojekten trägt diese Annahme nicht. Die Sprint-Datei ist deshalb der Stand selbst, nicht dessen Ankündigung.
Gegenüber SpecKit, BMAD, OpenSpec, GSD Core und Kiro ist das kein Konkurrenzangebot. Die fünf regeln die Reihenfolge — beschreiben, planen, zerlegen, umsetzen. Sie sagen nicht, welche Datei ein Abschnitt anfassen darf, welche Grenze in Code gehört und womit „fertig“ belegt ist. Genau das steht hier, und es läuft neben jedem der fünf.
Methode 07 — Verortung
zieht den Vergleich im Einzelnen, mit Lesedatum im Kopf, weil diese Seite schneller driftet als
der Rest. Zwei verbreitete Angaben stimmen dort nicht mehr: Das ursprüngliche GSD-Repository ist
archiviert und lebt als GSD Core weiter, und SpecKit ist mit dem
converge-Schritt nicht mehr linear.
Der Fall, an dem Textregeln scheitern
Jede CLAUDE.md enthält irgendwo den Satz „niemals secrets.json
committen“. Der funktioniert — solange der Dateiname im Befehl vorkommt. Er tut es hier nicht:
$ git add -A
Der Guard sieht deshalb nicht in den Befehl, sondern fragt das Werkzeug, was der Befehl bewirken würde:
# Nur Befehle, die ueberhaupt etwas stagen koennen: git add in jeder Form —
# und git commit -a, das Verfolgtes selbst stagt.
printf '%s' "$befehl" | grep -qE '(^|[;&|]|\s)git\s+(-[^ ]+\s+)*add(\s|$)' \
|| printf '%s' "$befehl" | grep -qE '(^|[;&|]|\s)git\s+commit([^;&|]*)?\s-[A-Za-z]*a' \
|| exit 0
# Kandidaten = was der Befehl TATSAECHLICH stagen wuerde. Gemessen, nicht
# geschaetzt: `git status` weiss nicht, ob eine Datei vom Befehl erfasst waere.
if printf '%s' "$befehl" | grep -qE '…add\s+(-u|--update)(\s|$)' \
|| printf '%s' "$befehl" | grep -qE '…commit…\s-[A-Za-z]*a'; then
roh=$(git add -u --dry-run 2>/dev/null) # -u / commit -a: nur Verfolgtes
else
roh=$(git add -A --dry-run 2>/dev/null) # sonst: auch Unverfolgtes
fi
kandidaten=$(printf '%s\n' "$roh" | sed -n "s/^add '\(.*\)'$/\1/p")
$ hooks/tests/test-guard.sh
Nicht-Treffer (duerfen NICHT blocken):
ok git add einer harmlosen Datei (Code 0)
ok Bulk-Add ohne geschuetzte Datei (Code 0)
Treffer (muessen blocken):
ok .env vorhanden, Bulk-Add -A (Code 2)
ok Add in Befehlskette (Code 2)
Gemessen statt geschaetzt:
ok commit -am stagt verfolgte Datei (Code 2)
ok add -u ignoriert unverfolgte .env (Code 0)
ok add -A erfasst dieselbe .env (Code 2)
Fail-closed ohne jq:
ok ohne jq blockt der Guard (Code 2)
...
19 bestanden, 0 fehlgeschlagen
Drei Härtungen sind im August aus produktiver Kundenarbeit zurückgeflossen — dort waren über
hundert unverfolgte Dateien mit realen Daten im Arbeitsverzeichnis gelandet, keine davon von
.gitignore erfasst. Messen statt schätzen: --dry-run
beseitigt einen Fehlalarm, der vorher garantiert kam — git add -u neben einer
herumliegenden, unverfolgten .env. git commit -am mit
abgedeckt: Es stagt selbst und lief vorher vorbei. Fail-closed ohne
jq: Fehlt das Werkzeug, blockt der Guard und nennt den
Installationsbefehl, statt still durchzulassen. Ein Guard, der auf einem frisch aufgesetzten
Rechner unbemerkt abgeschaltet ist, ist schlimmer als keiner.
Übernommen ist dabei die Technik, nicht der Fall: Dieser Guard kennt keine Kundendateien und
keine Kundenpfade — die stehen in der .claude/geschuetzte-pfade des jeweiligen
Projekts. Vor der Veröffentlichung läuft das Herkunfts-Gate darüber.
Dieselbe Unterscheidung trägt weiter, als sie zunächst aussieht: Regeln, die abgewogen werden dürfen, gehören in Text. Regeln, bei denen ein Verstoß eine Meldepflicht auslöst, gehören in Code, der nicht abwägt. Die meisten Projekte legen beides an denselben Ort und wundern sich über das Ergebnis.
Warum das offen liegt
Weil Werkzeuge, die man nicht lesen kann, keine Werkzeuge sind, sondern Versprechen. Und weil das, was hier steht, ohnehin nur durch Nachbauen besser wird.
Die Herkunft steht drin, wo es eine gibt: Der Sprint-Gedanke ist angeregt durch CC_GodMode von Dennis Westermann — dort eingebettet in ein großes Agenten-System, hier auf das eingedampft, was ohne Toolchain trägt. Was nicht übernommen wurde, ist genauso benannt wie das, was übernommen wurde. Das ist keine Höflichkeit, das ist Nachprüfbarkeit.
Alte Tugend, unverändert gültig: nimm, verbessere, gib zurück. Und dann rede darüber — nicht aus Eitelkeit, sondern weil ungeteiltes Wissen niemandem nützt und stillschweigend verrottet.
Alles unter Apache-2.0. Patentklausel drin, Namensnennung drin, kommerzielle Nutzung
ausdrücklich erlaubt — auch für die, die damit Geld verdienen wollen.
github.com/sitelookgmbh-arch/zfdw-ki-leitplanken
Wer
Hinter Wirkarchitektur steht die sitelook GmbH in Neuss. Über sie läuft die Arbeit: Entwicklung, Beratung, Schulung — und die Rechnung. Gemacht wird sie von Martin Eggert.
Geschrieben wird hier aus der Praxis: Fachanwendungen und die Infrastruktur darunter — Blazor/.NET, nginx, Asset-Pull-Deploys, DNS, das übliche. Dazu eine Herkunft in der technischen Reportage, und aus ihr die eine Regel, die jeden Text auf dieser Seite prägt: Komplexe Sachverhalte werden verständlich, wenn man die Motivation der Beteiligten begreiflich macht. Deshalb beginnt jeder Methodentext mit dem Problem und kommt erst danach zur Regel — eine Regel ohne ihren Grund wird beim nächsten Zweifel wegdiskutiert.
Und ein Satz, älter als jedes Werkzeug hier: Einer ist keiner. Die Fehler liegen selten in den Teilen, fast immer in den Übergängen zwischen ihnen. Wer das einmal in einer laufenden Produktion gesehen hat, kennt das Muster, lange bevor es Write-Scope heißt.
Es geht nicht um Verpackung. Die Ästhetik im vermeintlich Reizlosen ist ergiebiger als aufgeblähter Schein — was man dieser Seite ansieht.
Kontakt
Issues und Pull Requests gehen ins Repo — das ist der schnellere Weg. Für alles andere:
Kolophon
Handgeschriebenes HTML, ein Stylesheet, kein Build. Systemschriften, weil eine Webfont-Einbindung eine Anfrage an einen fremden Host wäre. Ausgeliefert als statische Dateien vom Edge.
Content-Security-Policy: default-src 'none'; style-src 'self';
img-src 'self' data:; form-action 'none'; base-uri 'none';
frame-ancestors 'none'
Referrer-Policy: no-referrer
Permissions-Policy: camera=(), microphone=(), geolocation=()
/_headers. default-src 'none' heißt: Was nicht ausdrücklich erlaubt ist, wird nicht geladen.Diese Seite: 14,6 kB HTML, 7,3 kB CSS — unkomprimiert; über die Leitung geht brotli-komprimiert etwa die Hälfte. 2 Anfragen insgesamt. Kein Skript, kein Cookie, kein Banner.