Wenn dem Code-Reviewer die Credits ausgehen
Es war einer dieser Momente, in denen ein Werkzeug genau dann streikt, wenn man es am meisten braucht. Ein Projekt unter Zeitdruck, ein Stapel Pull Requests — und mein automatischer Code-Reviewer meldete auf jeden einzelnen nur noch dieselbe Zeile:
we couldn't start this review because you've reached your PR review rate limit.
Die Prepaid-Credits waren aufgebraucht. Praktisch hieß das: Pull Requests gingen ungereviewt durch. In einer heißen Phase ist das genau das Risiko, das man nicht tragen will.
Drei naheliegende Reaktionen: nachkaufen, von Hand reviewen, oder ungereviewt mergen. Teuer, langsam oder fahrlässig. Also haben Claude und ich eine vierte gebaut — eine Weiche.
Die Idee: der Ausfall ist maschinenlesbar
Der Schlüssel steckte in der Fehlermeldung selbst. Der Reviewer postet seinen Rate-Limit-Hinweis nicht als Fließtext, sondern mit einem stabilen, versteckten Marker im Kommentar:
<!-- This is an auto-generated comment: rate limited by coderabbit.ai -->
Das ist kein Bug. Das ist ein Signal. Wenn der Ausfall maschinenlesbar ist, kann ich deterministisch darauf reagieren — kein Polling, kein Timeout-Raten. Ein GitHub-Workflow lauscht auf neue Kommentare und springt nur an, wenn genau dieser Marker vom Reviewer-Bot kommt:
on:
issue_comment:
types: [created]
jobs:
claude-review:
if: >
github.event.issue.pull_request &&
github.event.comment.user.login == 'coderabbitai[bot]' &&
contains(github.event.comment.body, 'rate limited by coderabbit.ai')
# ... dann: Claude reviewt den PR
Läuft der primäre Reviewer normal, ist der Marker nicht da — und es passiert nichts. Kein Doppel-Review, kein doppelter Verbrauch. Eine echte Weiche eben: der eine Reviewer übernimmt, wenn der andere ausfällt.
Die Falle, die man genau einmal lernt
issue_comment-Workflows laufen immer mit der Datei-Version vom Default-Branch, nicht mit der des PR. Die Weiche wirkt also erst, nachdem sie auf main gemergt ist — und dann für jeden künftigen PR. Noch eine scharfe Kante: In diesen Events steht die PR-Nummer in github.event.issue.number, nicht in pull_request.number (das ist hier null). Zwei kleine Steine, die einen sonst eine halbe Stunde kosten.
Vom einen Repo zum ganzen Portfolio
Eine Weiche in einem Repository ist nett. Aber die Credits des Reviewers waren überall aufgebraucht. Also: Rollout über alle aktiven Repos.
Statt 14-mal zu klicken, lief alles über die GitHub-API — Branch anlegen, Datei schreiben, PR öffnen, komplett remote:
gh api repos/$SLUG/git/refs -f ref="refs/heads/ci/claude-review-switch" -f sha="$BASE_SHA"
echo "$PAYLOAD" | gh api -X PUT "repos/$SLUG/contents/$WF_PATH" --input -
gh pr create -R "$SLUG" --base "$DEF" --head "ci/claude-review-switch" --title "…"
Eine Voraussetzung: Der gh-Token braucht den workflow-Scope, sonst lehnt GitHub das Schreiben von Workflow-Dateien ab. Ein Lauf, vierzehn Repositories.
„Kopier doch einfach das Secret" — geht nicht
Hier kam die erste echte Lektion. Jeder Workflow braucht einen Token. Mein Reflex: aus dem Repo, wo es schon klappt, das Secret „rüberkopieren". Geht nicht. GitHub-Actions-Secrets sind write-only — man kann sie setzen, aber nie zurücklesen. Aus gutem Grund.
Die saubere Lösung: den Token einmal erzeugen, in einem Passwort-Manager ablegen und beim Rollout je Repo direkt von dort ziehen:
gh secret set CLAUDE_CODE_OAUTH_TOKEN -R "$SLUG" \
--body "$(op item get 'claude-code/oauth - ci' --vault 'Development Keys' \
--fields CLAUDE_CODE_OAUTH_TOKEN --reveal)"
Der Token landet nie im Terminal-Verlauf, nie in einem Chat, nie in einem Log — er fließt direkt aus dem Vault ins Secret.
Der Umweg, der wichtiger war als das Ziel
13 von 14 PRs ließen sich sofort mergen. Einer hing — blockiert von der Branch-Protection, weil ein Pflicht-Check namens lint-and-test rot war. Der einfache Weg wäre ein Admin-Override gewesen. Der richtige Weg war nachzusehen, warum.
Der rote Schritt: npm audit --audit-level=moderate. Drei transitive Schwachstellen hatten sich angesammelt — eine „high", zwei „moderate". Das hatte mit meiner Änderung nichts zu tun; der Check war seit Tagen rot und blockierte jeden PR.
Ein einziges npm audit fix (ohne --force, alles non-breaking) löste alle drei. Lokal komplett verifiziert — npm ci, audit, lint, test (103/103 grün) — dann gemergt. Erst danach die Weiche.
Das ist die eigentliche Lehre: Ein npm audit-Gate ist gut, aber es sammelt stille Sicherheits-Schuld, bis irgendwann ein völlig unbeteiligter PR daran scheitert. Wer dann per Admin-Override durchwinkt, behebt nichts — er reicht das Problem an den Nächsten weiter.
Was bleibt
- Automatisiere die Erkennung, nicht den manuellen Fallback. Der Marker macht aus „ich müsste mal nachsehen" ein deterministisches Ereignis.
- Secrets haben eine Quelle, kein Backup. Write-only zwingt zu sauberer Token-Hygiene — der Vault als einzige Wahrheit.
- Root Cause vor Bequemlichkeit. Der blockierte PR war kein Hindernis. Er war ein Hinweis.
Gebaut habe ich das nicht allein — Claude war den ganzen Weg im Loop: Recherche, Skript, Verifikation, Rollout. Genau die Art Arbeit, bei der ein Agent glänzt: viele kleine, korrekte Schritte über viele Repos, ohne dass einem auf halber Strecke die Konzentration ausgeht.
