TL;DR
- Spotifys "90 %" ist der Mittelwert von Bulk-Read-Szenarien, gemessen in geschätzten Input-Tokens auf einem Java-Monorepo. Der Post nennt weder einen Dollarbetrag noch einen Qualitätswert.
- Nachgebaut in reinem Claude Code (ein PreToolUse-Hook, zwei günstige Subagents, eine Routing-Regel in drei Zeilen) und auf Fastify über vier Szenarien und 16 Läufe gemessen, senkte das Muster den Kontext des Hauptmodells um 59.6% und die Gesamtkosten um 33.1%.
- Die Deny-Hooks haben in den gemessenen Läufen keinmal ausgelöst. Die Ersparnis kam von der Routing-Regel in der CLAUDE.md; die Hooks sind das Sicherheitsnetz für den Tag, an dem das Modell sie ignoriert.
- Die Delegation war jedes Mal langsamer, im Schnitt +65.3% Wandzeit. Beim kleinen Szenario "Test schreiben" kostete sie 2.6% mehr.
- Zwei Fallen: Hooks feuern auch innerhalb von Subagents, also nimm deine Worker aus; und
sed -n-Bereichslesungen gehen glatt durch einen Hook, der nurcat,headundtailbeobachtet. - Die Zusammenfassung des Haiku-Readers enthielt in zwei von acht delegierten Läufen Sachfehler. Behalte den Verifikationsschritt des Hauptmodells.
Was die Messungen zeigen
Spotifys Plugin Shunt leitet Bulk-Arbeit über zwei "Modes" vom Hauptmodell weg: einen Bulk-Reader und einen Code-Writer, in den Beispielen beide mit Gemini 2.5 Flash, wobei das Modellfeld jedes in der Portal-Instanz konfigurierte Modell akzeptiert s1. Das Routing hat drei Schichten. Ein check-file-size-Hook feuert bei jedem Read und blockiert Dateien über einer konfigurierbaren Zeilenschwelle (Standard 350), woraufhin das Modell auf den Bulk-Reader-Skill verwiesen wird; ein check-bash-read-Hook fängt cat, head, tail, less und more auf großen Dateien ab, während Pipe-Befehle durchgehen s1. Die Hook-Quellen und die beiden Skills liegen im öffentlichen Repo s2, die Größenprüfung ist separat lesbar s3. Die Modes selbst leben in Portal, Spotifys interner Plattform, weshalb sich das Plugin in der ausgelieferten Form außerhalb der Firma nicht betreiben lässt s4.
Die Benchmark-Behauptung ist dünn. Spotify hat vier Szenarien auf einem Java-Monorepo getestet, "measuring tokens Claude would consume reading files directly vs. consuming the bulk-reader's summary", und meldet mittlere Bulk-Read-Einsparungen von rund 90% s1. Der Post selbst sagt, das Code-Write-Szenario sei in Tokens schwerer zu messen, die Zusammenfassungen der Worker enthielten keine verlässlichen Zeilennummern, weshalb sich das Editieren nicht delegieren lasse, der Worker habe einen subtilen Thread-Safety-Bug übersehen, den das Hauptmodell fand, und jede Delegation koste 10 bis 30 Sekunden, wobei Portal einen einzelnen Aufruf auf 30 Sekunden deckelt s1. Der Hacker-News-Thread stellte dieselben Fragen dazu, was die 90% eigentlich messen s7.
Der Nachbau ersetzt die Portal-Modes durch zwei Claude-Code-Subagents, deren Definitionsdateien das Modell festlegen: ein Explore-Reader auf Haiku und ein Code-Writer auf Sonnet s6. Das Deny ist ein PreToolUse-Hook, der die Deny-Entscheidung im aktuellen Hook-JSON-Format zurückgibt s5. Getestet wurde fastify/fastify bei Commit ac28821d, 294 .js/.ts-Dateien, 78270 Zeilen, 63 Dateien über 350 Zeilen. Modell-IDs laut Session-JSON: Hauptkonversation claude-opus-5[1m], Reader claude-haiku-4-5-20251001, Writer claude-sonnet-5. Jedes Szenario lief pro Konfiguration zweimal, 16 gemessene Läufe, Single-Turn-claude -p-Sessions mit reinen Projekt-Settings, damit beide Seiten denselben System-Prompt hatten s5.
Wo das Muster gewann: S2, eine Call-Graph-Frage über drei Dateien (lib/route.js mit 691 Zeilen, lib/reply.js mit 1090 und lib/request.js mit 398), ging von einem mittleren Hauptkontext von 357165.5 Tokens auf 73440.0 (-79.4%) und von 0.5810500000000001 USD auf 0.21823605000000001 USD (-62.4%). Wo nicht: S4, das Schreiben eines Tests für eine 45-Zeilen-Quelle anhand einer 19-Zeilen-Referenz, kostete 0.29465575 USD ohne Delegation und 0.3022213 USD mit (+2.6%), weil Sonnet ein zweiter voller Kontext ist (13004 bis 18729 Cache-Read-Tokens) und das Hauptmodell die erzeugte Datei trotzdem erneut las und den Test ausführte s6.
Drei Befunde zählen mehr als die Prozentwerte. Erstens: Die Hooks feuerten in den 16 gemessenen Läufen keinmal. Mit der Routing-Regel in der CLAUDE.md führte das Hauptmodell wc -l aus und delegierte von selbst. Das einzige beobachtete Deny stammte aus einem Verifikationslauf ohne CLAUDE.md, in dem dem Modell Read verweigert wurde, dann cat -n, und es allein mit grep -n antwortete, ohne je das Agent-Tool aufzurufen s5. Zweitens: Hooks laufen auch in Subagents. In zwei verworfenen Läufen wurde der Haiku-Reader selbst von der Größenprüfung abgewiesen und wich auf stückweise offset/limit-Lesungen aus. Die Lösung ist eine Ausnahme case "$agent_type" in Explore|code-writer) exit 0 ganz oben im Hook, wobei der Feldname aus dem geloggten stdin bestätigt wurde s5. Drittens: In der Baseline-Konfiguration benutzte das Hauptmodell das Read-Tool überhaupt nie. Es las jede Datei über Bash (cat -n, sed -n '1,200p', sed -n '200,560p'), ein Hook, der nur Read beobachtet, fängt also nichts, und ein Bash-Hook, der nur cat, head und tail ohne Pipe matcht, lässt sed -n-Bereiche weiterhin durch s3.
Die Qualität wurde per grep gegen die Quelle geprüft. Die Baseline lieferte in einem S2-Lauf falsche Zeilennummern (sie gab Dateien mit sed -n ohne Zeilennummern aus und zählte von Hand). Die delegierte Konfiguration lieferte im anderen S2-Lauf drei und in einem S3-Lauf zwei Sachfehler, alle darauf zurückzuführen, dass die Haiku-Zusammenfassung für bare Münze genommen wurde: falsche Aufrufer von buildRequest/buildReply, eine nicht exportierte Konstante als Export aufgeführt, ein abgedeckter Iterator als nicht abgedeckt markiert. Wo das Hauptmodell Output-Tokens für die erneute Prüfung per grep ausgab (S3, 4534 bis 4738 Output-Tokens), hielten die Antworten s6. Im Test-Szenario bestand jede erzeugte Datei: 12/12, 6/6, 7/7 und 10/10 Tests. Ein Reddit-Bericht zeigt den verwandten Fehlerfall eines Hauptmodells, das Worker auf dem falschen Modell startet, wenn nichts es festlegt s8; genau davor schützen der require-model-Hook und das model:-Feld in den Agent-Dateien.
Messungen
Mittelwerte der 2 Läufe pro Zelle. "Hauptkontext" sind Input + cache_creation + cache_read Tokens, die dem Hauptmodell über die Session berechnet wurden, die mit Spotifys "tokens in the main context" vergleichbare Größe. A = reines Claude Code, B = Hook + Subagents + CLAUDE.md-Regel.
| Szenario | Hauptkontext A | Hauptkontext B | Änderung | Haupt-Output A | Haupt-Output B | Änderung | Gesamtkosten A | Gesamtkosten B | Änderung | Dauer A s | Dauer B s | Änderung |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| S1 | 88693.0 | 51551.5 | -41.9% | 1424.5 | 1060.5 | -25.6% | 0.13910675 | 0.08653685 | -37.8% | 21.817500000000003 | 43.799499999999995 | +100.8% |
| S2 | 357165.5 | 73440.0 | -79.4% | 3835.0 | 2555.5 | -33.4% | 0.5810500000000001 | 0.21823605000000001 | -62.4% | 51.637 | 129.036 | +149.9% |
| S3 | 303807.5 | 114135.5 | -62.4% | 6192.0 | 4636.0 | -25.1% | 0.451037 | 0.3738534 | -17.1% | 93.321 | 124.64099999999999 | +33.6% |
| S4 | 143431.5 | 121818.0 | -15.1% | 5275.5 | 3340.0 | -36.7% | 0.29465575 | 0.3022213 | +2.6% | 65.7125 | 86.857 | +32.2% |
| alle 4 | 223274.375 | 90236.25 | -59.6% | 4181.75 | 2898.0 | -30.7% | 0.366462375 | 0.2452119 | -33.1% | 58.122 | 96.08337499999999 | +65.3% |
Protokoll: zwei byte-identische Shallow-Clones von fastify/fastify bei ac28821d; repo-shunt fügt .claude/ (Settings, zwei Agent-Dateien, drei Hooks) und eine CLAUDE.md-Routing-Regel hinzu, sonst nichts. Jede Session: claude -p "<prompt>" --output-format json --setting-sources project --strict-mcp-config mit leerer MCP-Konfiguration, ohne --model, 600 s Timeout. Vier Prompts, auf beiden Seiten identisch: S1 Exports von lib/reply.js, S2 Call-Graph über drei lib-Dateien, S3 Methoden von lib/hooks.js gegenüber der Abdeckung in test/hooks.test.js, S4 test/head-route.test.js nach dem Vorbild von test/noop-set.test.js schreiben. Die Werte stammen ungerundet aus modelUsage und total_cost_usd der Session-JSON. Die Antworten wurden per grep gegen die Quelle geprüft; die erzeugten Tests liefen mit node --test.
Das machst du am Montag
- Lass
wc -lüber dein Repo laufen und zähle die Dateien über 350 Zeilen. Liegt die Zahl nahe null, hör hier auf: Die Schwelle existiert, weil Delegation bei kleinen Dateien mehr kostet, als sie spart. - Füge deiner CLAUDE.md eine Routing-Regel in drei Zeilen hinzu: Dateien über der Schwelle gehen an einen Reader-Subagent, musterfolgender Code an einen Writer-Subagent, Debugging und Architektur bleiben beim Hauptmodell. In den Messungen hat diese Regel die ganze Arbeit erledigt.
- Lege
.claude/agents/Explore.mdmitmodel: haikuund.claude/agents/code-writer.mdmitmodel: sonnetim Frontmatter an, damit das Worker-Modell in der Datei festgelegt ist und nicht dem Orchestrator überlassen bleibt. - Schreibe den PreToolUse-Hook auf Read als Sicherheitsnetz, der die Deny-Entscheidung im aktuellen Hook-JSON-Format zurückgibt, und lass seine ersten Zeilen mit exit 0 enden, wenn
agent_typeeiner deiner Worker ist. - Erweitere den Bash-Hook über
cat,headundtailhinaus: Matchesed -n-Bereiche undcat -nauf großen Dateien, lass Pipe- und grep-Befehle durch. - Stelle eine echte Frage mit und ohne den
.claude/-Ordner überclaude -p --output-format jsonund vergleichetotal_cost_usdundduration_ms, nicht allein die Input-Spalte. - Prüfe zwei delegierte Antworten per grep gegen die Quelle, bevor du der Zusammenfassung des Readers traust; plane den Verifikationsschritt des Hauptmodells als Teil der Kosten ein.
- Miss auch eine Multi-Turn-Session: Die Single-Turn-Ergebnisse lassen den Hauptkontext bei 50k bis 119k Tokens gegenüber 84k bis 414k ohne Delegation, die zweite Frage sollte also günstiger starten, das wurde aber nicht gemessen.
Weiterlesen
- Lies das Hook-Format und das Feld
agent_typein der offiziellen Referenz, bevor du einen Hook aus einem Blogpost kopierst; die Deny-Form und die Felder auf stdin machen die Subagent-Ausnahme erst möglich s5. - Die Subagent-Dokumentation behandelt das Frontmatter-Feld
modelund Tool-Beschränkungen, womit sich ein Reader schreibgeschützt und günstig halten lässt s6. - Spotifys eigener Abschnitt "What doesn't work" ist der nützlichste Teil des Posts: kein delegiertes Editieren (keine verlässlichen Zeilennummern in Zusammenfassungen), kein delegiertes Denken (ein übersehener Thread-Safety-Bug), 10 bis 30 Sekunden pro Roundtrip s1.
- Die Shunt-README zeigt die dreischichtige Struktur (Hooks, Skripte, Skills) und die Skill-Texte, die dem Modell sagen, wann es delegieren soll; die Skill-Prosa ist der Teil, den man anpassen sollte, nicht der Hook s2.
- Portal-Modes sind eine Konfigurationsschicht über einem Modell plus System-Prompt; dieselbe Idee lässt sich auf eine Claude-Code-Agent-Datei mit
model-Feld abbilden s4. - Im Hacker-News-Thread wurden die Messfragen zuerst gestellt, und er taugt als Checkliste dafür, was man von jeder Token-Spar-Behauptung verlangen sollte s7.
- Ein Reddit-Thread dokumentiert einen Orchestrator, der fünf Worker auf seinem eigenen teuren Modell startete; leg das Modell in der Agent-Datei fest und, wenn du eine harte Garantie willst, verweigere Agent-Aufrufe ohne
model-Feld s8.
Quellen
- Portal by Spotify cut my Claude Code token usage by 90%, Spotify Engineering. Warum lesen: die ursprüngliche Behauptung, das dreischichtige Design und ein ehrlicher Abschnitt über Einschränkungen, der die Schlagzeile relativiert.
- Shunt plugin (spotify/portal-ai-plugins), GitHub. Warum lesen: die echten Hooks, Skripte und Skill-Texte, kurz genug, um sie ganz zu lesen.
- check-file-size hook source, GitHub. Warum lesen: die 350-Zeilen-Prüfung in wenigen Zeilen Shell, die Vorlage für dein eigenes Deny.
- Portal Modes documentation, Spotify. Warum lesen: was ein "Mode" ist, damit du siehst, warum er auf eine Subagent-Datei abbildbar ist.
- Claude Code hooks reference, Anthropic. Warum lesen: das aktuelle Deny-Format und die stdin-Felder, darunter das, das einen Subagent identifiziert.
- Claude Code subagents, Anthropic. Warum lesen: das Frontmatter-Feld
modelund Tool-Allowlists für einen günstigen, schreibgeschützten Worker. - Hacker News discussion of the Spotify post, Hacker News. Warum lesen: die Fragen dazu, was die 90% messen, gestellt bevor jemand nachgemessen hat.
- Fable spawned five Fable agents instead of Opus (r/ClaudeCode), Reddit. Warum lesen: der Fehlerfall, den ein festgelegtes
model-Feld verhindert.
FAQ
Ist die 90%-Zahl falsch?
Sie misst eine einzige Sache: geschätzte Input-Tokens im Hauptkontext bei Bulk-Read-Szenarien auf großen Java-Dateien. Auf einer ähnlichen Metrik sah der Nachbau 41.9% bis 79.4% bei Lese-Szenarien. Über Kosten, Zeit oder Antwortqualität sagt sie nichts, und der Post behauptet auch nichts anderes.
Brauche ich Portal dafür?
Nein. Das Routing steckt in einer CLAUDE.md-Regel, zwei Agent-Dateien mit festgelegtem Modell und einem PreToolUse-Hook. Portal liefert bei Spotify die Worker-Modelle; eine Zeile model: haiku erledigt dasselbe in reinem Claude Code.
Wann kostet Delegation mehr?
Bei kleinen Dateien. Das Test-Szenario mit 45 Zeilen kostete mit Delegation 2.6% mehr, weil der Writer ein zweiter voller Kontext ist und das Hauptmodell das Ergebnis trotzdem erneut las und testete. Jeder delegierte Lauf war außerdem langsamer, im Schnitt +65.3%.
Warum hat der Hook nie ausgelöst?
Weil die Routing-Regel in der CLAUDE.md das Hauptmodell dazu brachte, wc -l zu prüfen und zu delegieren, bevor es zu lesen versuchte. Der Hook zählt nur, wenn das Modell die Regel ignoriert, was im Verifikationslauf ohne CLAUDE.md geschah.
AIDive