Automatischer Push: 32 Datei(en) geändert

- .claude/agents/executer.md
- .claude/agents/planer.md
- .claude/agents/pruefer.md
- .claude/agents/recherche.md
- .claude/skills/plan-executer-pruefung/SKILL.md
- .claude/workflows/executer-welle.js
- .claude/workflows/plankritik.js
- .claude/workflows/pruefung.js
- .claude/workflows/welle-mit-pruefung.js
- .gitignore
- .vault-tools/regelwerk-check/ENTWURF.md
- .vault-tools/regelwerk-check/regelwerk_check.py
- … und 20 weitere

Erzeugt vom PostToolUse-Hook .vault-tools/auto-push/auto_push.py.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
Pascal MichelandClaude Opus 5 committed 2026-09-24 04:00:02 +02:00
1 parent b7cc7433a9
commit c5da36cb41
18 files changed
+1055 -35

No files matched your search

+136 -6
View File
@@ -20,7 +20,7 @@ Sechs Prüfungen, jede über eine GESCHLOSSENE Menge:
2 Frontmatter Trägt jede Regelwerk-Datei die sieben Pflichtfelder?
3 Erreichbarkeit Ist jede Regelwerk-Datei vom Stamm aus verlinkt?
4 Freigabe Steht eine Regelwerk-Datei auf status: pending-review?
5 Modell Weicht model: einer Agentendatei von der Rollentabelle ab?
5 Modell/Effort Weichen model: oder effort: einer Agentendatei von der Rollentabelle ab?
6 Planablage Nennt eine Datei die Dateiform ohne die Ordnerform?
Die Rollentabelle und die Liste der Regelwerk-Verweise werden AUS CLAUDE.md
@@ -36,8 +36,12 @@ WAS DIESE PRÜFUNG NICHT SIEHT — benannte Lücken
eine Heuristik im Positivlisten-Gewand. Bewusst weggelassen.
* Modellaussagen im Fließtext. "(`executer`, Sonnet — bei reiner Abschrift
Haiku)" ist für einen Menschen eindeutig und für ein Skript nicht. Geprüft
wird ausschließlich das model:-Feld im Frontmatter.
Haiku)" ist für einen Menschen eindeutig und für ein Skript nicht.
Geprüft werden ausschließlich die Felder model: und effort: im
Frontmatter.
* Ein YAML-Kommentar hinter dem Wert (effort: high # …) wird nicht
abgeschnitten und ergibt einen Befund; für model: galt das schon vorher.
* INHALTLICHE Widersprüche. Zwei Dateien können dieselbe Regel in
verschiedenen Worten gegensätzlich formulieren, und diese Prüfung meldet
@@ -46,6 +50,23 @@ WAS DIESE PRÜFUNG NICHT SIEHT — benannte Lücken
aufgefallen: die Planablage (Prüfung 6) ja, "fortsetzen statt frisch
starten" nein.
* effort: bei model: haiku. Haiku 4.5 kennt keinen Effort; Claude Code
sendet ihn dann nicht (Claude Code 2.1.280, Programmdatei, nachgelesen
2026-09-23). Die Rollentabelle führt keinen Agenten auf Haiku; die
Abschrift-Stufe steht im Task-Frontmatter, nicht in einer Agentendatei.
* Doppelter Schlüssel effort:. Der flache Frontmatter-Leser nimmt den
letzten Wert, wie bei model:.
* Ob Claude Code den Wert anwendet. Das zeigt nur das Feld effort im
Transkript eines echten Laufs, und eine geänderte Agentendatei wirkt
in der laufenden Sitzung nicht sofort. Belegt am 2026-09-23 in frischen
Sitzungen über das Agent-Werkzeug und im Workflow.
* effort in gespeicherten Workflows unter .claude/workflows/. Sie setzen
den Effort mit agentType absichtlich nicht; eine Abweichung dort sieht
diese Prüfung nicht.
===============================================================================
DIESES SKRIPT IST EIN FANGNETZ, KEIN NACHWEIS.
===============================================================================
@@ -103,6 +124,11 @@ def wikilinks(text: str) -> list[str]:
PLANPFAD = re.compile(r"docs/plans/JJJJ-MM-TT[^\s`]*")
BACKTICK = re.compile(r"`([^`]+)`")
# Die Stufen stammen aus Claude Code 2.1.280 (Programmdatei, nachgelesen
# 2026-09-23). Claude Code selbst nimmt zusätzlich Großschreibung, "med"
# und ganze Zahlen an; die Vorgabe hier ist bewusst enger.
EFFORT_WERTE = ("low", "medium", "high", "xhigh", "max")
class Befund:
def __init__(self, schwere: str, ort: str, text: str) -> None:
@@ -163,7 +189,7 @@ def rollentabelle(text: str) -> dict[str, str]:
"""Liest die Zuordnung Agent -> Modellalias aus der Tabelle im Stamm.
Eine Zeile sieht so aus:
| Planen, Spezifizieren | `planer` | Opus 5 (`opus`) |
| Planen, Spezifizieren | `planer` | Opus 5.5 (`opus`) | `high` (Frontmatter) |
Genommen wird der erste Backtick-Ausdruck der Agenten- und der
Modellspalte. Zeilen ohne Backticks in der Agentenspalte (etwa
'Hauptsitzung') werden übersprungen.
@@ -184,6 +210,52 @@ def rollentabelle(text: str) -> dict[str, str]:
return zuordnung
def entquotet(wert: str) -> str:
"""Nimmt passende einfache oder doppelte Anführungszeichen ab: 'high' -> high."""
if len(wert) >= 2 and wert[0] == wert[-1] and wert[0] in ("'", '"'):
return wert[1:-1]
return wert
def effort_spalte(text: str) -> int | None:
"""Findet den Index der Effort-Spalte in der Rollentabelle im Stamm.
Gesucht wird die Tabellenzeile, deren Zellen (getrimmt) sowohl 'Agent'
als auch 'Effort' enthalten — das ist die Kopfzeile. Der Index der Zelle
'Effort' ist die Effort-Spalte.
"""
for zeile in text.split("\n"):
if not zeile.startswith("|"):
continue
spalten = [s.strip() for s in zeile.strip("|").split("|")]
if "Agent" in spalten and "Effort" in spalten:
return spalten.index("Effort")
return None
def rollentabelle_effort(text: str, spalte: int) -> dict[str, str]:
"""Liest den Effort je Agent aus der Rollentabelle im Stamm.
Genommen wird der erste Backtick-Ausdruck der Effort-Spalte (`spalte`).
Fehlt ein Backtick-Ausdruck, ist der Wert für diesen Agenten leer.
"""
zuordnung: dict[str, str] = {}
for zeile in text.split("\n"):
if not zeile.startswith("|"):
continue
spalten = [s.strip() for s in zeile.strip("|").split("|")]
if len(spalten) <= spalte:
continue
agenten = BACKTICK.findall(spalten[1])
if not agenten:
continue
effort_treffer = BACKTICK.findall(spalten[spalte])
wert = effort_treffer[0].strip() if effort_treffer else ""
for name in agenten:
zuordnung[name.strip()] = wert
return zuordnung
def stamm_regelwerkverweise(text: str) -> set[str]:
"""Alle im Stamm verlinkten Regelwerk-Dateien, als Dateiname ohne Endung."""
namen: set[str] = set()
@@ -252,7 +324,13 @@ def pruefe_freigabe(vault: Path, befunde: list[Befund]) -> None:
)
def pruefe_modelle(vault: Path, tabelle: dict[str, str], befunde: list[Befund]) -> None:
def pruefe_modelle(
vault: Path,
tabelle: dict[str, str],
effort_index: int | None,
effort_tabelle: dict[str, str],
befunde: list[Befund],
) -> None:
for datei in sorted((vault / AGENTEN).glob("*.md")):
rel = datei.relative_to(vault).as_posix()
fm = frontmatter(lies(datei))
@@ -278,6 +356,47 @@ def pruefe_modelle(vault: Path, tabelle: dict[str, str], befunde: list[Befund])
)
)
# Effort: nur prüfbar, wenn die Effort-Spalte der Rollentabelle
# gefunden wurde (siehe main() für den Befund am Stamm, falls nicht).
if effort_index is None:
continue
soll = effort_tabelle.get(name, "")
if not soll:
befunde.append(
Befund("wichtig", "CLAUDE.md", f"Rollentabelle nennt für '{name}' keinen Effort")
)
effort_roh = fm.get("effort")
if not effort_roh:
befunde.append(
Befund(
"wichtig",
rel,
"kein effort: im Frontmatter — der Agent erbt den Effort der Hauptsitzung",
)
)
continue
effort_wert = entquotet(effort_roh)
if not effort_wert:
befunde.append(
Befund(
"wichtig",
rel,
"kein effort: im Frontmatter — der Agent erbt den Effort der Hauptsitzung",
)
)
elif effort_wert not in EFFORT_WERTE:
befunde.append(
Befund(
"blockierend",
rel,
f"effort: {effort_wert} ist nicht in der Vorgabe (erlaubt: low, medium, high, xhigh, max)",
)
)
elif soll and effort_wert != soll:
befunde.append(
Befund("blockierend", rel, f"effort: {effort_wert} — Rollentabelle im Stamm sagt {soll}")
)
def pruefe_planablage(vault: Path, dateien: list[Path], befunde: list[Befund]) -> None:
for datei in dateien:
@@ -339,6 +458,17 @@ def main() -> int:
Befund("blockierend", "CLAUDE.md", "keine Regelwerk-Verweise gefunden — Prüfung 3 kann nicht laufen")
)
effort_index = effort_spalte(stammtext) if tabelle else None
if tabelle and effort_index is None:
befunde.append(
Befund(
"blockierend",
"CLAUDE.md",
"Effort-Spalte der Rollentabelle nicht auffindbar — Prüfung 5 kann den Effort nicht prüfen",
)
)
effort_tabelle = rollentabelle_effort(stammtext, effort_index) if effort_index is not None else {}
dateien = dateien_im_geltungsbereich(vault)
pruefe_wikilinks(vault, dateien, befunde); gelaufen += 1
@@ -347,7 +477,7 @@ def main() -> int:
pruefe_erreichbarkeit(vault, verlinkt, befunde); gelaufen += 1
pruefe_freigabe(vault, befunde); gelaufen += 1
if tabelle and (vault / AGENTEN).is_dir():
pruefe_modelle(vault, tabelle, befunde); gelaufen += 1
pruefe_modelle(vault, tabelle, effort_index, effort_tabelle, befunde); gelaufen += 1
pruefe_planablage(vault, dateien, befunde); gelaufen += 1
except SystemExit: