The Operator's ===OPERATOR-DECISION=== schema gains an optional "escalation" field (<=2 steps of model/reasoning_effort/iteration_limit, validated against a new per-runtime orchestration.MODEL_POOL allowlist): per-parent for direct_builder, per-child for split. On limit_reached, completion_watcher.py now walks this ladder (via the shared fanout.escalation_ladder_for()) instead of a single flat identical-params retry, escalating model/iteration_limit before falling back to today's manual repair/Aufteilen-angefordert checkpoints. A card that never went through the Operator keeps its existing flat single-retry behavior unchanged. orchestration.child_failed(), fanout.child_terminal(), and trigger.py's Aufteilen-angefordert guard all switch from the old hardcoded ">= 1" threshold to the card's actual ladder length. board.html surfaces the current attempt count on affected cards. Also includes the board-session-usage-indicator research writeup (Codex app-server JSON-RPC + Claude /api/oauth/usage as the two non-interactive usage sources) and its Operator-produced child intents, plus the operator_klaerung_noetig phase-visibility fix already staged in this checkout (distinct phase for a needs_human/crashed Operator run that never produced children, instead of reusing "durch_kinder_blockiert"). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SyeDivnWm6hgiNd3YKjK7Z
144 lines
7.7 KiB
Markdown
144 lines
7.7 KiB
Markdown
# Intent: Anzeige der verbleibenden Claude-/Codex-Sitzungslimits im Intent-Board
|
|
|
|
## Ziel
|
|
|
|
Ein kleines, dauerhaft sichtbares UI-Element im Intent-Board (z. B. in
|
|
der Kopfzeile neben Titel/Untertitel), das anzeigt, wie viel Prozent des
|
|
aktuellen Nutzungslimits für Claude Code und für Codex CLI noch übrig
|
|
sind — für die eine interaktive `drone`-Identität, deren Login/Kontingent
|
|
von den meisten Board-Rollen gemeinsam genutzt wird (Reviewer/Researcher/
|
|
Planner über Claude, Builder/Worker/Agent über Codex; siehe
|
|
`board-agent.nix`s eigene Kommentare zu diesem geteilten
|
|
Login-Tradeoff). Zweck: auf einen Blick sehen, ob gerade noch Spielraum
|
|
für weitere Board-Läufe ist, bevor eine Karte losgeschickt wird.
|
|
|
|
## Rechercheergebnis (geklärt, 10.09.2026)
|
|
|
|
Live auf blunix nachrecherchiert (interaktive Klärung mit dem Operator,
|
|
10.09.2026), nachdem der ursprüngliche Rechercheversuch vom 09.09.2026
|
|
(reine `--help`/`doctor`-Prüfung) korrekt feststellte, dass keine der
|
|
offensichtlichen CLI-Unterprozeduren einen Prozentsatz liefert. Ein
|
|
tieferer Blick fand für beide Runtimes eine echte, nicht-interaktive
|
|
Quelle:
|
|
|
|
**Codex:** `codex app-server` (dokumentiertes, wenn auch als
|
|
„[experimental]" markiertes CLI-Subcommand) beantwortet über sein
|
|
Stdio-JSON-RPC-Protokoll die Methode `account/rateLimits/read` nach
|
|
einem `initialize`-Handshake, ohne dass eine interaktive Sitzung nötig
|
|
ist — live getestet, Antwortzeit deutlich unter einer Sekunde. Die
|
|
Antwort enthält `rateLimits.primary.usedPercent` (5-Stunden-Fenster,
|
|
`windowDurationMins: 300`) und `rateLimits.secondary.usedPercent`
|
|
(Wochenfenster, `windowDurationMins: 10080`), je mit `resetsAt`
|
|
(Unix-Timestamp). Eine bereits laufende `codex app-server`-Instanz ist
|
|
dafür nicht nötig; ein kurzlebiger Kindprozess pro Abfrage reicht.
|
|
Einschränkung: `codex app-server` schreibt beim Start in mehrere Dateien
|
|
im eigenen `CODEX_HOME` (u. a. `logs_2.sqlite`, `goals_1.sqlite`,
|
|
`state_5.sqlite`, `models_cache.json`, Plugin-/Skill-Cache) — kein enger,
|
|
vorhersagbarer Satz, sondern praktisch der gesamte Home-Baumstand. Da
|
|
`board-agent-trigger.service` mit `ProtectHome = "read-only"` läuft, ist
|
|
ein direkter Aufruf gegen das echte `/home/drone/.codex` nicht
|
|
schreibfähig. Entscheidung: ein eigenes, dauerhaftes, beschreibbares
|
|
Probe-`CODEX_HOME` unterhalb des Board-Agent-State-Verzeichnisses
|
|
anlegen (kein neuer `ProtectHome`-Downgrade), dessen `auth.json` vor
|
|
jeder Anfrage frisch aus `/home/drone/.codex/auth.json` kopiert wird —
|
|
nicht nur einmalig beim Servicestart wie beim bestehenden
|
|
`prepareCodexHome`-Muster für die isolierte Builder-Identität, weil
|
|
dieser Dienst dauerhaft läuft (`Restart = "always"`) und ein
|
|
zwischenzeitlich rotiertes Token sonst erst nach einem Neustart wieder
|
|
funktionieren würde. Die Kopierkosten (wenige KB) sind gegenüber dem
|
|
ohnehin unter einer Sekunde liegenden RPC-Aufruf vernachlässigbar, bei
|
|
einem Frontend-Poll-Intervall von rund 60 Sekunden erst recht.
|
|
|
|
**Claude:** Es gibt kein offizielles CLI-Subcommand analog zu
|
|
`codex app-server`. `claude auth status --json` liefert Konto-Metadaten
|
|
(u. a. `subscriptionType`), aber keinen Prozentsatz. Ein Blick in die
|
|
Strings des installierten `claude`-Binaries (`.claude-wrapped`, aktuell
|
|
Version 2.1.257) zeigt jedoch echte, im Client verdrahtete
|
|
API-Oberflächen: HTTP-Antwort-Header nach dem Muster
|
|
`anthropic-ratelimit-unified-5h-utilization` /
|
|
`anthropic-ratelimit-unified-7d-utilization` (analog zu Codex' primärem/
|
|
sekundärem Fenster) sowie den Pfad `/api/oauth/usage`. Live getestet mit
|
|
dem in `~/.claude/.credentials.json` gespeicherten OAuth-Access-Token
|
|
(`Authorization: Bearer …`, zusätzlich Header
|
|
`anthropic-beta: oauth-2025-04-20`, gefunden als Literal-String im
|
|
selben Binary) gegen `https://api.anthropic.com/api/oauth/usage`:
|
|
Antwort `200 OK` mit direkt nutzbarem JSON-Body, u. a.
|
|
`five_hour.utilization` (Prozentzahl, 5-Stunden-Fenster),
|
|
`seven_day.utilization` (Prozentzahl, Wochenfenster) und je einem
|
|
`resets_at`-ISO-Zeitstempel — keine Header-Auswertung nötig. Zum
|
|
Vergleich probeweise auch das offizielle, öffentliche und kostenlose
|
|
`/v1/messages/count_tokens` aufgerufen: authentifiziert erfolgreich
|
|
(kein 401), aber im Test mit `404` auf ein veraltetes Modellkürzel
|
|
gescheitert und selbst korrekt beantwortet nur die Rate-Limit-Header,
|
|
nicht diesen direkt nutzbaren Body. Entscheidung: `/api/oauth/usage`
|
|
verwenden, trotz des Risikos eines undokumentierten, privaten
|
|
Endpunkts — bewusst dieselbe Abwägung wie bei Codex' selbst als
|
|
„[experimental]" markiertem `app-server`. Der Aufruf braucht keinerlei
|
|
Schreibzugriff (nur Lesen von `~/.claude/.credentials.json`, das
|
|
bestehende `ProtectHome = "read-only"` reicht) und `board-agent-trigger`
|
|
hat schon heute uneingeschränkten ausgehenden Netzwerkzugriff — hier ist
|
|
also keine Sandbox-Anpassung nötig, anders als bei Codex.
|
|
|
|
Damit ist die ursprünglich blockierende Recherche abgeschlossen und
|
|
beide Quellen sind bestätigt nicht-interaktiv, ohne TUI-Sitzung
|
|
abrufbar.
|
|
|
|
## Umfang
|
|
|
|
- Neuer, ausschließlich lesender API-Endpunkt in
|
|
`board-agent/trigger.py` (`GET /api/board/usage`):
|
|
- Codex-Seite: `auth.json` aus `/home/drone/.codex` in ein eigenes,
|
|
dauerhaftes Probe-`CODEX_HOME` unterhalb des Board-Agent-State-
|
|
Verzeichnisses kopieren, `codex app-server` als kurzlebigen
|
|
Kindprozess starten, `initialize` + `account/rateLimits/read` per
|
|
Stdio-JSON-RPC senden, `rateLimits.primary.usedPercent` und
|
|
`rateLimits.secondary.usedPercent` auslesen.
|
|
- Claude-Seite: Access-Token aus `~/.claude/.credentials.json` lesen,
|
|
`GET https://api.anthropic.com/api/oauth/usage` mit
|
|
`Authorization: Bearer …` und `anthropic-beta: oauth-2025-04-20`
|
|
aufrufen, `five_hour.utilization` und `seven_day.utilization`
|
|
auslesen.
|
|
- Der Endpunkt gibt ausschließlich die berechneten Prozentwerte (plus
|
|
optional die `resets_at`-Zeitstempel) zurück — nie Access-Tokens,
|
|
rohe Limit-/Dollar-Felder oder sonstige Rohdaten an das Frontend
|
|
durchreichen.
|
|
- Schlägt eine der beiden Quellen fehl, liefert der Endpunkt für genau
|
|
diese Seite eine Leerdarstellung statt den ganzen Aufruf fehlschlagen
|
|
zu lassen — die jeweils andere Quelle bleibt unabhängig nutzbar.
|
|
- Kleines, unauffälliges UI-Element in `board-agent/board.html`
|
|
(Kopfzeile oder schmale eigene Leiste), das den Endpunkt periodisch
|
|
abruft (alle 60 Sekunden) und knapp anzeigt, etwa
|
|
„Claude: 60 % übrig · Codex: 0 % übrig". Kein neuer Dialog, keine
|
|
eigene Spalte.
|
|
- Bei fehlender/nicht auslesbarer Quelle: klare, unaufdringliche
|
|
Leerdarstellung (z. B. „—") statt eines falschen oder geratenen Werts.
|
|
|
|
## Explizit ausgeschlossen
|
|
|
|
- Keine historische Verlaufsanzeige/Graph über die Zeit — nur der
|
|
aktuelle Momentanwert.
|
|
- Keine Alarmierung/Benachrichtigung bei niedrigem Kontingent (z. B.
|
|
XMPP-Nachricht) — reine passive Anzeige in diesem Schritt.
|
|
- Keine Aufschlüsselung pro Rolle/Spalte (Reviewer vs. Builder vs.
|
|
Researcher) — ein einziger Wert je Anbieter (Claude, Codex) für die
|
|
eine geteilte Identität.
|
|
- Keine Änderung an den Board-Spalten/Trigger-Logik — rein additiv.
|
|
|
|
## Annahmen
|
|
|
|
- Die relevante Zahl bezieht sich auf die geteilte interaktive
|
|
`drone`-Identität (ein Login, viele Rollen), nicht auf einen
|
|
hypothetischen Wert pro Rolle/Secret.
|
|
- Ein grober, klar als Schätzung gekennzeichneter Näherungswert ist
|
|
besser als gar keine Anzeige, aber nur falls das Rechercheergebnis
|
|
keine echte Quelle findet — Priorität liegt auf einer echten Zahl,
|
|
falls verfügbar.
|
|
|
|
## Erfolgskriterien
|
|
|
|
- Das Board zeigt einen aktuellen, unaufdringlichen Prozentwert für
|
|
Claude und für Codex (oder eine klare Leerdarstellung, falls technisch
|
|
nicht möglich).
|
|
- Keine Secrets/Tokens/Rohdaten verlassen den Server-Endpunkt.
|
|
- Die Anzeige aktualisiert sich automatisch, ohne dass die Seite neu
|
|
geladen werden muss.
|