Automatischer Push: 46 Datei(en) geändert

- .claude/agents/planer.md
- .claude/settings.json
- .claude/workflows/executer-welle.js
- .claude/workflows/plankritik.js
- .claude/workflows/planung.js
- .claude/workflows/quorum.js
- .claude/workflows/verbrauch.js
- .claude/workflows/welle-mit-pruefung.js
- .vault-tools/shell-wache/ENTWURF.md
- .vault-tools/shell-wache/docs/code/shell_wache.md
- .vault-tools/shell-wache/docs/plans/2026-10-30-shell-wache/00-uebersicht.md
- .vault-tools/shell-wache/docs/plans/2026-10-30-shell-wache/task-01-shell-wache.md
- … und 34 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-10-31 03:00:01 +01:00
1 parent f2ccec39d6
commit 13213ea0ac
46 files changed
+2380 -48

No files matched your search

+3 -2
View File
@@ -9,7 +9,8 @@ export const meta = {
// aus dem Frontmatter von .claude/agents/executer.md (medium); ein effort im Task überschreibt
// ihn, etwa low für Abschrift mit typografischen Zeichen. Ein Opus-Task ist die Hochstufung
// nach zwei Fehlschlägen und läuft ohne Angabe auf high statt auf dem medium des Executers.
// Haiku kennt keinen Effort.
// Bei haiku verwirft effortFuer() einen Task-Effort; es gilt das medium aus dem Frontmatter,
// das Haiku 5.5 auch erhält (AI/Regelwerk/haiku-5-5.md, A1 und A7).
const MODELLE = ['haiku', 'sonnet', 'opus']
const EFFORTS = ['low', 'medium', 'high', 'xhigh', 'max']
const OPUS_PARALLEL = 2
@@ -72,7 +73,7 @@ ${a.zusatz ? a.zusatz + '\n' : ''}Übertrage deinen Schlussbericht in die Felder
function effortFuer(t) {
if (t.modell === 'haiku') {
if (t.effort) log(`${t.datei}: effort ${t.effort} bei haiku wirkungslos, nicht gesetzt`)
if (t.effort) log(`${t.datei}: effort ${t.effort} bei haiku nicht gesetzt, es gilt das medium aus dem Frontmatter des executer`)
return undefined
}
if (t.effort) return t.effort
+5 -3
View File
@@ -31,6 +31,8 @@ export const meta = {
// Frontmatter von .claude/agents/pruefer.md; args.effort überschreibt ihn nur bewusst.
// Der Hilfsagent hat keinen agentType und bekommt deshalb seinen Effort mit (low: gemessen
// gleich treu wie high bei mechanischer Arbeit, codeworkflow.md "Effort je Rolle").
// Modell: werkzeug:kopie läuft auf haiku, weil nur kopieAusLauf() die Ausgabe liest. Planwerkzeuge und
// Mutantenlauf bleiben auf sonnet: ihre Rohausgabe geht wörtlich an die Linsen.
// Opus-Plätze: Vor den Linsen und vor der Widerlegung liest verbrauch.js den Planverbrauch ab.
// Die Linsen laufen mit so vielen Plätzen, wie verbrauch.js erlaubt (höchstens so viele wie
// Linsen, höchstens LINSEN_HOECHSTENS), die Widerlegung mit höchstens zwei. Gebremst heißt: Die
@@ -164,14 +166,14 @@ async function ablesen(anlass, wunsch) {
return r
}
function werkzeugAgent(label, phase, befehl, zweck, zusatz) {
function werkzeugAgent(label, phase, befehl, zweck, zusatz, modell = 'sonnet') {
return agent(`Du führst einen Werkzeugbefehl aus und gibst seine Ausgabe roh zurück. Zweck: ${zweck}
Führe genau diesen Befehl einmal im Bash-Werkzeug (Git-Bash) aus, unverändert:
${befehl}
${zusatz ? '\n' + zusatz + '\n' : ''}
Ändere keine Datei außer denen, die der Befehl selbst anlegt. Deute nichts und fasse nichts zusammen. Gib Befehl, Exit-Code und die vollständige Ausgabe zurück; bei mehr als 200 Zeilen die ersten 60 und die letzten 120, mit einer Zeile "[... N Zeilen gekürzt ...]" dazwischen.`,
{ label, phase, schema: LAUF, model: 'sonnet', effort: 'low' })
{ label, phase, schema: LAUF, model: modell, effort: 'low' })
}
function testort(ctx) {
@@ -259,7 +261,7 @@ if (!ctx.kopie && args.materialisieren) {
? `TASKS=(${liste})`
: `shopt -s nullglob; pushd ${q(args.planordner)} >/dev/null && TASKS=(task-*.md) && popd >/dev/null; [ \${#TASKS[@]} -gt 0 ] || { echo "KEINE_TASKS: im Planordner liegt keine task-*.md; materialisieren.tasks angeben"; exit 3; }`
const befehl = `${auswahl}; T=$(mktemp -d) && echo "KOPIE=$(cygpath -m "$T/mat")" && ${PY} ${q(W + '/kopie_bauen.py')} ${q(args.projekt)} "$T/mat" --ohne ${args.materialisieren.ohne.map(q).join(' ')} && ${PY} ${q(W + '/plan_materialisiere.py')} ${q(args.planordner)} "$T/mat" "\${TASKS[@]}"`
const r = await werkzeugAgent('werkzeug:kopie', 'Vorbereitung', befehl, 'Kopie des Projekts bauen und den Plan darauf anwenden')
const r = await werkzeugAgent('werkzeug:kopie', 'Vorbereitung', befehl, 'Kopie des Projekts bauen und den Plan darauf anwenden', '', 'haiku')
ctx.kopie = kopieAusLauf(r, 'Plankritik')
vorbereitung.push(r)
}
+7 -3
View File
@@ -1,12 +1,12 @@
export const meta = {
name: 'planung',
description: 'Erstplanung: je Task ein planer, gestartet, sobald die Taskdateien seiner Voraussetzungen geschrieben sind; Opus-Plätze nach Verbrauch, vorgegeben zwei',
whenToUse: 'Schritt 2 der Standardschleife, wenn 00-uebersicht.md mit der Tasktabelle steht und viele Taskdateien zu schreiben sind (AI/Regelwerk/codeworkflow.md, "Verbrauch und Opus-Plätze"). Nicht für Nachbesserungen. Args: {projekt, planordner, gemeinsam, taskauftrag, tasks: [{nr, thema, datei, modell, voraussetzungen: [nr], welle?}], erledigt?: [nr], plaetze?: 1..4, nachlesen_alle?: 1..20, zusatz?}. plaetze ist der Wunsch, verbrauch.js senkt ihn; ohne plaetze gilt zwei, drei oder vier erst nach der Eichung der Stufen. taskauftrag darf {NR}, {THEMA}, {DATEI}, {MODELL}, {WELLE} und {VORAUSSETZUNGEN} enthalten. Rückgabe mit status fertig, unvollstaendig, gebremst oder abgebrochen; offene Tasks mit erledigt in einem neuen Lauf nachholen, nicht mit resumeFromRunId. Die Plankritik läuft danach als eigener Workflow.',
whenToUse: 'Schritt 2 der Standardschleife, wenn 00-uebersicht.md mit der Tasktabelle steht und viele Taskdateien zu schreiben sind (AI/Regelwerk/codeworkflow.md, "Verbrauch und Opus-Plätze"). Nicht für Nachbesserungen. Args: {projekt, planordner, gemeinsam, taskauftrag, tasks: [{nr, thema, datei, modell, voraussetzungen: [nr], welle?}], erledigt?: [nr], plaetze?: 1..4, nachlesen_alle?: 1..20, effort?, zusatz?}. effort überschreibt den Effort aller Planer bewusst, etwa für die Messung medium gegen high; ohne effort gilt das Frontmatter von planer.md. plaetze ist der Wunsch, verbrauch.js senkt ihn; ohne plaetze gilt zwei; drei oder vier sind seit der Eichung der Stufen am 2026-10-30 frei. taskauftrag darf {NR}, {THEMA}, {DATEI}, {MODELL}, {WELLE} und {VORAUSSETZUNGEN} enthalten. Rückgabe mit status fertig, unvollstaendig, gebremst oder abgebrochen; offene Tasks mit erledigt in einem neuen Lauf nachholen, nicht mit resumeFromRunId. Die Plankritik läuft danach als eigener Workflow.',
phases: [{ title: 'Taskdateien', detail: 'planer je Task, Start nach den Voraussetzungen, Plätze nach Verbrauch' }],
}
// Rollenparameter: model wird immer gesetzt (Stamm), der Effort kommt aus dem Frontmatter von
// .claude/agents/planer.md. Ein Task startet erst, wenn die Planer aller seiner Voraussetzungen
// .claude/agents/planer.md; args.effort überschreibt ihn nur bewusst (Messplan A2). Ein Task startet erst, wenn die Planer aller seiner Voraussetzungen
// ein Ergebnis geliefert haben; sonst erfindet er Namen, die ein Vorgänger anders schreibt
// (codeworkflow.md, "Verbrauch und Opus-Plätze"). Die Zahl gleichzeitiger Planer liest
// verbrauch.js am Anfang und nach je nachlesen_alle fertigen Planern ab. Gebremst heißt: Kein
@@ -14,8 +14,9 @@ export const meta = {
// ohne Ergebnis startet keiner mehr, meist ist dann das Kontingent erschöpft. Ein Ergebnis zählt
// nur, wenn es die erwartete Taskdatei nennt; sonst gilt der Task als gescheitert.
// VORGABE_PLAETZE ist Stufe 1 der Freigabe vom 2026-09-24 (Pool mit zwei Plätzen). Stufe 3 mit
// drei bis vier Plätzen für die Erstplanung kommt erst nach der Eichung der Stufen in verbrauch.js.
// drei bis vier Plätzen über plaetze hat Pascal nach der Eichung am 2026-10-30 freigegeben.
const MODELLE = ['haiku', 'sonnet', 'opus']
const EFFORTS = ['low', 'medium', 'high', 'xhigh', 'max']
const HOECHSTENS = 4
const VORGABE_PLAETZE = 2
const OHNE_ABLESUNG = 2
@@ -60,6 +61,7 @@ function pruefeArgs(a) {
}))
if (a.erledigt !== undefined && !(Array.isArray(a.erledigt) && a.erledigt.every(n => nummern.has(n)))) throw new Error('planung: erledigt muss eine Liste bekannter Tasknummern sein')
if (a.plaetze !== undefined && !(Number.isInteger(a.plaetze) && a.plaetze >= 1 && a.plaetze <= HOECHSTENS)) throw new Error('planung: plaetze muss eine ganze Zahl von 1 bis ' + HOECHSTENS + ' sein')
if (a.effort !== undefined && !EFFORTS.includes(a.effort)) throw new Error('planung: effort "' + a.effort + '" ungültig')
if (a.nachlesen_alle !== undefined && !(Number.isInteger(a.nachlesen_alle) && a.nachlesen_alle >= 1 && a.nachlesen_alle <= 20)) throw new Error('planung: nachlesen_alle muss eine ganze Zahl von 1 bis 20 sein')
// Zyklen: Kahn-Verfahren über die Voraussetzungen; was übrig bleibt, hängt im Kreis.
const offen = new Map(a.tasks.map(t => [t.nr, t.voraussetzungen.length]))
@@ -134,6 +136,7 @@ const nochOffen = () => [...status.values()].some(s => s === 'offen')
function starte(t) {
status.set(t.nr, 'laeuft')
const opts = { label: `planer:task-${String(t.nr).padStart(2, '0')}`, phase: 'Taskdateien', schema: TASK_SCHEMA, agentType: 'planer', model: 'opus' }
if (args.effort) opts.effort = args.effort
laufend.set(t.nr, agent(auftrag(args, t, jeNr), opts).then(r => ({ nr: t.nr, r }), e => ({ nr: t.nr, r: null, fehler: e && e.message })))
}
@@ -199,6 +202,7 @@ const offen = liste('offen')
const zustand = gebremst ? 'gebremst' : abgebrochen ? 'abgebrochen' : gescheitert.length || blockiert.length || offen.length ? 'unvollstaendig' : 'fertig'
return {
status: zustand,
effort: args.effort || '(Frontmatter)',
geschrieben,
gescheitert,
blockiert,
+6 -5
View File
@@ -15,7 +15,7 @@ export const meta = {
// der Ablauf gebaut ist. Plan: .vault-tools/workflow-pruefung/docs/plans/2026-09-29-quorum/.
//
// Paket: Ein Workflow-Skript hat weder Dateisystem noch Shell. Das Prüfpaket baut deshalb ein
// Hilfsagent (sonnet, low), der genau einen Befehl fährt: quorum_werkzeug.py paket. Das Skript
// Hilfsagent (haiku, low), der genau einen Befehl fährt: quorum_werkzeug.py paket. Das Skript
// entscheidet, ob der Unterschied leer ist; der Hilfsagent überträgt nur die Ausgabe.
// Die Zeile QUORUM_PAKET trägt nur Felder fester Größe. Dateiliste und Stand-Liste bleiben in
// paket.json; den Stand setzt quorum_werkzeug.py ablegen beim Ablegen des Berichts aus paket.json
@@ -32,8 +32,9 @@ export const meta = {
// "usage limit" im Log des Jobs und zieht die Antwort heraus.
// - Gültig ist die Codex-Stimme nur mit gelesenem Status vor dem Lauf, Job completed, gelesenem
// Log ohne "usage limit" und einem Lesebeleg mit der Lesemarke aus paket.md. Sonst Haiku.
// - Die Codex-Hilfsagenten laufen auf sonnet mit low: feste Befehle, Ausgaben übertragen. Haiku
// nicht, weil Befundtexte typografische Zeichen tragen können, die Haiku still ersetzt.
// - Die Hilfsagenten für Paket und Codex laufen auf haiku mit low: feste Befehle, das Skript liest nur
// Marken und Felder. Haiku 4.5 ersetzte typografische Zeichen still; Haiku 5.5 hielt sie in 6 von 6
// Läufen (AI/Regelwerk/haiku-5-5.md, A3). codex:ende überträgt Befundtexte, der Byte-Vergleich fehlt dort.
// Zusammenführen: Ein Sonnet-Agent ohne agentType gruppiert nur belegte Befunde; das Skript teilt
// jede Gruppe nach Datei und Zeilen in zusammenhängende Teilgruppen (Funktion teilgruppen) und
// zählt die Stimmen. Mehrheit heißt zwei verschiedene Stimmen, die Schwere der Gruppe ist die
@@ -161,7 +162,7 @@ Führe genau diesen Befehl einmal im Bash-Werkzeug (Git-Bash) aus, unverändert:
${befehl}
${zusatz ? '\n' + zusatz + '\n' : ''}
Ändere keine Datei außer denen, die der Befehl selbst anlegt. Deute nichts und fasse nichts zusammen. Gib Befehl, Exit-Code und die vollständige Ausgabe zurück; bei mehr als 200 Zeilen die ersten 60 und die letzten 120, mit einer Zeile "[... N Zeilen gekürzt ...]" dazwischen.`,
{ label, phase, schema: LAUF, model: 'sonnet', effort: 'low' })
{ label, phase, schema: LAUF, model: 'haiku', effort: 'low' })
}
function ausgabe(r) {
@@ -320,7 +321,7 @@ async function codexStimme(a, p) {
z.grund = gescheitert ? 'Warten auf Codex gescheitert, Auftrag abgebrochen' : `nach ${runden} Warterunden nicht fertig, Auftrag abgebrochen`
return z
}
const e = await agent(codexEndeAuftrag(a, p, z.job), { label: 'codex:ende', phase: 'Stimmen', schema: CODEX, model: 'sonnet', effort: 'low' })
const e = await agent(codexEndeAuftrag(a, p, z.job), { label: 'codex:ende', phase: 'Stimmen', schema: CODEX, model: 'haiku', effort: 'low' })
if (e && Number.isInteger(e.dauer_s)) z.dauer_s = e.dauer_s
const ungueltig = codexUngueltig(e, p)
if (ungueltig) {
+10 -2
View File
@@ -13,8 +13,16 @@ export const meta = {
// und resetsAt. Von 19 typisierten Limit-Abbrüchen im Session-Speicher (22.08. bis 20.09.)
// waren 16 five_hour und 3 seven_day, keiner seven_day_opus. Ein Fenster "Weekly · Opus" zählt
// trotzdem wie die Woche, falls es auftaucht, weil die Agenten, um die es geht, auf Opus laufen.
// - Die Stufen: Projektvorgabe, vorläufig (Pascal, 2026-09-24). Sie stehen nur hier und werden
// nach der Messreihe mit .vault-tools/workflow-pruefung/verbrauch_reihe.py nachgestellt.
// - Die Stufen: Projektvorgabe (Pascal, 2026-09-24), geeicht am 2026-10-30 und von Pascal
// unverändert bestätigt. Messreihe verbrauch_reihe.py, Ablesungen nach Plan und Konto getrennt
// (Max-Plan, zwei Konten, 406 Paare, 232 Opus-Agentenstunden): rund 9 bis 10 % des
// 5-Stunden-Fensters und 2,5 % der Woche je Opus-Agentenstunde, andere Sitzungen eingerechnet.
// Ein Paar aufeinanderfolgender Ablesungen, meist eine Staffel, hob das Fenster im Median um 3
// bis 5 Punkte, im P90 um 9 bis 14, in der Spitze um 33 bis 42. Nach einer P90-Staffel bleiben
// damit bei 4 Plätzen mindestens 36 Punkte Abstand zu 100 %, bei 2 mindestens 16, bei 1 nur
// rund 2. Die Wochenstufen halten Reserve für den Rest der Woche, eine Staffel mit vier
// Opus-Agenten kostet rund 5 Wochenpunkte. Für vier gleichzeitige Opus-Agenten gab es nur zwei
// Paare. Belege: .vault-tools/workflow-pruefung/LIESMICH.md. Die Stufen stehen nur hier.
// - Ohne lesbare Ablesung: Projektvorgabe, die bisherige Stammregel von zwei Opus-Agenten.
// - Ob der Ableser abgelesen hat: Quelle. Der Auftrag schreibt im Fehlerfall status "fehler",
// plan "" und fenster [] vor; get_usage kennt laut Werkzeugbeschreibung (gelesen 2026-10-16)
+5 -3
View File
@@ -14,6 +14,8 @@ export const meta = {
// Aufträge und Rollenparameter an genau einer Stelle stehen. Der Hilfsagent hat keinen
// agentType und bekommt seinen Effort deshalb mit (low). Opus läuft nur in den Kindern,
// und die laufen nacheinander; die Obergrenze von zwei hält executer-welle selbst.
// Modell: werkzeug:kopie läuft auf haiku, weil nur das Skript die Ausgabe liest. werkzeug:vergleich
// bleibt auf sonnet: seine Rohausgabe geht an den pruefer.
// Verbrauch: Vor und nach der Prüfung liest dieser Workflow den Planverbrauch über verbrauch.js
// ab (nur messen); das Kind pruefung bekommt verbrauch: false, weil ein Kind keinen weiteren
// Workflow aufrufen kann.
@@ -53,14 +55,14 @@ function pruefeArgs(a) {
}
}
function werkzeugAgent(label, phase, befehl, zweck) {
function werkzeugAgent(label, phase, befehl, zweck, modell = 'sonnet') {
return agent(`Du führst einen Werkzeugbefehl aus und gibst seine Ausgabe roh zurück. Zweck: ${zweck}
Führe genau diesen Befehl einmal im Bash-Werkzeug (Git-Bash) aus, unverändert:
${befehl}
Ändere keine Datei außer denen, die der Befehl selbst anlegt. Deute nichts und fasse nichts zusammen. Gib Befehl, Exit-Code und die vollständige Ausgabe zurück; bei mehr als 200 Zeilen die ersten 60 und die letzten 120, mit einer Zeile "[... N Zeilen gekürzt ...]" dazwischen.`,
{ label, phase, schema: LAUF, model: 'sonnet', effort: 'low' })
{ label, phase, schema: LAUF, model: modell, effort: 'low' })
}
// Anfang und Ende behalten: Das Ergebnis der Suite steht am Schluss.
@@ -94,7 +96,7 @@ const fehler = []
phase('Kopie')
if (!kopie) {
const befehl = `T=$(mktemp -d) && echo "KOPIE=$(cygpath -m "$T/mat")" && ${PY} ${q(W + '/kopie_bauen.py')} ${q(args.projekt)} "$T/mat" --ohne ${args.ohne.map(q).join(' ')} && ${PY} ${q(W + '/plan_materialisiere.py')} ${q(args.planordner)} "$T/mat" ${taskdateien.map(q).join(' ')}`
const r = await werkzeugAgent('werkzeug:kopie', 'Kopie', befehl, 'Stand vor der Welle kopieren und die Taskdateien der Welle darauf anwenden')
const r = await werkzeugAgent('werkzeug:kopie', 'Kopie', befehl, 'Stand vor der Welle kopieren und die Taskdateien der Welle darauf anwenden', 'haiku')
belege.kopie = r
const lauf = r && r.laeufe && r.laeufe[0]
const m = lauf && /^KOPIE=(.+?)\s*$/m.exec(lauf.ausgabe)