Ein Claude-Skill, der eine Website so prüft, wie ein sorgfältiger Code-Reviewer es täte: Er sammelt Belege, bevor er sich eine Meinung bildet, folgt jedem personenbezogenen Datum vom Browser bis zum letzten Drittanbieter, bewertet jeden Befund nach deutschem Datenschutzrecht und schreibt erst dann die Datenschutzerklärung. Diese Seite zeigt, wie das Paket aufgebaut ist und was in jedem Schritt passiert.
Claude liest nie das ganze Paket auf einmal. Die Description ist immer im Kontext und entscheidet, ob der Skill anspringt. SKILL.md wird geladen, wenn er es tut, und enthält den Ablauf. Alles andere holt sich erst die Phase, die es braucht — ein 100-KB-Paket kostet also nur wenige Kilobyte Kontext, bis das Audit tatsächlich beginnt. Klicke eine Datei an, um zu sehen, wann sie gelesen wird und von welcher Phase.
Die Reihenfolge ist der Punkt. Eine Datenschutzerklärung, die geschrieben wird, bevor jemand weiß, was die Seite lädt, nennt Dienste, die es nicht gibt, und verschweigt die, die es gibt — das ist selbst ein Transparenzmangel nach Art. 5 Abs. 1 lit. a. Also zuerst Belege, dann Fragen, zuletzt die Erklärung. Klicke eine Phase an oder lass die Sequenz laufen.
Was Claude sehen kann, hängt davon ab, was es bekommen hat. Jede Stufe tiefer verliert Sicht, und der Bericht nennt die erreichte Stufe, damit der Mandant weiß, was verifiziert und was geschlossen wurde. Der Skill weigert sich, aus einer Beschreibung allein eine generische Erklärung zu erzeugen; er stellt stattdessen die Rückfragen. Ein Scan, der die Seite nicht erreicht, liefert kein Urteil (Exit-Code 3) — der Bericht rutscht eine Stufe tiefer und sagt das; ein Netzwerkfehler wird nie als saubere Seite gelesen.
Zuerst Abhängigkeiten (package.json ist der schnellste, verlässlichste Beleg), dann Quellcode nach Drittanbieter-Origins und Endgerät-Storage, dann Serverseite nach Stellen, an denen PII die App verlässt, dann Config nach Regionen und Headern. Env-Dateien werden nur nach Schlüsselnamen durchsucht; Werte gelangen nie in einen Bericht.
Google Tag Manager ist eine Blackbox, bis Tags feuern — der Skill fordert deshalb den Container-Export an. Ein Fetch sieht keine Cookies, die API-Antworten setzen. Ein Sprachumschalter heißt: jede Sprache braucht ihre eigene DSE (Art. 12). Jeder dieser Punkte ist ein expliziter Schritt, keine Hoffnung.
Was (Daten) · woher (Origin, Land) · wann (vor oder nach Consent) · wozu (Zweck) · Rechtsgrundlage · welcher Vertrag (AVV, gemeinsame Verantwortlichkeit, keiner) · Speicherdauer. Sieben Felder, für jeden Fluss gefüllt, werden zur Datenfluss-Tabelle des Berichts.
build-evidence.mjs gibt jeder Beobachtung eine ID. Jeder 🔴/🟠-Befund endet mit Evidenz: E-03 · beobachtet — oder abgeleitet, wenn er einen Schritt über das Gesehene hinausgeht (GA „lädt vor Consent“ aus dem Code, ohne Runtime-Scan), oder Mandantenangabe, wenn er auf Aussagen des Mandanten beruht.
list-processors.mjs macht aus derselben Evidenz die Auftragsverarbeiter-Tabelle: Art. 28, Art. 26 oder eigener Verantwortlicher, Vertrag, Region, Transfermechanismus und die Liste der anzufordernden AVVs. Ob unterschrieben, bleibt ⚪️, bis der Mandant es bestätigt; Hoster und Postfach kommen von Hand dazu.
diff-scans.mjs vergleicht zwei Scans. Ein neuer Tracker vor Consent ist eine 🔴-Regression und lässt --strict scheitern; ein entfernter Dienst wird aufgelistet, damit er auch aus der DSE verschwindet. dsgvo-watch.yml lässt das wöchentlich gegen eine eingecheckte Baseline laufen.
Frühere Entwürfe prüften die Seite. Der Skill prüft den Pfad. Personenbezogene Daten kommen im Browser an und wandern durch Edge-Code, API-Handler, eine Datenbank und eine Reihe von Drittanbietern, bevor sie in Logs und Backups landen. Jeder Hop ist eine Stelle, an der eine Rechtsgrundlage, ein Vertrag oder eine Speicherfrist fehlen kann. Klicke einen Hop an, um zu sehen, was dort geprüft wird.
references/architecture.md. Der laufende Punkt ist eine Absendung des Kontaktformulars; die Zeile darunter zeigt, wie jeder Hop für dieses Formular aussieht und welche Frage das Audit dort stellt.scripts/scan-origins.mjs öffnet die Seite in einem frischen Chromium-Profil und protokolliert, was der Browser tut, bevor jemand das Banner berührt. Dann klickt es „Ablehnen“ und prüft, ob etwas Neues lädt. Dann lädt es neu, klickt „Akzeptieren“ und inventarisiert alles, was die Seite laden kann — das ist die Liste, die die Datenschutzerklärung abdecken muss. In diesem letzten Schritt sucht es zuerst einen expliziten Alle-akzeptieren-Button und klickt nie eine Ablehnen-Variante wie „Nur notwendige akzeptieren“, damit das Inventar auch dann vollständig ist, wenn das Banner die Ablehnen-Option zuerst nennt. Spiele die Ausgabe auf einem der beiden Fixtures aus dem Repo ab.
Jeder Punkt des Prüfkatalogs bekommt einen von fünf Status. Einige Regeln des Skills sind strenger als das Gesetz verlangt, weil sich für eine kleine Praxis oder einen Pflegedienst der Dokumentationsaufwand des rechtmäßigen, aber komplizierten Wegs selten lohnt. Diese Regeln bleiben im Bericht 🔴, aber der Bericht sagt, dass sie die Regel der Agentur sind, nicht das Gesetz — damit Mandant und Anwalt entscheiden können. Schalte das Beispiel um, um den Unterschied in der Formulierung zu sehen.
| Status | Bedeutung | Beispiel |
|---|---|---|
| Kritisch | Rechtswidrig mit Abmahn-, Bußgeld- oder Schadensersatzrisiko. Blockiert den Go-live. | GA feuert vor Consent · Google Fonts vom CDN · kein Impressum |
| Hoch | Klarer Mangel, in diesem Sprint beheben. | Kein Ablehnen auf der ersten Ebene · fehlende Art.-13-Angaben · alter OS-Plattform-Link · PII in Logs |
| Mittel | Vertretbar, aber schwach — oder Verstoß gegen eine konservative Regel. | Vage Speicherfristen · kein VVT · US-Analytics mit Consent |
| OK | Konform. | Self-hosted Fonts · AVV abgelegt · EU-Region gepinnt |
| Unklar | Braucht Mandanten-Input oder Runtime-Verifikation. Sagt genau, was. | GTM ohne Container-Export · DPF-Status einer Entität |
Deployment-Regeln mit ihrer Nuance. Kein Consent → keine Drittanbieter-Ausführung (Gesetz; Essentielles wie das CMP oder ein Payment-Iframe ist nach § 25 Abs. 2 Nr. 2 TDDDG ausgenommen). Fonts und CDN-Assets self-hosted (Gesetz; Consent würde es heilen, aber niemand willigt für eine Schrift ein). Berechtigtes Interesse heilt § 25 nicht (Gesetz). Art.-9-Daten → keine US-Dienste im Datenpfad (Regel). AVV vor Go-live (Gesetz). US-Transfers nennen ihren Mechanismus, DPF nur für die gelistete Entität (Gesetz). KI-APIs sind Auftragsverarbeiter und brauchen Kennzeichnung nach Art. 50 KI-VO (Gesetz). Nie eine Erklärung kopieren (Urheberrecht). Nie einen Befund abschwächen — aber immer sagen, welcher Art er ist.
Das Repo ist ein Claude-Code-Plugin. Ein gepushter Versions-Tag baut das .skill-Paket und veröffentlicht ein GitHub-Release: Claude-Code-Nutzer aktualisieren mit einem Befehl, Claude.ai- und Cowork-Nutzer laden eine Datei herunter. Jedes Release hält außerdem einen Rechtsstand fest — den Monat, bis zu dem die Rechtsquellen verifiziert wurden —, denn das Recht bewegt sich, und ein Compliance-Werkzeug muss sagen, wie alt sein Wissen ist.
plugin.json entsprechen, sonst verweigert der Workflow — und der Paketschritt lässt den Validator erneut laufen, damit nie ein kaputter Skill ausgeliefert wird."version": "1.0.0"was Claude Code vergleicht"version": "1.0.0"Katalogeintrag"version": "1.0.0"Toolingmetadata.version · law-standreist im .skill mitnpm run validate schlägt fehl, wenn sie auseinanderlaufen, wenn dem CHANGELOG der Abschnitt fehlt, wenn evals/evals.json auf ein nicht existierendes Fixture zeigt oder wenn ein bekannter früherer Fehler wieder auftaucht (grep mit Klammer-Glob, § 7 Nr. 3 UWG, ein OS-Plattform-Link ohne Entfernungshinweis). Es warnt, wenn die Description näher als 40 Zeichen an die 1024-Zeichen-Grenze kommt.
npm test zeigt, dass der grep-Block Treffer findet und der Scanner den richtigen Button klickt. Es sagt nichts darüber, ob ein mit dem Skill geschriebenes Audit gut ist: ob es den GA4-Tag im Layout findet, Formspree als regelbasiertes 🔴 statt als gesetzliches einstuft oder nach der Kammer fragt, statt eine zu erfinden. Evals messen das. Jedes ist ein erfundenes Fixture, ein Prompt, wie ein Entwickler ihn tippen würde, und eine Liste von Erwartungen, an denen ein fauler Durchlauf scheitert. Mit dem Skill und ohne ihn ausgeführt, ist die Differenz der Bestehensquote der Wert des Skills; gegen die Vorversion ausgeführt, ist die Differenz das, was eine Änderung bewirkt hat.
| Eval | Fixture | Was es fängt |
|---|---|---|
nextjs-ga-fonts-audit | Next.js: GA4 vor Consent, Google Fonts vom CDN, Kontakt-Route zu Resend + Sentry mit dem Body in extra, regions: ["iad1"], alter ODR-Link | Evidenz zuerst, nur aus Code; der Hop-Trace (ein Formular, vier Empfänger); der Satz zur Evidenzstufe; nur Audit, wenn Audit verlangt war |
static-site-runtime-scan | Statische Seite mit „Nur notwendige akzeptieren“ vor „Alle akzeptieren“ | Dass der Scanner wirklich läuft und nicht durch HTML-Lesen ersetzt wird; dass die Ablehnen-Variante nicht für Akzeptieren gehalten wird; ein 404 hinter einem vorhandenen Impressum-Link ist 🔴 |
praxis-art9-intake | Buchungsseite einer ästhetischen Chirurgie: Behandlungs-Select, Textarea Beschwerden/Medikamente, Foto-Upload, Formspree, Calendly | Art. 9 an den Feldern erkannt; US-Dienste im Gesundheitspfad als regelbasiertes 🔴 mit Hinweis auf die anwaltliche Ausnahme; § 203 StGB, DSFA, DSB angesprochen; Rückfragen statt generischer Erklärung |
astro-minimal-dse-generation | Astro bei Hetzner, @fontsource, Plausible, nodemailer ans eigene Postfach, vollständige INTAKE.md | Moduldisziplin: nur, was die Evidenz trägt; Plausible auf Art. 6 Abs. 1 lit. f, nicht auf Consent; Fristen aus dem Intake; kein Platzhalter übrig; Art. 21 hervorgehoben; LDI NRW benannt |
ai-chatbot-processor | OpenAI-Chat-Route mit Triage-System-Prompt, unbegrenzte chat_logs in Supabase, UI-Text „Unser Team antwortet sofort“ | LLM als Auftragsverarbeiter (DPA, kein Training, Speicherdauer, Region); Kennzeichnung nach Art. 50 KI-VO; Art. 22 für die Triage; Steuereingaben als Art.-9-nah; „verifizieren“ für den DPF-Status |
Zwanzig Prompts auf Deutsch und Englisch, zwölf, die den Skill öffnen sollen, und acht, die es nicht sollen (eine Supabase-Tabelle, ein Vercel-Build-Fehler, SPF für Resend). Sie testen allein die Description und schützen ihren letzten Satz — den, der gewöhnliche Entwicklungsarbeit nicht zum Audit werden lässt.
scripts/grade-report.mjs prüft, was kein Urteilsvermögen braucht: acht Abschnitte in der richtigen Reihenfolge, jeder 🔴/🟠-Block mit Befund, Rechtsgrundlage, Risiko, Maßnahme und Aufwand, jeder 🔴/🟠-Befund mit Evidenz-ID und Evidenzstufe, jede zitierte ID im Evidenzverzeichnis, der RDG-Hinweis, kein „abmahnsicher“, kein übrig gebliebener Platzhalter, § 5 DDG statt TMG. Goldene und kaputte Fixtures halten den Grader selbst in der CI ehrlich.
Jede Änderung an SKILL.md, references oder Vorlagen: Output-Evals gegen die Vorversion. Jede Änderung an der Description: Trigger-Evals, drei Durchläufe je Prompt. Ein neuer Rechtsstand: Output-Evals — und eine neue Erwartung für jedes geänderte Urteil. Ein Release: alle drei, mit den Zahlen im Changelog.
Was Evals nicht sagen können. Sie messen gegen die Fixtures und Erwartungen, die jemand geschrieben hat. Eine Rechtsposition, die in recht.md falsch ist und in einer Erwartung wiederholt wird, besteht mit voller Punktzahl. Die Primärquellen-Regel in CONTRIBUTING ist die Kontrolle der Erwartungen; die Evals kontrollieren, dass der Skill anwendet, was die Referenzen sagen.
Die Teile, die viele Augen brauchen, sind die, die veralten: Dienst-Urteile, Rechtsquellen und Framework-Muster. Jeder hat eine Datei, in die er gehört, ein Issue-Template, das nach der nötigen Quelle fragt, und einen Test, der den wahrscheinlichsten Weg abfängt, ihn kaputt zu machen. Die vierte Art, ein Eval, ist die Art, wie eine Änderung an den anderen drei gemessen wird.
Ein Urteil, eine Gesetzesänderung, neue Behördenleitlinien. Gehört in recht.md — und in checklist.md oder services.md, wenn es ein Urteil ändert. Braucht eine Primärquelle mit Datum. Hebt den Rechtsstand an.
Sicherung: Validator lehnt bekannt veraltete Zitate ab; PR-Checkliste fragt nach der Quelle.
Eine Zeile in services.md (Consent? Rechtsgrundlage? Region? Urteil + Alternative), ein Origin-Regex in der SIGNATURES-Liste des Scanners, damit er beschriftet wird, und ein DSE-Modul, falls das generische nicht passt.
Sicherung: Scanner-Test belegt die Erkennung auf einer Fixture-Seite; Anbieter-Dokumentation Pflicht.
Ein Consent-Gating- oder Self-Hosting-Beispiel für ein noch nicht abgedecktes Framework, unter den sieben generischen Prinzipien in patterns.md. Prinzipien bleiben framework-agnostisch; Beispiele illustrieren sie.
Sicherung: Es muss den Load gaten, nicht die Nutzung; die Anti-Pattern-Liste ist die Checkliste.
Ein kleines erfundenes Fixture mit jedem Signal an seinem Platz, ein Prompt, wie ein Entwickler ihn tippen würde, und 8–11 Erwartungen in evals/evals.json, an denen ein fauler Durchlauf scheitert. Ein neues Urteil oder eine neue Rechtsposition bekommt eines, damit eine Regression sichtbar würde.
Sicherung: Validator prüft, dass Fixtures existieren und IDs eindeutig sind; der Durchlauf vergleicht mit der Vorversion.
npm test ausführt| Prüfung | Was sie schützt | Wie |
|---|---|---|
validate.mjs | Paketintegrität, Versionsabgleich, Frontmatter, tote Verweise, Agent-Definition, Eval-Definitionen | Statische Prüfungen, keine Abhängigkeiten |
phase1.test.sh | Die Phase-1-Befehle finden tatsächlich etwas | Extrahiert den echten Bash-Block aus SKILL.md, lässt ihn auf einem Fixture-Repo laufen, prüft Treffer und dass kein Secret-Wert ausgegeben wird |
grade-report.test.mjs | Der deterministische Grader selbst | Akzeptiert den goldenen Bericht, die DSE und das Impressum; weist den kaputten Bericht aus sieben benannten Gründen zurück |
scanner.test.mjs | Der Runtime-Scanner Ende-zu-Ende | Drei Fälle: die nicht konforme Seite (Origins vor Consent, Ablehnen-Differenz, Akzeptieren-Inventar, alter ODR-Link), das Banner mit der Ablehnen-Option zuerst und eine unerreichbare URL, die mit Exit 3 ohne Urteil enden muss |
package | Das .skill ist baubar und validiert | Läuft in der CI bei jedem Push; Artefakt 14 Tage aufbewahrt |