.vault-tools (ohne trading-plattform-pruefung und watermarks-remover), .claude/agents, .claude/skills, .claude/workflows, .claude/settings.json. Co-Authored-By: Claude Opus 5.5 <[email protected]>
9.9 KiB
9.9 KiB
type, title, status, summary, tags, created, updated, modell, effort, modell_begruendung
| type | title | status | summary | tags | created | updated | modell | effort | modell_begruendung | |||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| plan-task | Task 01 — verbrauch.js: Planverbrauch lesen und Opus-Plätze rechnen | draft | Neuer gespeicherter Workflow, der über get_usage das 5-Stunden-Fenster und die Woche abliest und daraus die erlaubten Opus-Plätze rechnet; die Stufen stehen nur hier. |
|
2026-09-24 | 2026-09-24 | sonnet | low | Abschrift: jede Zeile steht wörtlich im Plan, Zieldateien und Verbote sind genannt. Sonnet low statt Haiku, weil der Code das Zeichen · (U+00B7) trägt und Haiku in der Messung vom 2026-09-23 typografische Zeichen still ersetzt hat. |
Task 01 — verbrauch.js: Planverbrauch lesen und Opus-Plätze rechnen
Die globalen Vorgaben stehen in 00-uebersicht.md (Abschnitt „Globale Vorgaben“). Arbeitsverzeichnis ist der Vault-Wurzelordner D:/Claude; alle Pfade gelten von dort.
Was danach anders ist:
- Es gibt
verbrauch.js. Ein Haiku-Agent lädtmcp__ccd_session_mgmt__get_usageund überträgt die Fenster; das Skript ordnet sie ein (5-hour ...,Weekly ... all models, falls vorhandenWeekly ... Opus) und rechnetplaetze = min(wunsch, Stufe 5 Stunden, Stufe Woche, 4). - Ohne lesbare Ablesung gilt zwei, wie bisher im Stamm.
nicht_gelesenundunbekannte_fenstersind eigene Stati, nie ein stilles Grün. wunsch: 0misst nur und bremst nie;probeersetzt den Agenten für den Regressionslauf im echten Laufzeitsystem.
Zieldateien
.claude/workflows/verbrauch.js(neu)
Verbote
- Keine andere Datei, auch nicht die übrigen Workflows unter
.claude/workflows/und nichts unterAI/Regelwerk/,.claude/agents/oderCLAUDE.md. - Kein Commit, kein Push, kein Lauf eines echten Workflows.
- Kein Umformulieren, auch nicht von Kommentaren oder Sonderzeichen; ein Widerspruch zwischen Plan und Baum wird gemeldet.
Umsetzung
.claude/workflows/verbrauch.js
Die ganze Datei ist neu:
export const meta = {
name: 'verbrauch',
description: 'Liest den Planverbrauch (5-Stunden-Fenster, Woche) über get_usage und rechnet daraus, wie viele Opus-Agenten gleichzeitig laufen dürfen',
whenToUse: 'Vor jeder Opus-Staffel eines Workflows, als Kind aufgerufen: workflow({ scriptPath: "D:/Claude/.claude/workflows/verbrauch.js" }, { anlass, wunsch }). Args: {anlass, wunsch: ganze Zahl ab 0, probe?}. wunsch 0 heißt nur messen. Rückgabe {status: ok|nicht_gelesen|unbekannte_fenster, quelle, fuenf_stunden, woche, woche_opus, plaetze, gebremst, grund, fenster}. Ohne lesbare Ablesung gilt die alte Obergrenze zwei. Regel: AI/Regelwerk/codeworkflow.md, "Verbrauch und Opus-Plätze".',
phases: [{ title: 'Verbrauch', detail: 'ein Haiku-Agent liest get_usage ab, das Skript entscheidet' }],
}
// Geltungsbereich (AI/Regelwerk/pruefwerkzeuge.md): Das Skript liest den Planverbrauch und
// rechnet daraus, wie viele Opus-Agenten gleichzeitig laufen dürfen. Es ist eine Bremse, kein
// Nachweis. Woher die Antworten kommen:
// - Welche Fenster zählen und wie sie heißen: Quelle. get_usage in der Desktop-App lieferte am
// 2026-09-24 "5-hour limit", "Weekly · all models" und "Weekly · Fable", je mit percentUsed
// 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.
// - Ohne lesbare Ablesung: Projektvorgabe, die bisherige Stammregel von zwei Opus-Agenten.
// Was das Skript nicht sieht: Agenten, die nach der Ablesung in anderen Sitzungen starten;
// laufende Agenten, die nach der Ablesung weiter verbrauchen; Sitzungen ohne get_usage
// (außerhalb der Desktop-App). Das Urteil rechnet das Skript, der Haiku-Agent liest nur ab.
const HARTE_OBERGRENZE = 4
const OHNE_ABLESUNG = 2
// Je Stufe [Schwelle in Prozent, Plätze unterhalb der Schwelle]; ab der letzten Schwelle 0.
const STUFEN_FUENF_STUNDEN = [[50, 4], [70, 2], [85, 1]]
const STUFEN_WOCHE = [[70, 4], [85, 2], [95, 1]]
const FUENF_STUNDEN = /^\s*5[- ]?hour/i
const WOCHE_ALLE = /^\s*weekly\b.*\ball models\b/i
const WOCHE_OPUS = /^\s*weekly\b.*\bopus\b/i
const ABLESUNG = {
type: 'object',
properties: {
verfuegbar: { type: 'boolean' },
status: { type: 'string' },
plan: { type: 'string' },
fenster: {
type: 'array',
items: {
type: 'object',
properties: { label: { type: 'string' }, percentUsed: { type: 'number' }, resetsAt: { type: 'string' } },
required: ['label', 'percentUsed', 'resetsAt'],
},
},
fehler: { type: 'string' },
},
required: ['verfuegbar', 'status', 'plan', 'fenster', 'fehler'],
}
const AUFTRAG = `Lade mit dem Werkzeug ToolSearch das Werkzeug mcp__ccd_session_mgmt__get_usage (Abfrage "select:mcp__ccd_session_mgmt__get_usage") und rufe es einmal ohne Parameter auf.
Übertrage aus dem Ergebnis plan.status nach status und plan.plan nach plan. Übertrage jeden Eintrag aus plan.windows mit label, percentUsed und resetsAt unverändert nach fenster, auch Einträge, die dir unwichtig erscheinen. Setze verfuegbar auf true und fehler auf "".
Ist das Werkzeug nicht verfügbar oder scheitert der Aufruf, setze verfuegbar auf false, status auf "fehler", plan auf "", fenster auf [] und schreibe die Fehlermeldung wörtlich nach fehler.
Tu sonst nichts. Übertrage das Ergebnis in die Felder des StructuredOutput-Werkzeugs.`
function pruefeArgs(a) {
if (!a || typeof a !== 'object') throw new Error('verbrauch: args fehlen')
if (typeof a.anlass !== 'string' || !a.anlass.trim()) throw new Error('verbrauch: anlass fehlt')
if (!Number.isInteger(a.wunsch) || a.wunsch < 0) throw new Error('verbrauch: wunsch muss eine ganze Zahl ab 0 sein, ist ' + JSON.stringify(a.wunsch))
if (a.probe !== undefined && (a.probe === null || typeof a.probe !== 'object' || Array.isArray(a.probe))) throw new Error('verbrauch: probe muss ein Objekt sein')
}
function stufe(prozent, stufen) {
for (const [schwelle, plaetze] of stufen) if (prozent < schwelle) return plaetze
return 0
}
// Ordnet die Fenster ein. Ein Fenster, das als 5 Stunden oder Woche erkannt wird, aber keine
// Prozentzahl von 0 bis 100 trägt, ist ein Befund und wird nicht still übergangen.
function einordnen(fenster) {
if (!Array.isArray(fenster)) return { fehler: 'fenster ist keine Liste' }
const e = { fuenf: null, woche: null, opus: null, andere: [] }
for (const f of fenster) {
if (!f || typeof f !== 'object' || typeof f.label !== 'string') return { fehler: 'Fenster ohne label: ' + JSON.stringify(f) }
const art = FUENF_STUNDEN.test(f.label) ? 'fuenf' : WOCHE_ALLE.test(f.label) ? 'woche' : WOCHE_OPUS.test(f.label) ? 'opus' : null
if (!art) { e.andere.push(f.label); continue }
const p = f.percentUsed
if (typeof p !== 'number' || !Number.isFinite(p) || p < 0 || p > 100) return { fehler: `${f.label}: percentUsed ${JSON.stringify(p)} ist keine Zahl von 0 bis 100` }
const neu = { prozent: p, zuruecksetzung: typeof f.resetsAt === 'string' ? f.resetsAt : null }
if (!e[art] || e[art].prozent < p) e[art] = neu
}
const fehlt = [!e.fuenf && '5-hour limit', !e.woche && 'Weekly all models'].filter(Boolean)
if (fehlt.length) return { fehler: 'Fenster fehlt: ' + fehlt.join(', ') + (e.andere.length ? '; gelesen: ' + e.andere.join(', ') : '') }
return e
}
pruefeArgs(args)
phase('Verbrauch')
const wunsch = args.wunsch
const deckel = wunsch > HARTE_OBERGRENZE ? `; wunsch ${wunsch} auf die harte Obergrenze ${HARTE_OBERGRENZE} gesenkt` : ''
let quelle = 'probe'
let ablesung = args.probe
if (ablesung === undefined) {
quelle = 'agent'
ablesung = await agent(AUFTRAG, { label: 'verbrauch:' + args.anlass, phase: 'Verbrauch', schema: ABLESUNG, model: 'haiku' })
}
function ohneAblesung(status, grund) {
const plaetze = Math.min(wunsch, OHNE_ABLESUNG)
log(`Verbrauch ${args.anlass}: ${status} (${grund}); ${plaetze} Plätze nach der alten Obergrenze`)
return { status, quelle, fuenf_stunden: null, woche: null, woche_opus: null, plaetze, gebremst: false, grund: grund + deckel, fenster: ablesung && Array.isArray(ablesung.fenster) ? ablesung.fenster : null }
}
if (!ablesung || typeof ablesung !== 'object') return ohneAblesung('nicht_gelesen', 'kein Ergebnis vom Ableseagenten')
if (ablesung.verfuegbar !== true || ablesung.status !== 'ok') return ohneAblesung('nicht_gelesen', `get_usage: verfuegbar ${ablesung.verfuegbar}, status ${ablesung.status}${ablesung.fehler ? ', ' + ablesung.fehler : ''}`)
const e = einordnen(ablesung.fenster)
if (e.fehler) return ohneAblesung('unbekannte_fenster', e.fehler)
const wocheProzent = Math.max(e.woche.prozent, e.opus ? e.opus.prozent : 0)
const grenzeFuenf = stufe(e.fuenf.prozent, STUFEN_FUENF_STUNDEN)
const grenzeWoche = stufe(wocheProzent, STUFEN_WOCHE)
const plaetze = Math.min(wunsch, grenzeFuenf, grenzeWoche, HARTE_OBERGRENZE)
const gebremst = wunsch > 0 && plaetze === 0
const grund = `5 Stunden ${e.fuenf.prozent} % (bis ${grenzeFuenf} Plätze), Woche ${wocheProzent} % (bis ${grenzeWoche} Plätze)${e.opus ? ', Opus-Woche ' + e.opus.prozent + ' %' : ''}${deckel}`
log(`Verbrauch ${args.anlass}: ${grund}; ${plaetze} von ${wunsch} Plätzen${gebremst ? ', gebremst' : ''}`)
return { status: 'ok', quelle, fuenf_stunden: e.fuenf, woche: e.woche, woche_opus: e.opus, plaetze, gebremst, grund, fenster: ablesung.fenster }
Verifikation
Im Vault-Wurzelordner:
node -e "const t=require('fs').readFileSync(process.argv[1],'utf8').replace(/^export const meta = /m,'const meta = ');new (Object.getPrototypeOf(async function(){}).constructor)('agent','parallel','pipeline','phase','log','workflow','args','budget',t);console.log('PARSE OK')" .claude/workflows/verbrauch.js
Erwartet: PARSE OK, Exit 0.
Danach git status --porcelain -- .claude/workflows/verbrauch.js zeigen.