Erster Stand des öffentlichen Ausschnitts aus dem Vault. Die .gitignore arbeitet als Positivliste: ausgeschlossen ist alles, eingeschlossen nur, was ausdrücklich wieder aufgenommen wird. Notizen, Projekte, Finanzen, das Sitzungsgedächtnis und settings.local.json bleiben damit außen vor. Der Kundenname in AI/Regelwerk/seo.md ist durch eine neutrale Bezeichnung ersetzt; die Regeln selbst sind unverändert. Co-Authored-By: Claude Opus 5 <[email protected]>
17 KiB
type, title, status, summary, tags, created, updated
| type | title | status | summary | tags | created | updated | ||
|---|---|---|---|---|---|---|---|---|
| plan | Sitzungs-Hooks und Schließzaun im Linkcheck | active | Nach dem Plan gibt ein SessionStart-Hook den Stand des Sitzungsprotokolls als Kontext aus, ein PostToolUse-Hook startet den Regelwerk-Check nach Änderungen an der Anweisungsschicht, und der Linkcheck schließt Codeblöcke nach CommonMark. |
|
2026-09-13 | 2026-09-13 |
Sitzungs-Hooks und Schließzaun im Linkcheck
Ziel
Nach diesem Plan liegen zwei Hook-Skripte unter .vault-tools/session-hooks/, jedes mit Regressionstreiber. sitzungsstart.py zählt zu Sitzungsbeginn, was das Sitzungsprotokoll in CLAUDE.md verlangt, und gibt es als Kontext aus. regelwerk_nach_edit.py startet regelwerk_check.py, sobald eine Datei von Stamm, Regelwerk, Agenten oder Skills geändert wurde, und meldet Befunde, eine fehlende, abstürzende oder hängende Prüfung. Außerdem schließt strip_code() im Linkcheck einen Codeblock nur noch mit einem passenden Zaun. Damit verschwindet der Fehlalarm [[:space:]] in Code Projekte/active - Logging/docs/plans/2026-09-08-a-betriebsmodelle/task-09-gate.md. Wirksam in Claude Code werden die Hooks erst mit dem Eintrag in settings.json, und der ist nicht Teil dieses Plans.
Nicht im Umfang
- Einträge in
.claude/settings.jsonoder.claude/settings.local.json. Die macht der Koordinator nach der Prüfung. - Jede Änderung außerhalb von
.vault-tools/session-hooks/und.vault-tools/linkcheck/. Auch der Kommentar inregelwerk_check.py, der die Zahl der Linkcheck-Fälle nennt, bleibt stehen. - Die Öffnerregel des Linkchecks (Backtick im Info-String). Sie ist im Entwurf als Lücke benannt.
CHANGELOG.md:.vault-tools/führt keins.
Architektur
Claude Code
SessionStart ──stdin JSON──> sitzungsstart.py ──stdout JSON──> additionalContext
│
└─ importiert strip_code() aus linkcheck/linkcheck.py
PostToolUse (Edit|Write|MultiEdit)
──stdin JSON──> regelwerk_nach_edit.py
│ Pfad im Geltungsbereich? nein -> still
└─ startet regelwerk-check/regelwerk_check.py --vault <wurzel>
ohne Befund -> still
sonst -> stdout JSON (additionalContext, systemMessage)
linkcheck/linkcheck.py strip_code() <── auch von regelwerk_check.py importiert
Beide Hooks enden immer mit Exit 0. Entscheidungen und Herkunft stehen in .vault-tools/session-hooks/ENTWURF.md (entsteht in Task 1), die Regel zum Schließzaun in .vault-tools/linkcheck/ENTWURF-codeblock-erkennung.md (Task 3).
Globale Vorgaben
Diese Vorgaben gelten für jeden Task. Die Taskdateien verweisen hierher und wiederholen sie nicht.
- Abschrift, keine Autorschaft. Code und Texte aus dem Plan werden Zeichen für Zeichen übernommen. Wer einen Widerspruch im Plan findet, meldet ihn und löst ihn nicht still auf. Kommentare und Docstrings werden nicht umformuliert.
- Test zuerst. Erst den Treiber oder die Fälle anlegen, den Fehlschlag im Wortlaut beobachten und melden, dann die Umsetzung. Weicht der Fehlschlag vom Plan ab, anhalten und melden.
- Nur die Zieldateien des eigenen Tasks. Keine weiteren Dateien, keine Hilfsskripte im Vault. Temporäres gehört ins Temp-Verzeichnis, das der Treiber selbst anlegt und löscht.
- Shell. PowerShell, Arbeitsverzeichnis
D:\Claude. Vor jedem Python-Aufruf$env:PYTHONIOENCODING = "utf-8". Interpreter istpython, niepython3. Keinbash, kein Heredoc, keinpython -c, keinpython -. - Dateien. UTF-8 ohne BOM, Zeilenende LF. Nach dem Anlegen oder Ändern einer Python-Datei
python -m py_compile <datei>. - Nur Standardbibliothek, Python 3.13.
- Kein Commit. Der Vault-Root ist kein Git-Repository, und Subagenten committen nie.
- Keine Geheimnisse lesen.
.claude/settings.json,.claude/settings.local.jsonund Transkripte werden nicht geöffnet. - Schlägt ein Fall fehl, wird nicht am Code gedreht, bis er grün ist. Gemeldet werden Fall, vollständige Ausgabe und die vermutete Ursache. Die Korrektur passiert im Plan.
Dateiübersicht
| Datei | Task | Art |
|---|---|---|
.vault-tools/session-hooks/sitzungsstart.py |
1 | neu |
.vault-tools/session-hooks/faelle_sitzungsstart.py |
1 | neu |
.vault-tools/session-hooks/ENTWURF.md |
1 | neu |
.vault-tools/session-hooks/regelwerk_nach_edit.py |
2 | neu |
.vault-tools/session-hooks/faelle_nach_edit.py |
2 | neu |
.vault-tools/linkcheck/linkcheck.py |
3 | ändern |
.vault-tools/linkcheck/faelle.py |
3 | ändern |
.vault-tools/linkcheck/ENTWURF-codeblock-erkennung.md |
3 | ändern |
Tasks
| Nr | Datei | Zieldateien | Modell | parallel mit |
|---|---|---|---|---|
| 1 | task-01-sitzungsstart.md |
sitzungsstart.py, faelle_sitzungsstart.py, ENTWURF.md in session-hooks/ |
sonnet | 2, 3 |
| 2 | task-02-regelwerk-nach-edit.md |
regelwerk_nach_edit.py, faelle_nach_edit.py in session-hooks/ |
sonnet | 1, 3 |
| 3 | task-03-schliesszaun.md |
linkcheck.py, faelle.py, ENTWURF-codeblock-erkennung.md in linkcheck/ |
haiku | 1, 2 |
Die Zieldateien sind disjunkt, alle drei Tasks können gleichzeitig laufen. Eine Abhängigkeit gibt es zur Laufzeit: sitzungsstart.py importiert strip_code() aus linkcheck.py, das Task 3 ändert. Die Fälle von Task 1 hängen nicht von der Schließzaun-Regel ab, ein Lauf während einer halb geschriebenen Datei kann aber scheitern. Deshalb wiederholt die Abnahme den Treiber von Task 1 nach dem Ende von Task 3. Wer Nebenläufigkeit ganz vermeiden will, startet Task 3 zuerst, er ist der kleinste.
Vor dem Start (Koordinator)
Den Linkcheck einmal vor Task 3 laufen lassen und die Ausgabe sichern, sonst fehlt der Vergleich:
Set-Location D:\Claude
$env:PYTHONIOENCODING = "utf-8"
python .vault-tools\linkcheck\linkcheck.py --vault . --alle > "$env:TEMP\linkcheck-vorher.txt"; "exit=$LASTEXITCODE"
Laut Sitzungsprotokoll AI/sessions/2026-09-13-18.md meldete er 3 tote Links bei 1006 Notizen, einer davon der Fehlalarm in task-09-gate.md.
Abnahme
- Die Verifikationsbefehle aller drei Taskdateien selbst wiederholen, nicht aus dem Bericht übernehmen.
- Den Treiber von Task 1 nach dem Ende von Task 3 noch einmal fahren.
- Jede neu angelegte Datei byteweise gegen ihren Codeblock im Plan vergleichen, bei Task 3 jede ersetzte Stelle gegen den Neutext.
.vault-tools/plan-diff/plan_diff.pyerwartet eine andere Form der Pfadzeile, als diese Taskdateien sie haben. Ob es hier trägt, ist nicht geprüft, im Zweifel von Hand vergleichen. - Je Treiber mindestens einen Fall absichtlich kaputt machen und rot sehen. In
sitzungsstart.py(?<!\S)aus_NEEDS_REVIEWentfernen: Der Fall „aehnliche Tags zaehlen nicht" muss fallen. Inregelwerk_nach_edit.pydas+ "/"im Präfixvergleich streichen: Der Fall „Datei neben dem Vault mit gleichem Namensanfang" muss fallen. Der Fall „Nachbarordner mit gleichem Namensanfang" bleibt bei diesem Eingriff grün, weil der Rest des Pfads nicht passt; das ist kein blinder Fleck. Infaelle.pyvon Task 3 genügt der Blick auf die drei Fälle, die vor der Umsetzung rot waren. Danach alles zurücksetzen. - Lauf mit echten Daten wie unten.
Lauf mit echten Daten
Task 1. python .vault-tools\session-hooks\faelle_sitzungsstart.py --echt zweimal. Stand beim Planen, zum Vergleich:
- Tagesnotiz
Inbox/2026-09-13.mdvorhanden. - Inbox ohne
type: daily:2026-09-13-vernetzung-vault-claude.md. Die übrigen 28 Dateien inInbox/tragentype: daily. needs-review:Inbox/2026-09-13-vernetzung-vault-claude.mdüber den Frontmatter-Tag. Den Text#needs-reviewgab es beim Planen in 17 anderen Dateien. In den gelesenen Zeilen steht er in Backticks, auch inCLAUDE.mdZeile 118, oder in Zeilen, die zu Codebeispielen gehören; ob diese Zeilen in einem Fenced-Block liegen, wurde nicht geprüft. Nicht gelesen wurden zwei lange Zeilen:Code Projekte/active - Agentic Cockpit/docs/plans/2026-09-05-agentic-cockpit/task-04-vault-reader-teil-1.mdZeile 53 undCode Projekte/active - Agentic Cockpit/docs/code/vault_reader.mdZeile 26. Jeden Treffer des Hooks an seiner Zeile nachlesen. Steht das Tag dort ohne Backticks im Fließtext, stimmt der Treffer.reviewohnereview-done: Zahl gegenReview-Queue.basein Obsidian halten. Eine Abweichung muss sich aus den Ausschlüssen (Import/, Codeblöcke, Inline-Code) erklären lassen, sonst ist sie ein Befund.pending-review:pruefwerkzeuge.md.- Sitzungsdateien vom 2026-09-13: beim Planen
2026-09-13-16.md,2026-09-13-16b.md,2026-09-13-18.md, dazu alles, was seitdem entstanden ist. - Laufzeit beider Läufe unter 5 Sekunden.
Die Gegenprüfung für needs-review läuft mit eigener Suche, nicht mit dem Treiber: Grep über *.md nach needs-review, dann Ausschlüsse, Backticks und Codeblöcke von Hand abziehen.
Task 2. python .vault-tools\session-hooks\faelle_nach_edit.py --echt. Solange pruefwerkzeuge.md auf pending-review steht: systemMessage mit Exit 1, 1 Befundzeile(n) und im Kontext [klein] AI/Regelwerk/pruefwerkzeuge.md — status: pending-review — Freigabe steht aus. Danach einen Hook-Lauf mit einem Pfad außerhalb des Geltungsbereichs von Hand prüfen, er muss still bleiben:
Set-Location D:\Claude
$env:PYTHONIOENCODING = "utf-8"
'{"cwd": "D:\\Claude", "tool_name": "Edit", "tool_input": {"file_path": "D:\\Claude\\Inbox\\2026-09-13.md"}}' | python .vault-tools\session-hooks\regelwerk_nach_edit.py; "exit=$LASTEXITCODE"
Erwartet: nur exit=0, keine Zeile davor.
Task 3. Den Linkcheck nach Task 3 erneut fahren und gegen linkcheck-vorher.txt halten. Erwartet: Die Zeile mit task-09-gate.md -> [[:space:]] fehlt, alle anderen Befunde sind gleich. Dazu der Vergleich alte gegen neue Zaunerkennung über alle Notizen, weil der Linkcheck nur tote Links zeigt und ein jetzt verschluckter gültiger Link dort nicht auffällt. Das Skript gehört ins Scratchpad, nicht in den Vault:
"""Vergleicht alte und neue Zaunerkennung über den Vault: Welche Notizen liefern andere Wikilinks?
Nur für die Abnahme von Task 3, gehört nicht in den Vault.
"""
import re
import sys
VAULT = r"D:\Claude"
sys.path.insert(0, VAULT + r"\.vault-tools\linkcheck")
sys.path.insert(0, VAULT + r"\.vault-tools\obsidian-vault-navigator\scripts")
import vaultlib as V # noqa: E402
from linkcheck import strip_code as neu # noqa: E402
_FENCE_RE = re.compile(r"^\s{0,3}(`{3,}|~{3,})")
_INLINE_CODE_RE = re.compile(r"(`+)(?:(?!\1).)*?\1")
def alt(body):
"""strip_code() in der Fassung vor Task 3."""
if not body:
return ""
zaun = None
aus = []
for zeile in body.split("\n"):
m = _FENCE_RE.match(zeile)
if zaun is None:
if m:
zaun = m.group(1)[0] * 3
aus.append(" " * len(zeile))
continue
aus.append(_INLINE_CODE_RE.sub(lambda t: " " * len(t.group(0)), zeile))
else:
if m and m.group(1)[0] * 3 == zaun:
zaun = None
aus.append(" " * len(zeile))
return "\n".join(aus)
def links(text):
return {m.group(1).strip() for m in V._WIKILINK_RE.finditer(text)}
def main():
sys.stdout.reconfigure(encoding="utf-8")
geprueft = 0
anders = 0
for ap, rp in V.walk_vault(VAULT):
if not rp.endswith(".md"):
continue
with open(ap, "r", encoding="utf-8", errors="replace") as fh:
_, body = V.parse_frontmatter(fh.read())
geprueft += 1
a, n = links(alt(body)), links(neu(body))
if a != n:
anders += 1
print(rp)
print(" nur alt:", sorted(a - n))
print(" nur neu:", sorted(n - a))
print(f"{anders} von {geprueft} Notizen liefern andere Wikilinks.")
main()
Erwartet ist mindestens task-09-gate.md mit nur alt: [':space:']. Jede weitere Notiz mit nur alt: ist ein Link, den der Linkcheck nicht mehr sieht, und wird an der Stelle nachgelesen. Ist es ein echter Link hinter einem Block, den bisher eine Zeile mit Info-String versehentlich geschlossen hat, stimmt die neue Regel und die Notiz hat einen Zaunfehler. Ist es kein Zaunfehler, ist das ein Befund gegen Task 3.
Risiken
- Rauschen nach jedem Edit. Solange
pruefwerkzeuge.mdaufpending-reviewsteht, meldetregelwerk_nach_edit.pybei jeder Änderung an Stamm, Regelwerk, Agenten oder Skills denselben Befund. Das sieht man an dersystemMessage. Ein Hook, der immer anschlägt, wird überlesen. - SessionStart feuert öfter als gedacht. Ohne Matcher läuft der Hook auch bei
resume,clear,compactundforkund legt denselben Kontext erneut ab. Die Laufzeit fällt dann jedes Mal an. - Verschluckte Links. Ein Block, den bisher eine Zeile mit Info-String versehentlich geschlossen hat, läuft nach Task 3 weiter, notfalls bis Dateiende. Der Linkcheck prüft die Links dahinter dann nicht mehr. Sichtbar macht das nur der Vergleichslauf oben.
- Timeout-Reihenfolge.
regelwerk_nach_edit.pybricht den Check nach 20 Sekunden selbst ab. Setzt dersettings.json-Eintrag eintimeoutunter etwa 25 Sekunden, beendet Claude Code den Hook, bevor er melden kann, und die Meldung fehlt. - Falsche Wurzel. Beide Hooks nehmen
cwdaus der Eingabe. Läuft eine Sitzung mit einem anderencwdalsD:\Claudeund greift der Eintrag trotzdem, zeigtsitzungsstart.pydas in der Kopfzeile.regelwerk_nach_edit.pybleibt dann bei Vault-Dateien still, und das sieht niemand. Ob Einträge ausD:\Claude\.claude\settings.jsonbei einem anderen Startordner überhaupt geladen werden, ist nicht geprüft. - Laufzeit. Die 5 Sekunden sind ein Ziel, gemessen wird am echten Vault. Bei kaltem Dateicache oder wachsendem Vault kann
sitzungsstart.pylänger brauchen. Der erste--echt-Lauf zeigt eher den kalten Wert, der zweite den warmen. - Mitternacht. Die Treiber rechnen das Datum einmal beim Start. Läuft ein Treiber über Mitternacht, schlagen datumsabhängige Fälle fehl, ohne dass am Hook etwas falsch ist.
- Regressionslauf des Regelwerk-Checks.
.vault-tools/regelwerk-check/regressionslauf.pybricht nach dem Code schon heute an der Grundlinie ab, weil die Kopie des Regelwerkspruefwerkzeuge.mdmitpending-reviewenthält. Das ist aus dem Code gelesen, nicht gefahren, und hat mit Task 3 nichts zu tun. Ein Abbruch dort ist kein Beleg gegen Task 3. - Python auf dem PATH. Die Exec-Form startet
pythonüber den PATH. Ändert sich der PATH, scheitert der Hook mit einem Exit ungleich 0. Claude Code meldet das als nicht blockierenden Fehler, die Hook-Ausgabe fehlt dann.
Getroffene Annahmen
- Inbox-Notizen werden auch in Unterordnern von
Inbox/gezählt, nur.md-Dateien, Punktordner ausgenommen. - Die Zählung
reviewohnereview-donehat dieselben Ausschlüsse wieneeds-review(Import/,_index/, Punktordner,node_modules). Import/und_index/fallen nur direkt unter der Wurzel heraus, Punktordner undnode_modulesin jeder Tiefe.- Tags werden ohne Rücksicht auf Groß- und Kleinschreibung verglichen. Ein Inline-Tag steht am Zeilenanfang oder nach Leerraum.
#needs-review/xund#needs-review-donezählen nicht alsneeds-review. - Kaputtes YAML wird tolerant gelesen: Ein Tag in einer nicht geschlossenen Liste zählt. Ein Frontmatter ohne Schlusszeile gilt nicht als Frontmatter.
regelwerk_nach_edit.pybestimmt die Wurzel wiesitzungsstart.py(cwd, sonst zwei Ebenen über dem Skript).- Ein relativer
file_pathgilt relativ zur Wurzel. Der Pfadvergleich ignoriert Groß- und Kleinschreibung im ganzen Pfad, nicht nur beim Laufwerk. - Still bleibt der Regelwerk-Hook nach dem Check nur bei Exit 0 mit der Schlusszeile „Keine der N gelaufenen Prüfungen hat angeschlagen." und ohne
ACHTUNG-Zeile. Exit 0 mitACHTUNGist ein Befund. - Interner Timeout 20 Sekunden, Kontext höchstens 40 Zeilen und 4000 Zeichen.
tool_namewird nicht geprüft, das übernimmt der Matcher.ENTWURF.mdfür beide Hooks gehört zu Task 1, damit die Zieldateien disjunkt bleiben.- Jeder Punkt des Sitzungsstart-Hooks läuft in einem eigenen
try. Das geht über den Auftrag hinaus, dort war nur ein Fehler insgesamt verlangt. - Der Wortlaut der CommonMark-Spezifikation wurde nicht gezogen. Die Schließzaun-Regel ist an markdown-it-py 4.2.0 belegt, das lokal im Projekt Agentic Cockpit liegt.
- In
ENTWURF-codeblock-erkennung.mdwird die gepflegte Zahl „vierzehn Angriffsfälle" durch „alle Angriffsfälle ausfaelle.py" ersetzt.
Offene Punkte für den Koordinator
settings.json-Einträge: Matcher für SessionStart (alle Quellen oder nurstartupundclear) und eintimeoutvon mindestens 30 Sekunden für den PostToolUse-Eintrag.- Das Rauschen durch
pruefwerkzeuge.mdaufpending-review: freigeben lassen oder für die Zeit bis zur Freigabe hinnehmen. - Den Abschnitt 4.5 der CommonMark-Spezifikation 0.31.2 gegen die Regel in
ENTWURF-codeblock-erkennung.mdhalten und den Vermerk „Abgleich offen" danach streichen oder korrigieren. regelwerk_check.pynennt im Kommentar 17 Linkcheck-Fälle, nach Task 3 sind es mehr. Die Datei liegt außerhalb dieses Plans.regressionslauf.pydes Regelwerk-Checks bricht wegenpending-reviewan der Grundlinie ab. Das ist unabhängig von diesem Plan, verdeckt aber jeden Regressionsnachweis dort.