Modul 8

Skills, Tools & Infrastruktur

Tag 3 · ca. 105 Minuten

Inhalt

Lernziel Modul 8

Der Teilnehmer kann Skills, Rules, Commands und Hooks pro Workflow-Phase bauen und das Git-Handling weitgehend autonom gestalten.

  1. Bauen statt benennen — Modul 2 hat die Primitive vorgestellt, hier entstehen sie als Dateien im Repo.
  2. Pro Workflow-Phase — jede Phase aus Modul 5 bekommt ihr Werkzeug, statt einer Sammlung einzelner Kunststücke.
  3. Git-Handling — Commit und Push laufen weitgehend ohne Rückfrage.
Wer dem Agenten git push überlässt, muss alle anderen Primitive vorher im Griff haben.

Nur der Hook erzwingt etwas

Drei Primitive legen Text in den Kontext und hoffen.
Das vierte läuft außerhalb des Modells — und wird deshalb ausgeführt, nicht gelesen.

im Kontext des Modells
bei jedem Aufruf
CLAUDE.md
niemand entscheidet — ist einfach da
wenn ein Glob passt
Rule
das Tool entscheidet, anhand des Pfads
beim Aufruf
Skill
Modell über die Beschreibung oder Mensch per Slash-Befehl
außerhalb des Modells
an einem Tool-Event
Hook
kommt gar nicht in den Kontext — läuft als Programm
Anweisung, kein Zwangdeterministisch erzwungen
CLAUDE.md, Rule und Skill sind Bitten an ein nicht-deterministisches Modell — der Hook ist Code.

Skills bauen

Woher Skills kommen

Drei Wege, dieselbe Bauform: mitgeliefert, installiert oder selbst geschrieben — am Ende ist es immer eine SKILL.md.

  1. Mitgeliefert: Claude Code bringt eigene mit — /review, /security-review, /init. Was geladen ist, zeigt /skills.
  2. Installiert: Plugins aus einem Marktplatz bündeln Skills, Agents, Hooks und MCP-Server. Der offizielle Marktplatz ist ab Werk da — echtes Beispiel: claude-md-management von Anthropic (Modul 7).
  3. Selbst gebaut: .claude/skills/<name>/SKILL.md im Repo (Team) oder unter ~/.claude/ (nur ihr).
  4. Namensraum & Vorrang: Plugin-Skills heißen /plugin:skill. Sonst gilt: persönlich schlägt Projekt, und jeder eigene Skill überschreibt einen mitgelieferten gleichen Namens.
  5. Änderungen greifen sofort — kein Neustart nötig. Nur ein neu angelegtes Skill-Verzeichnis braucht einen.
/skills # was ist gerade geladen?
/plugin # Marktplatz durchsehen (Discover)
/plugin install github@claude-plugins-official
/reload-plugins # ohne Neustart aktivieren

# selbst gebaut
.claude/skills/deploy/SKILL.md # Repo = Team
~/.claude/skills/…/SKILL.md # nur ihr
Fremder Code läuft mit euren Rechten — das gilt für Plugins und für eingecheckte Projekt-Skills: ein Skill kann sich per allowed-tools selbst breite Rechte geben, sobald ihr dem Ordner vertraut.
Vorher lesen.
checked am 2026-07-26 gegen code.claude.com/docs/discover-plugins

Anatomie einer SKILL.md

Ein Skill ist ein Ordner mit einer Markdown-Datei: .claude/skills/<ordner>/SKILL.md — und die hat genau zwei Teile:

  1. YAML-Frontmatter zwischen den ----Zeilen: die Metadaten, nach denen ausgewählt wird — Name, Beschreibung, erlaubte Werkzeuge. Nur die Beschreibung liegt dauerhaft im Kontext.
  2. Markdown-Body darunter: die eigentliche Anleitung an das Modell. Lädt erst beim Aufruf — ausführliches Referenzmaterial gehört trotzdem daneben (Folie „Wo das Wissen liegt").
---
name: build
description: Build + push images to GHCR — local Docker build or CI.
  Use when the user wants to build/push images (not deploy).
allowed-tools: Bash(*), Read, Agent  ·  argument-hint: [local | ci]
---

# Build + Push Images
## Help (no-op path)
If the argument is `help`: print ONLY this usage and STOP — build nothing.

**This skill only BUILDS + PUSHES. It does NOT deploy.**
Deploy is a separate, human-gated step (`/deploy`).
| Mode | Invocation | When | … ganz normale Markdown-Tabelle

cgsit-finance/.claude/skills/build/SKILL.md — gekürzt. · Feldreferenz: code.claude.com/docs/en/skills

Wissen oder Ablauf

Bevor ihr Felder setzt: welche Sorte Inhalt steht im Body?
Die Antwort entscheidet fast jede Frontmatter-Wahl danach.

Reference content — Wissen Task content — Ablauf
Was drinstehtKonventionen, Muster, Style Guides, DomänenwissenSchritt für Schritt für eine Aktion
Beispielapi-conventions, testing-guardrails/deploy, /commit, /test
Wer löst ausmeist das Modell, wenn es zur Arbeit passtmeist ihr, per /name
Typische Felderuser-invocable: false · von einem Agenten vorladbardisable-model-invocation: true · ggf. context: fork
Läuftinline, neben dem Gesprächskontextinline oder im Subagenten
  1. Fork nur für Ablauf: ein Wissens-Skill im Fork bekommt Regeln, aber keine Aufgabe — und kommt ohne Ergebnis zurück.
  2. Jede Zeile kostet wiederkehrend: ein geladener Skill bleibt über die Turns hinweg im Kontext. Schreibt, was zu tun ist — nicht, warum.
Wissen wird angewandt, Ablauf wird ausgeführt. Wer das vorab entscheidet, muss die Felder danach nicht mehr raten.
checked am 2026-07-26 gegen code.claude.com/docs/skills

Wo das Wissen liegt

Nicht alles gehört in die SKILL.md.
Die Frage ist immer dieselbe: wer braucht es sonst noch?

  1. Nebendateien — nur für diesen Skill. Die SKILL.md bleibt Übersicht und Wegweiser, Details liegen daneben und laden erst bei Bedarf. Faustregel: unter 500 Zeilen.
  2. Verlinken nicht vergessen: im Body muss stehen, was in welcher Datei steht — sonst weiß Claude Code nicht, wann es sie öffnen soll.
  3. Zentrales Dokument — brauchen es mehrere Wege, gehört es nach docs/. Bei CGS hängt docs/testing.md an sechs Stellen.
  4. Die Wahl: braucht es nur dieser eine Skill? Nebendatei. Brauchen es Menschen und mehrere Werkzeuge? docs/ plus Verweise (Modul 7).
# 1) Nebendateien — gehören zu EINEM Skill
my-skill/
  SKILL.md # Übersicht + Wegweiser
  reference.md # lädt erst bei Bedarf
  scripts/helper.py # ausgeführt, nicht geladen

## Additional resources
- For complete API details, see reference.md

# 2) zentrales Wissen — cgsit-finance
docs/testing.md # eine Wahrheit
  referenziert aus CLAUDE.md
  · rules/testing-rules.md
  · agents/test-engineer.md
  · skills/test · test-generator
    · architecture-reviewer · doc-initializer
Eine Wahrheit, viele Eingänge. Kopiertes Wissen driftet — verlinktes nicht.
checked am 2026-07-26 gegen code.claude.com/docs/skills + cgsit-finance

Ein geladener Skill bleibt

Beim Aufruf wandert der gerenderte Body als eine Nachricht in die Unterhaltung — und bleibt dort.
Er wird nicht neu gelesen.

  1. Schreibt stehende Anweisungen, keine Einmal-Schritte — was während der ganzen Aufgabe gelten soll, muss auch so formuliert sein.
  2. Zweimal aufrufen kostet nichts extra: bei identischem Inhalt kommt nur ein Hinweis „schon geladen", keine zweite Kopie.
  3. Nach /compact werden die zuletzt aufgerufenen Skills wieder angehängt — je die ersten 5.000 Tokens, gemeinsames Budget 25.000. Ältere fallen dabei heraus.
  4. „Der Skill wirkt nicht mehr": meist ist der Inhalt noch da, das Modell wählt nur anders. Antwort: description schärfen — oder einen Hook, wenn es garantiert sein muss.
Ein Skill ist keine Funktion, die aufgerufen und beendet wird — er ist Text, der ab jetzt mitfährt. Deshalb zählt jede Zeile, und deshalb ist die Wirkung nie garantiert.
checked am 2026-07-26 gegen code.claude.com/docs/skills

Die Frontmatter-Felder

Feld Wirkung Beispiel aus dem Repo
nameAufrufname (/name) — nicht zwingend der OrdnernameOrdner architecture-reviewer, name review-architecture
descriptionWofür & wann. Danach entscheidet das Modell, ob es den Skill zieht.„Use when the user asks to commit changes."
allowed-toolsVorab-Freigabe für den Turn des Aufrufs — keine Beschränkung. Entziehen: disallowed-toolsBash(git *) beim commit-Skill
argument-hintErwartete Argumente, wird beim Aufruf angezeigt[backend | frontend | all]
disable-model-invocationtrue = nur der Mensch startet ihn — siehe nächste Foliecommit, tag: true
user-invocablefalse = nur das Modell zieht ihn — siehe nächste Folieüberall true
contextfork = der Skill läuft im Subagenten (dazu agent, background)Kapitel „Context-Firewall"

Vollständige Feldreferenz: code.claude.com/docs/en/skills

checked am 2026-07-26 gegen code.claude.com/docs/skills + cgsit-finance

Auslöser und Katalogeintrag

Zwei Felder steuern, wer den Skill starten darf — und ob seine Zeile im Skill-Katalog steht, den das Modell in jedem Request mitliest:

Frontmatter Du Claude Code Was im Kontext liegt
(Default)jajadescription immer · voller Skill beim Aufruf
disable-model-invocation: truejaneindescription gar nicht · voller Skill, wenn du aufrufst
user-invocable: falseneinjadescription immer · voller Skill beim Aufruf
  1. Der Katalog ist je Skill eine Zeile aus name + description — der volle Text lädt erst beim Aufruf (Kontext-Anatomie: Modul 3).
  2. Gesperrt heißt: fehlt im Katalog. Mit disable-model-invocation: true steht die Zeile gar nicht erst im Kontext.
  3. Was nicht im Katalog steht, kann das Modell nicht ziehen — es weiß nicht, dass es den Skill gibt.

code.claude.com/docs/en/skills

checked am 2026-07-26 gegen code.claude.com/docs/skills

Pflicht für eigene Skills: der Help-Pfad

Gebt jedem eigenen Skill einen help-Pfad — sonst führt ein /name help den Skill aus, statt ihn zu erklären.

  1. Warum: Ein hilfsbereites Modell liest /test help als „führe die Tests aus und erkläre es dabei" — Hilfsbereitschaft ist antrainiert (Modul 1).
  2. Wie: als erste Anweisung im Body, und ausdrücklich als Nichts-Tun formuliert: print ONLY this usage and STOP.
  3. Was hineingehört: Aufrufformen und Argumente, was der Skill nicht tut, und wohin man stattdessen geht.
## Help (no-op path)
If the argument is `help`, `-h` or `--help`: print ONLY this usage and STOP — run no tests.
> **Usage:** `/test [backend|frontend|all]` — run local unit tests, compact pass/fail.
> • `all` (default) — backend `mvn test` + frontend `ng test` • `backend` / `frontend` — one only
> • e2e is NOT here (CI job). Run before `/build` — the local build does not test.
Bei /deploy ist dieser Block der Unterschied zwischen einer Frage und einem Produktionsrollout.

Wörtlich aus cgsit-finance/.claude/skills/test/SKILL.md — dasselbe Muster in build, deploy, ship.

Was der Slash-Befehl garantiert

Der /-Befehl macht das Laden einer Prozedur sicher.
Ihre korrekte Verwendung macht er nicht sicher: im Kontext ist auch eine Anleitung nur Text.

  1. Geladen? /deploy getippt: sicher. Vom Modell über die description gezogen: wahrscheinlich, nicht sicher. disable-model-invocation: true: nur der Mensch.
  2. Befolgt? Nie garantiert. Das Modell liest die Schritte — auch bei einem perfekten Skill.
  3. Wirkung verhindert? Permissions greifen am Befehl. Sie fangen den groben Fehlgriff (Force-Push, rm -rf), nicht die übersprungene Prüfung.
  4. Also: was garantiert sein muss, gehört ins Shell-Skript — Prüfungen, Reihenfolge, Abbruch bei Fehlschlag.
  5. Faustregel: was schiefgehen darf, darf im Skill stehen — was nicht schiefgehen darf, gehört ins Skript.
# Leiter der Verbindlichkeit
CLAUDE.md # wird gelesen, vielleicht befolgt
/deploy (Skill) # sicher geladen, interpretiert
deny / ask # blockt den Befehl, nicht den Denkfehler
deploy.sh # prüft, bricht ab, oder liefert
Hook # erzwingt es auch ungefragt
Der Slash-Befehl macht das Laden sicher, die Permission die Wirkung — dazwischen liegt Text, den ein Modell liest.
checked am 2026-07-26 gegen code.claude.com/docs/skills

Skills als Context-Firewall

Ein Skill ist nicht nur eine Anleitung — er ist der Ort, an dem man Output aus dem Hauptkontext heraushält.

Hauptkontextbleibt schlank
Skill sagt: im Subagenten
eigener Kontext · wird verworfen
mvn test
hunderte Zeilen
Maven-Ausgabe
zurück kommt nur
{scope, passed, failed,
failing_tests[], rc}
arbeitetAusgabewas ankommt
Ein mvn test im Hauptthread belastet den Kontext dauerhaft, im Subagenten einmal — zurück kommen fünf Zeilen.

Erzwingen statt bitten: context: fork

Die Anweisung im Body ist eine Bitte.
Ein Frontmatter-Feld macht daraus eine Zusage: der Skill läuft dann im Subagenten.

  1. context: fork — der Skill selbst läuft im Subagenten, sein Body wird dessen Prompt — ohne eure Konversationshistorie.
  2. Standard ist Hintergrund: ihr arbeitet weiter, das Ergebnis kommt später an. background: false wartet im selben Zug.
  3. agent: <typ> wählt den Subagenten-Typ — optional: ohne das Feld braucht ihr keine eigene Agent-Definition.
  4. Nur für Task content (Folie „Zwei Sorten Inhalt"): ein reiner Wissens-Skill bekommt im Fork keine Aufgabe und liefert nichts zurück.
  5. Gegenbeispiel (fortgeschritten): das test-Skill in cgsit-finance forkt nicht — es steuert zwei parallele Subagenten und führt deren Ergebnisse zusammen. Ein Fork kann nur einen Auftrag — nächste Folie im Detail.
---
name: run-tests
description: Run the full suite, return a compact result.
context: fork # läuft im Subagenten
agent: test-engineer # optional: welcher Typ
background: false # im selben Zug warten
---

# der Body ist jetzt der Auftrag des Subagenten
Run `mvn test`. Return ONLY {passed, failed, failing_tests[]}.
Änderungen eines Hintergrund-Forks liegen außerhalb der Checkpoints — /rewind holt sie nicht zurück.
Dafür ist Git zuständig.
checked am 2026-07-26 gegen code.claude.com/docs/skills

Praxisfall: ein Skill orchestriert Subagenten

Das test-Skill aus cgsit-finance bleibt im Hauptkontext — und schickt zwei parallele Subagenten in die laute Arbeit.

  1. Warum überhaupt auslagern: Maven- und Karma-Ausgabe sind hunderte Zeilen — und sie bleiben für immer im Kontext.
  2. Zwei Suiten, zwei Subagenten: Backend und Frontend sind unabhängig, also laufen sie gleichzeitig.
  3. Randbedingungen werden mitgegeben — jede mit einem datierten Vorfall als Begründung, nicht als Prinzip.
  4. Zurück kommt ein vereinbartes Format, keine Rohlogs: {scope, passed, failed, failing_tests[], rc}.
  5. Danach entscheidet der Skill: etwas rot? Dann kein /build und kein /deploy.
  6. Das sind generische Subagenten — professioneller geht es mit einem eigenen Agent-Typ: nächste Folie.
allowed-tools: Bash(*), Read, Agent # darf Subagenten starten

## How to run — in a SUBAGENT (context hygiene)
Run each suite in a subagent that returns ONLY a compact
result: `{scope, passed, failed, failing_tests[], rc}`.
Do NOT paste raw test logs into the main thread.

For `all`: the two suites are independent
--> run them as two parallel subagents.

**Guardrails to pass to the subagent(s):**
1. Run from the repo root, NOT `-pl`-scoped.
   (lesson 2026-05-18, RFC-163: rot in CI, grün lokal)
2. Backend needs Docker (DevServices/Testcontainers).
Der Skill orchestriert: starten, Randbedingungen mitgeben, einsammeln, entscheiden.
Genau deshalb darf er nicht selbst forken — im Subagenten könnte er nichts mehr zusammenführen.
checked am 2026-07-26 gegen cgsit-finance/.claude/skills/test/SKILL.md

Der Master-Skill schrumpft

Dieselbe Aufgabe wie auf der Folie zuvor — aber die Randbedingungen sind ausgezogen.
Übrig bleibt reine Orchestrierung.

  1. Was bleibt: wen starten, wie viele parallel, was mit dem Ergebnis geschieht.
  2. Was weg ist: Repo-Root-Regel, Docker-Hinweis, CHROME_BIN-Kniff — alles, was wie beschreibt statt was.
  3. Warum das zählt: ein zweiter Aufrufer (etwa /ship) müsste dieselben Randbedingungen sonst kopieren — und die Kopien driften.
  4. Agent in allowed-tools bleibt Pflicht — ohne das startet der Skill keinen Subagenten.
# .claude/skills/test/SKILL.md — die abgespeckte Fassung
---
name: test
description: Runs the local suites, reports compact pass/fail.
allowed-tools: Bash(*), Read, Agent
argument-hint: [backend | frontend | all]
---

Backend suite --> subagent (subagent_type: backend-test-runner).
Frontend suite --> subagent (subagent_type: frontend-test-runner).
For `all`: both are independent --> run them in parallel.

Relay the compact result per scope.
If anything is red: no `/build`, no `/deploy` — surface the failures.
Ein guter Orchestrator ist kurz: er sagt wen und was danach — nicht wie.
Das Wie gehört zum Ausführenden.
checked am 2026-07-26 gegen code.claude.com/docs/sub-agents

Wohin die Randbedingungen wandern

In je einen Agent-Typ pro Umgebung — und jeder lädt sein Fachwissen als Skill vor, statt es im eigenen Text zu vergraben.

  1. Zwei Suiten, zwei Spezialisten: Backend braucht Docker, Frontend einen headless Chromium — die Randbedingungen sind disjunkt.
  2. skills: lädt den vollen Inhalt beim Start — jeder Agent bekommt nur sein eigenes Wissen, kein Ballast.
  3. Warum als Skill statt im Agent-Text: so ist dasselbe Wissen auch für Menschen und andere Agenten verfügbar — das ist Reference content in Reinform.
  4. Grenzen im Agenten: tools bestimmt, was er kann; model und maxTurns, was er kostet.
# .claude/agents/backend-test-runner.md
name: backend-test-runner tools: Bash, Read model: haiku
skills: [ backend-test-guardrails ] # Repo-Root, Docker
Run `mvn test` from the repo root. Return ONLY {…}.

# .claude/agents/frontend-test-runner.md
name: frontend-test-runner tools: Bash, Read model: haiku
skills: [ frontend-test-guardrails ] # CHROME_BIN, vitest
Run `npx ng test --watch=false`. Return ONLY {…}.

# die beiden Wissens-Skills — disjunkt, kein Ballast
backend: Repo-Root statt `-pl` (RFC-163) · DevServices
frontend: CHROME_BIN setzen · fehlender Browser = rc 126
Faustregel: Wiederholte Randbedingungen gehören in einen Agenten — und wenn Menschen sie auch brauchen, in einen Skill, den der Agent vorlädt.
checked am 2026-07-26 gegen code.claude.com/docs/sub-agents

Parameter: übergeben, prüfen, einsetzen

Ein Skill nimmt Argumente entgegen — aber es gibt keine Schema-Prüfung: Validierung ist eine Anweisung im Body, die harte Grenze bleiben die Freigaben.

  1. Deklarieren: argument-hint zeigt die erwartete Form beim Tippen, arguments benennt sie ([issue, branch]).
  2. Einsetzen: $ARGUMENTS, $0/$1 nach Position, $name für benannte — plus ${CLAUDE_SKILL_DIR}/${CLAUDE_PROJECT_DIR} für Pfade.
  3. Prüfen: als erste Anweisung im Body — „ist das Argument nicht local oder ci: nachfragen und stoppen". Das ist eine Bitte, kein Gate.
  4. Sicher einsetzen: ein Argument ist Fremdtext. Nie ungeprüft in eine Befehlszeile — und allowed-tools so eng wie möglich fassen.
  5. Vorsicht bei !befehl``: dessen Ausgabe wird vor dem Senden in den Prompt eingesetzt. Was da hineinläuft (Text aus einem Pull Request, Logs), ist ungeprüfter Input — Modul 9.
---
argument-hint: [local | ci]
arguments: [mode]
allowed-tools: Bash(${CLAUDE_SKILL_DIR}/scripts/build.sh *)
---

Ist $mode weder `local` noch `ci`:
nachfragen und STOPPEN — nichts bauen.

Sonst: ${CLAUDE_SKILL_DIR}/scripts/build.sh $mode
Der Trick mit ${CLAUDE_SKILL_DIR}: dieselbe Variable in allowed-tools und im Body — dann trifft die Freigabe genau den Befehl, den der Skill startet.
checked am 2026-07-26 gegen code.claude.com/docs/skills

Skills, die Skills verwenden

Ein Skill darf andere Skills aufrufen — damit werden aus einzelnen Schritten eine Kette mit einem menschlichen Tor darin.

  1. Voraussetzung: das Skill-Werkzeug in allowed-tools — ohne das ruft ein Skill keinen anderen auf.
  2. Echtes Beispiel: /ship in cgsit-finance verkettet /test, /build, /deploy und die Verifikation.
  3. Rot stoppt die Kette: nie auf roten Tests bauen, nie auf fehlgeschlagenem Build deployen.
  4. Das Tor bleibt menschlich: vor dem Deploy fragt die Kette — genau dort, wo es unumkehrbar wird.
  5. Freigaben gelten auch hier: Skill(commit) erlaubt gezielt, ein deny auf Skill schaltet alle ab.
# cgsit-finance/.claude/skills/ship/SKILL.md
allowed-tools: Bash(*), Read, Agent, AskUserQuestion, Skill

 /test --> /build --> [HUMAN GATE] --> /deploy --> verify
 (grün?) (nach GHCR) (fragt nach) (rollout)

# Eine rote Stufe STOPPT die Kette.
Verkettung lohnt sich dort, wo die Reihenfolge Bedeutung hat.
checked am 2026-07-26 gegen cgsit-finance + code.claude.com/docs/skills

Warum der Skill nicht zieht

Der häufigste Frust beim ersten eigenen Skill — und er hat meist eine mechanische Ursache, keine inhaltliche.

  1. Zieht gar nicht: stehen in der description die Wörter, die ihr wirklich sagt? Gegenprobe: „Welche Skills gibt es?" fragen — taucht er auf?
  2. Zieht zu oft: description enger fassen, oder disable-model-invocation: true, wenn nur ihr ihn starten sollt.
  3. Der Katalog hat ein Budget — rund 1 % des Kontextfensters. Bei vielen Skills werden Beschreibungen gekürzt, zuerst bei den selten genutzten. Damit fallen genau die Stichworte weg, die zum Treffen nötig wären.
  4. Kaputtes Frontmatter lädt den Body ohne Metadaten: /name geht noch, aber das Modell hat keine Beschreibung zum Matchen. --debug zeigt den Parse-Fehler.
# findet Claude Code den Skill überhaupt?
/skills
> „Welche Skills gibt es?"

# was kostet der Katalog, wer sind die Treiber?
/doctor
/context # Zeile „Skills"

# Budget anheben (settings.json)
skillListingBudgetFraction: 0.02 # = 2 %

# Parse-Fehler sichtbar machen
claude --debug
Die description ist kein Kommentar, sondern die Suchoberfläche.
Wichtigster Anwendungsfall zuerst — der Text wird bei 1.536 Zeichen ohnehin gekappt.
checked am 2026-07-26 gegen code.claude.com/docs/skills

Skills pro Phase

Der Phasen-Workflow aus Modul 5 ist die Landkarte.
Jede Phase mit Wiederholung und Zeremonie bekommt einen Skill.

Analyse
/rfcs
RFC oder Ticket, Artefakt, Issue
Architecture-
Review
review-architecture
ux-reviewer
gegen Architektur-Doku
Planung
/rfcs update
/plan-feature
Status-Gate, Zerlegung
Implementierung
generate-tests
+ Rules (auto)
Testgerüst, Konventionen
Delivery
/test /build
/deploy /ship
Release-Kette mit Gate
Abschluss
/commit /tag
Commit-Konvention, Tags
Phase aus Modul 5Skill bei CGS
Die Bau-Regel: erst dreimal von Hand, dann Skill. Wer vorher automatisiert, baut Skills für Abläufe, die es noch nicht gibt (Zeremonie-Falle, Modul 6).

Analyse & Planung: der rfcs-Skill

---
name: rfcs
description: Manage cgsit-finance RFCs and GitHub Tickets. Decide RFC vs
  ticket-only, create/update specs in docs/rfcs/, create/link/close GitHub
  Issues, manage sub-tickets under an RFC.
user-invocable: true
allowed-tools: Read, Edit, Write, Glob, Grep, Bash(ls *), Bash(gh issue *), Bash(gh label *)
argument-hint: [list|status|new "title"|ticket "title"|update NNN status|close NNN]
---

Der Kern ist eine Entscheidung

Der Skill enthält eine Tabelle „RFC + Ticket vs. Ticket-only" — neues Feature, Refactoring, DB-Migration werden zum RFC; Bugfix und UI-Polish bleiben nur Ticket.

Und eine Tool-Allowlist

allowed-tools erlaubt gh issue und gh label — sonst nichts von gh. Kein gh repo delete, kein gh pr merge.

Architecture-Review als Skill

---
name: review-architecture
description: Review code changes against the project's architecture definition
  and Sensitive-Area invariants. Use when reviewing PRs, after implementing a
  feature, or as PFLICHT-Subagent-Review in RFC-169 Self-Review Discipline
  (Stripe / Auth / Securities-Core / Portfolio-Ledger / Money /
  Migration-on-Large-Table / Cross-Tenant).
---
Der Skill sagt dem Modell nicht nur was zu prüfen ist, sondern wie der Subagent zu briefen ist: Trigger, geänderte Dateien, Aufgabenkontext, klare Frage — „review against architecture, report per finding".
2026-07-10 Ein UI-Label zeigte „1 Gruppe" — „Gruppe" ist ein internes RBAC-Konzept, kundenseitig existiert nur „Subscriber". Tests waren grün, die Architektur war korrekt, trotzdem war es falsch. Daraus entstand der zweite Review-Skill: ux-reviewer prüft die Kundenoberfläche auf geleakte interne Begriffe. Ein Reviewer pro Blickwinkel.

Delivery-Phase: die Kette

/test
/build
HUMAN
GATE
/deploy
verify

/ship ist die Klammer über alle vier — und lässt das Gate trotzdem stehen:

Chains the three stages into one flow. **The deploy gate is always an
interactive human confirmation** (CLAUDE.md Push & Deploy Policy — deploy is
never autonomous).
Der Schnitt zwischen /build und /deploy ist bewusst: Bauen ist wiederholbar, Ausrollen ist es nicht.

Commands vs. Skills

Skill

Kann vom Modell selbst gezogen werden, hat Frontmatter, Tool-Allowlist, Argumente. Trägt die Logik.

Command

Nur vom Menschen per /name. Bei CGS oft nur eine kurze Einstiegs-Anweisung, die auf einen Skill zeigt.

# Review Current Changes

Review the code changes in the current branch against project standards.

1. Run `git diff main --name-only` to see changed files
2. Use the code-reviewer agent (`.claude/agents/code-reviewer.md`) checklist
3. Use the architecture-reviewer skill to check architecture compliance
4. Read `.claude/rules/` for relevant coding rules

Report findings grouped by severity (Critical -> Warning -> Suggestion).
If everything looks good, say so — don't invent issues.

cgsit-finance/.claude/commands/review.md — wörtlich, gekürzt. Vier Commands im Repo, elf Skills.

Rules & Hooks

Rules: Wissen, das sich selbst holt

Eine Rule ist eine Markdown-Datei unter .claude/rules/ mit Glob-Mustern (paths:) im Frontmatter.
Wird eine passende Datei angefasst, ist die Regel im Kontext — ohne dass jemand daran denkt.

---
paths: ["**/db/migration/**/*.sql",
        "**/db/migration/**/V*.sql",
        "**/src/main/resources/**/V*.sql"]
---

# Flyway Migration Safety (Quarkus + Postgres)

**Auto-loaded** for every `V*.sql` edit. This is the **load-bearing** rule:
a bad migration can put prod into a Flyway crash-loop until the next hotfix,
lock big tables for minutes, or silently corrupt cross-tenant data.

Neun Rules im Repo: java-conventions, quarkus-backend, api-rules, database-rules, testing-rules, angular-conventions, ui-theming, money-fx, migration-safety.

Die Grenze steht wörtlich in der CLAUDE.md: „If you edit a file outside these globs, no rule auto-loads — read the relevant rule file manually." Der Fehlerfall einer Rule ist stumm.

Hooks: bitten vs. garantieren

Ein Skill schreibt eine Bitte in den Kontext.
Ein Hook startet ein Programm am Tool-Event — und fragt das Modell nicht.

Mensch
im Modell · Wahrscheinlichkeit
liest
CLAUDE.md · Rule
Skill-Body
Modellentscheidet
Tool-Call
Bash · Edit
Write
Hook
exit 2 blockt
ausgeführt
oder nicht
was das Modell liest Hook · Programm, kein Text
Ein Hook ist das einzige Primitiv, dessen Wirkung nicht davon abhängt, ob das Modell gerade gut drauf ist.

Hooks registrieren: settings.json

"hooks": {
  "PreToolUse": [
    { "matcher": "Bash",
      "hooks": [
        { "type": "command",
          "command": "python3 \"$CLAUDE_PROJECT_DIR/scripts/claude-hooks/block-prod-compose-down.py\"" },
        { "type": "command",
          "command": "python3 \"$CLAUDE_PROJECT_DIR/scripts/claude-hooks/block-parallel-docker-build.py\"" }
      ] }
  ],
  "PostToolUse": [
    { "matcher": "Edit|Write|MultiEdit",
      "hooks": [
        { "type": "command",
          "command": "python3 \"$CLAUDE_PROJECT_DIR/scripts/claude-hooks/postedit-guardrails.py\"" },
        { "type": "command",
          "command": "python3 \"$CLAUDE_PROJECT_DIR/scripts/claude-hooks/rfc-gate-guardrails.py\"" }
      ] }
  ]
}
checked am 2026-07-21 gegen cgsit-finance

Der Vertrag: stdin, exit-Code, fail open

Ein Hook liest JSON auf stdin und antwortet mit einem exit-Code.
Mehr Schnittstelle gibt es nicht.

"""Contract: reads the PreToolUse JSON on stdin. Exit 0 = allow, exit 2 = block
(stderr shown to the model). Fails OPEN on any error so it never blocks
unrelated work."""
try:
    payload = json.load(sys.stdin)
except Exception:
    sys.exit(0)         # fail-open: never block on a parsing hiccup
JSON auf stdin
Tool-Name, Tool-Input
exit 0erlauben
PreToolUse: der Call läuft
PostToolUse: alles in Ordnung, still
dasselbe JSON,
Regel greift
exit 2eingreifen
PreToolUse: blockiert, stderr geht ans Modell
PostToolUse: Edit ist schon passiert Nudge ans Modell
Parsing-Fehler,
Absturz, Timeout
exit 0fail open
nichts wird blockiert — ein kaputter Hook
darf nie die ganze Arbeit anhalten

Ein echter PostToolUse-Hook

# PostToolUse = the edit already happened; this is a **nudge**, not a block.
# Exit 0 = clean/irrelevant, exit 2 = surface the reminder to the model.

fp = payload.get("tool_input", {}).get("file_path", "")

# --- SCSS (cgsit-finance-web) — ui-theming.md ---
if fp.endswith(".scss") and "cgsit-finance-web" in fp:
    for i, ln in enumerate(lines, 1):
        if varfallback.search(ln):
            findings.append(f"  L{i}: var(--cgs-*, <fallback>) — hex-Fallback "
                        f"versteckt fehlende Var im Dark-Mode (ui-theming.md §4.2)")
        elif hexrgb.search(ln):
            findings.append(f"  L{i}: rohe Farbe (#hex/rgb) — via var(--cgs-*) lösen")

if findings:
    sys.stderr.write(f"Guardrail-Grep für {fp} — bitte prüfen (Nudge, kein Block):\n" ...)
    sys.exit(2)
sys.exit(0)
Der Hook führt genau die Greps aus, die in ui-theming.md und migration-safety.md als Prosa stehen — damit ein Verstoß sofort auffällt statt beim Review oder beim Deploy.

Gute Hooks haben ein Datum und ein Predicate

2026-07-01 Zwei parallel laufende docker build haben WSL per OOM-Kill beendet. Der /build-Skill baut zwar sequenziell — aber ein beiläufig getipptes docker build umgeht den Skill. PreToolUse-Hook block-parallel-docker-build.py blockt einen zweiten Build, solange ein anderer läuft. Der Skill ist die Bitte, der Hook ist das Netz darunter.
2026-07-01 Derselbe Hook-Ansatz produzierte einen Fehlalarm: ein git commit -m "…docker build…" wurde geblockt, weil die Phrase im Text vorkam. Der Hook prüft seither, ob docker der Ausführende ist (argv0), nicht ob das Wort irgendwo vorkommt.
Produktionsschutz docker compose down löscht auf prod das PostgreSQL-Volume. Ein pauschales Verbot hätte die lokale Entwicklung lahmgelegt. block-prod-compose-down.py blockt nur, wenn drei Bedingungen gleichzeitig zutreffen — siehe unten.
# Lokales `docker compose down` bleibt erlaubt (die Dev-DB ist entbehrlich).
is_executor      = first_token in ("ssh", "docker", "docker-compose")
has_compose_down = re.search(r"docker[-\s]+compose\s+down", low) is not None
targets_prod     = (PROD_EIP in cmd) or ("ssh " in low)

if is_executor and has_compose_down and targets_prod:
    sys.exit(2)  # Meldung nennt die erlaubte Alternative
Das Predicate ist die Bedingung, die entscheidet — hier drei Prüfungen mit UND verknüpft, damit lokales Dev erlaubt bleibt.

Was ein Hook nicht kann

Der vierte Hook härtet die RFC-Status-Gates aus Modul 5: behauptet ein RFC den Status Accepted / In Progress / Done, muss das Beweis-Artefakt im Dokument stehen.

"""Was der Hook KANN (Mechanik/Evidenz):
  - Struktur-Lint (Pflichtfelder vollstaendig)
  - Accepted / In Review -> Analyse-Review-Notiz (+ Datum) vorhanden?
  - In Progress -> Design-Freigabe-Haken `- [x]` (oder Skip-Begruendung)?
  - Done -> Closeout-Notiz (+ Datum) vorhanden?
Was er NICHT kann: das *Urteil* des Reviews ersetzen — das bleibt der
architecture-reviewer-Subagent. Der Hook prueft nur, DASS der Review
dokumentiert ist, nicht ob er gut war."""
Grep, Datei-Check
Hookprüft Mechanik
Liegt der Beweis vor?
Modell, Architektur-Doku
Subagentfällt das Urteil
War der Review gut?
Erfahrung, Haftung
Menschträgt die Verantwortung
Geht das so raus?

Autonomes Git-Handling — die CGS-Freigabetabelle

Aktion Freigabe
Local builds, tests, commits no need to ask
gh run list, Log-Tails, DB-Leseabfragen, Backups proactive OK, just announce
git push origin main no need to ask — push when commits are ready
git push origin main --no-verify ask first
docker compose pull && up -d auf prod ALWAYS ask first
git push --force ALWAYS ask first
Anything destructive ALWAYS ask first
Die Trennlinie ist nicht „gefährlich / harmlos", sondern „reversibel / nicht reversibel".
Ein Push nach main ist rückholbar.
Ein Deploy trifft echte Nutzer.

Permissions: die Denylist

"permissions": {
  "allow": [ "Read(**)", "Write(**)", "Bash(**)" ],
  "deny": [
    "Bash(rm -rf /)",
    "Bash(git push --force *)",
    "Bash(git reset --hard*)",
    "Bash(git clean -fd*)",
    "Bash(docker compose down -v*)",
    "Bash(*DROP DATABASE*)",
    "Bash(aws rds delete-db-instance*)",
    "Bash(aws s3 rm*--recursive*)",
    "Bash(npm publish*)",
    "Bash(*pastebin*)", "Bash(*transfer.sh*)", "Bash(*file.io*)"
  ]
}

Unwiederbringlich

reset --hard, clean -fd, compose down -v, DROP DATABASE — alles, was nicht committete Arbeit oder Daten löscht.

Exfiltration

Pastebin-Dienste stehen auf deny, damit kein Code oder Secret „mal eben zum Teilen" das Haus verlässt. (Modul 9)

Commit-Konvention als Skill

---
name: commit
description: Create git commits following cgsit-finance project conventions.
  Use when the user asks to commit changes.
disable-model-invocation: true
user-invocable: true
allowed-tools: Bash(git *)
argument-hint: [message or "push"]
---

## Rules
- **NEVER** add "Co-Authored-By" lines
- **NEVER** add "Generated by" or similar AI attribution
- Commit message format: `module: short description`
- Use imperative mood (add, fix, update, remove — not added, fixed)
disable-model-invocation: true — der Agent darf committen, wenn man ihn schickt.
Er kommt nicht von selbst auf die Idee, mitten in einer Analyse Historie zu schreiben.

MCP: das Vokabular

Client

Die Anwendung, in der das Modell läuft — hier: Claude Code. Sie verbindet sich zu Servern.

Server

Ein Prozess, der Fähigkeiten anbietet. Lokal gestartet oder remote erreichbar.

Tools

Aufrufbare Funktionen mit Parametern — das, was der Agent tatsächlich ausführt.

Resources

Lesbare Inhalte, die der Server bereitstellt — Dokumente, Datensätze, Zustände.

Prompts

Vom Server mitgelieferte Vorlagen, die der Nutzer auswählen kann.

Connectors

Fertige, gehostete Anbindungen an Dienste — MCP als Produkt statt als Selbstbau.

MCP ist ein offenes Protokoll: ein Server, den ihr einmal baut, funktioniert an jedem Client, der MCP spricht — nicht nur an diesem.
checked am 2026-07-21 gegen Doku

Ein MCP-Server in der Praxis

// cgsit-finance/.mcp.json
{
  "mcpServers": {
    "angular": {
      "command": "npx",
      "args": ["-p", "@angular/cli", "ng", "mcp"],
      "cwd": "…/cgsit-finance-web"
    }
  }
}
// .claude/settings.local.json — Aktivierung ist ein SEPARATER Schritt
"enableAllProjectMcpServers": true,
"enabledMcpjsonServers": [ "angular" ]
.mcp.json ist eine Angebotsliste, keine Einschaltliste.
Konfiguriert heißt nicht aktiv — und im Repo eingecheckt heißt: das ganze Team bekommt dieselbe Angebotsliste (Modul 10).

MCP vs. CLI: Token Overhead

Jeder aktive MCP-Server lädt seine Tool-Definitionen in den Kontext — das kostet, bevor irgendetwas passiert, und in jeder Runde erneut (Modul 1: alles wird neu geschickt).

MCP-Server

Dauerhafte Kontextmiete für alle Tools, auch die nie benutzten. Zahlt sich aus bei Wissen, das der Agent sonst nicht hat.

CLI

Kostet nur bei Benutzung. Der Agent kann ohnehin Bash — und --help lesen.

Beleg aus dem Repo Für GitHub gibt es in cgsit-finance bewusst keinen MCP-Server — es läuft komplett über die gh-CLI: gh issue create im rfcs-Skill, gh run list/watch in build, ship, deploy. Wo eine CLI dasselbe kann, ist sie meist billiger — und man kann sie im Skill eng zuschneiden.
Vertiefung: ein eigenes MCP-Deck behandelt Konzepte, Server verwenden, einen eigenen Server bauen (Quarkus) und die Abgrenzung zur CLI — Modul 8 · MCP im Detail.

Open Source & Vendor Lock-in

Portabel

RFCs und Specs als Markdown · Architektur- und Domänen-Doku · Tests und Build · CI-Pipeline · Commit- und Review-Konventionen · MCP-Server (offenes Protokoll) · die Arbeitsweise selbst

Toolspezifisch

Skill-Format inkl. Frontmatter-Feldern · Hook-Events und Registrierung · settings.json-Keys und Permission-Syntax · Rule-Autoloading per Glob · Slash-Command-Ablage

Die Wertschöpfung steckt in den portablen Artefakten.
Toolspezifisch ist nur die Verdrahtung — und die ist in ein bis zwei Tagen neu gelegt.

Prüffrage fürs eigene Repo: Wenn morgen ein anderes Werkzeug käme — was wäre weg, und was bliebe?

Modul 8 in fünf Sätzen

1Skills sind Markdown mit Frontmatter — die description ist das Interface, allowed-tools die Allowlist, der Help-Pfad die Bremse.
2Ein Skill pro Phase, gebaut nach dem dritten manuellen Durchlauf — nicht vorher.
3Rules laden sich per Glob selbst — und schweigen, wenn der Glob nicht passt.
4Hooks sind das einzige deterministische Primitiv: exit 0 erlaubt, exit 2 blockt oder mahnt, jeder Fehler endet fail open. Gezielt, nicht pauschal.
5Autonomie nach Reversibilität vergeben: Push autonom, Deploy mit Gate, Unwiederbringliches auf deny.
Alles Gebaute ist nur so viel wert, wie es im Repo steht — versioniert, reviewbar, für alle (Modul 10).

Übung 8 — Skill und Hook bauen

Aufgabe

1. Skill: Baut in seminar-api einen eigenen Skill unter .claude/skills/<name>/SKILL.md mit Frontmatter (name, description, allowed-tools, argument-hint) und einem Help-Pfad, der nichts tut. Vorschlag: /review-slice — prüft den aktuellen Diff gegen eure Konventionen und meldet Findings nach Schweregrad.

2. Hook: Registriert einen PostToolUse-Hook auf Edit|Write, der eine einzige projektspezifische Regel per Grep prüft — z. B. System.out.println in *.java oder ein fehlender @Transactional. exit 0 wenn sauber, exit 2 mit einer Meldung, die den richtigen Weg nennt. Fail open bei jedem Fehler.

Verifizierbares Ergebnis: Beide greifen nachweislich — der Skill wird aufgerufen (per /name und einmal vom Modell selbst, nur über die description), und der Hook meldet sich sichtbar bei einem Edit, der die Regel verletzt — und schweigt bei einem, der sie einhält.

Dauer ca. 35 Minuten · Zweiergruppen

© 2026 CGS IT Solutions GmbH

Alle Rechte vorbehalten

Diese Schulungsunterlagen sind urheberrechtlich geschützt. Vervielfältigung, Weitergabe oder kommerzielle Nutzung — auch in Auszügen — nur mit ausdrücklicher schriftlicher Genehmigung der CGS IT Solutions GmbH.

cgsit-claude-training · Modul 8 · v0.11.5