This repository has been archived on 2026-09-17. You can view files and clone it, but you cannot make any changes to its state, such as pushing and creating new issues, pull requests or comments.
nixos-config/docs/intent/board-session-usage-indicator.md
pijukka 41e05ed43f board: automatic escalation ladder for limit_reached Builder retries
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
2026-09-10 13:58:52 +02:00

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.