नब्बे प्रतिशत, और वो वाक्य जिसने इसे बेचा
Spotify का Claude Code setup एक blog post है, जिसे Spotify के product manager Dimitri Mazmanov ने लिखा है और जिसका code GitHub पर है: उनका कहना है कि उनकी टीम जो configuration इस्तेमाल करती है, उसने उनका Claude Code token usage 90% घटा दिया। उनकी पहली ही पंक्ति पूरी दलील समेट लेती है: एक AI coding agent जो करता है, उसका ज़्यादातर हिस्सा सोचना नहीं, I/O है। एक method के बारे में सवाल का जवाब देने के लिए पाँच फ़ाइलें पढ़ना, या इक्कीसवीं test फ़ाइल लिखना जो बगल की बीस फ़ाइलों की नकल है, हज़ारों tokens फूँक देता है और उसमें reasoning लगभग शून्य होती है।
एक tweet ने इस post को एक ही वाक्य के दम पर पंद्रह लाख views तक पहुँचा दिया: लिखे हुए नियम एक सुझाव हैं, block नहीं। Hacker News ने इसे front page पर रखा, 271 points और 173 comments, और आधे comments एक ही सवाल पूछ रहे थे: 90% किसका? Spotify का अपना qualifier है "bulk read"। यह लेख उसी setup को plain Claude Code के अंदर फिर से बनाता है, फिर उसे मापता है, ताकि आपको ठीक-ठीक पता हो कि वह qualifier आपको क्या दिलाता है।
Portal असल में क्या है (और आप इसे क्यों नहीं चला सकते)
Portal कोई router नहीं है। यह Spotify का internal developer portal है, जो Backstage पर बना है, वही developer platform जिसे Spotify ने open source किया था। इसके अंदर जो feature यहाँ मायने रखता है, उसका नाम Modes है: Spotify की परिभाषा के मुताबिक, एक mode एक declarative agent है जो एक ephemeral runtime पर चलता है, मोटे तौर पर agents के लिए AWS Lambda। आप instructions लिखते हैं, एक model चुनते हैं, temperature सेट करते हैं, tools जोड़ते हैं। Mazmanov ने इनमें से दो बनाए, एक bulk reader और एक code writer, दोनों Gemini Flash पर temperature 0.2 के साथ, यानी दोनों जानबूझकर सस्ते और साधारण हैं।
Routing एक Claude Code plugin में रहती है जिसका नाम Shunt है। यह GitHub पर public है और दो commands में install हो जाता है। लेकिन step दो Portal की command line को आपके Portal instance के खिलाफ authenticate करता है, और आपके पास कोई Portal instance है ही नहीं। plugin public है; जिस चीज़ को वह काम सौंपता है, वह public नहीं है।
इसलिए समझदारी इसमें है कि plugin को भूल जाएँ और pattern को रख लें। उनके अपने शब्दों में इसकी तीन layers हैं: hooks, scripts, skills। इनमें से हर एक का plain Claude Code में एक equivalent मौजूद है, और इस लेख का बाकी हिस्सा उसी को बनाता और मापता है।
Layer एक: वो hook जो पूछने की जगह block करता है
Setup का version 1 project की instruction फ़ाइल में routing rules का एक block था। Mazmanov के शब्दों में यह "कुछ हद तक काम करता था": नियम सलाह भर थे, enforce नहीं होते थे, Claude उन्हें नज़रअंदाज़ कर सकता था, और हर project को अपनी अलग copy चाहिए थी। Version 2 इस फ़ैसले को prompt से निकालकर tool layer में ले जाता है, दो hooks के साथ, जो दोनों किसी tool call से पहले चलते हैं। एक हर file read पर नज़र रखता है, दूसरा shell पर।
Read hook bash की 33 लाइनें है। यह environment से एक threshold पढ़ता है, default में 350 लाइनें, फिर तीन चीज़ों को जाने देता है:
- कोई read जिसमें offset या limit हो, क्योंकि Claude को पहले से पता है कि उसे क्या चाहिए।
- कोई फ़ाइल जो मौजूद ही नहीं है।
- कोई फ़ाइल जो threshold पर या उससे नीचे है, क्योंकि छोटी चीज़ delegate करना उसे पढ़ने से महँगा पड़ता है।
बाकी सब block हो जाता है, एक message के साथ जिसे Claude फ़ाइल की जगह पढ़ता है: यह फ़ाइल इतनी लाइनों की है, bulk reader skill इस्तेमाल करो, और अगर edit के लिए exact content चाहिए तो सिर्फ़ वही section दोबारा पढ़ो। Shell hook किसी बड़ी फ़ाइल पर cat, head, tail, less और more को पकड़ता है। piped command पास हो जाती है, क्योंकि grep में pipe करना एक targeted read है।
Layering पर Mazmanov की बात ही असली बात है: अगर Claude skill description कभी पढ़े भी नहीं, तब भी hook महँगे read को block कर देता है। skill redirect को आसान बनाती है; block उसे असली बनाता है। एक detail आगे काम आएगी: script एक top-level decision के साथ जवाब देती है जिसका नाम "block" है। इस शब्द को याद रखिए।
Layer दो और तीन: workers और उनके numbers
Workers दो prompts हैं। reader: "you are a precise code analyst, output structured bullets only, no greetings, no prose, lead every bullet with the exact name, type or line number." writer: "match the existing patterns, naming and style exactly; output only the code, no fences, no explanations." उस आखिरी लाइन के बिना model सब कुछ Markdown में लपेट देता है, जिसे फिर Claude को parse करना पड़ता है।
दो scripts इन्हें wrap करती हैं। Bulk-read एक सवाल और file paths लेती है और उन्हें भेज देती है। Code-write एक spec और एक reference फ़ाइल लेती है और नतीजा सीधे disk पर लिख देती है, इसलिए Claude generated code को कभी देखता ही नहीं। हर delegation one-shot है: एक follow-up फ़ाइलें फिर से भेजता है। जहाँ मायने रखता है वहाँ यह मुफ़्त है, क्योंकि corpus worker के पास जाता है और Claude के context में कभी नहीं घुसता।
Layer तीन एक skill फ़ाइल है जो Claude को बताती है कि कब delegate करना है: 350 लाइनों से ऊपर की फ़ाइलें, तीन या उससे ज़्यादा फ़ाइलों में फैले सवाल, बड़े diffs। इसकी आखिरी लाइन है "verify line numbers before you edit"।
Spotify की table एक Java monorepo और तीन read scenarios को cover करती है। single-file case करीब 34,000 tokens से गिरकर 6,000 से नीचे आ जाता है, और तीनों rows में औसत बचत 90% है।
| Spotify का benchmark | मान |
|---|---|
| Repository | 1 Java monorepo |
| Scenario | 3, सभी bulk read |
| Single-file case, पहले | ~34,000 tokens |
| Single-file case, बाद में | < 6,000 tokens |
| औसत बचत | 90% |
| Token का अनुमान | प्रति token 4 characters |
| Writer पर enforcement | कोई नहीं (सिर्फ reader पर hook है) |
दो caveats खुद Spotify ने छापे हैं: tokens का अनुमान चार characters प्रति token के हिसाब से लगाया गया है, और writer पर कोई enforcement है ही नहीं। तो 90% तीन bulk-read rows का औसत है, अनुमानित input tokens में, बिना किसी quality score और बिना किसी dollar figure के। यही वह number है जिसे परखना है।
Rebuild, भाग एक: model field वाला एक subagent
Claude Code में एक built-in Explore subagent आता है, और एक हालिया release से यह आपके main model को inherit करता है, Opus तक capped, इसलिए "सस्ता reader" अब सस्ता नहीं रहा। Documentation एक वाक्य में इसका हल देता है: Explore नाम का एक project subagent built-in वाले को override करता है और अपना model field रखता है। एक markdown फ़ाइल, एक front matter, और model वाली लाइन में Haiku। यही bulk reader है। writer दूसरी फ़ाइल है: model Sonnet, tools सिर्फ़ Read और Write, और body में Spotify के अपने instructions paste किए हुए।
यह इसलिए काम करता है क्योंकि हर subagent एक ताज़ा, isolated context window के साथ शुरू होता है। वह जो पढ़ता है वह वहीं रहता है, main conversation में नहीं। यह Spotify का one-shot delegation है, बस network round trip के बिना।
फिर आता है वह हिस्सा जिसकी कोई योजना नहीं बनाता। इस हफ़्ते Reddit पर Fable को Opus agents spawn करने को कहा गया और उसने पाँच Fable agents spawn कर दिए: weekly limit का 73% तीस मिनट में खत्म। सबसे ऊपर का जवाब एक hook था जो तब चलता है जब model कोई subagent dispatch करता है, उसे model explicitly चुनने पर मजबूर करता है, और कहता है कि सबसे सस्ता वह model चुनो जो काम कर सके। यही hook नंबर तीन है: यह Agent tool पर नज़र रखता है, और जिस call में model नहीं है उसे एक वाक्य के साथ refuse कर देता है, "choose the model explicitly"।
Spotify की skill project की instruction फ़ाइल में तीन लाइनें बन जाती है: 350 लाइनों से ऊपर की फ़ाइलें explorer के पास जाती हैं, boilerplate writer के पास जाता है, हर agent call एक model सेट करती है। एक सीधा-सपाट विकल्प भी है: दो environment variables जो हर subagent पर एक ही model थोप देते हैं। ईमानदार सीमा यह है कि reader एक सस्ता model है, इसलिए वह जो लौटाता है वही main model को पता होता है। माप वाला section इसी को cover करता है।
Rebuild, भाग दो: deny, आज के hook format में
"block" शब्द याद है? Spotify की script एक top-level decision लौटाती है, लेकिन Claude Code का मौजूदा documentation कुछ और कहता है: एक PreToolUse hook अपना decision एक hook-specific output object के अंदर लौटाता है, और उस field का नाम permissionDecision है। इसके चार outcomes हैं, allow, deny, ask और defer, और यहाँ जो चाहिए वह deny है। hook reason के तौर पर जो भी लिखता है वह Claude को दिखाया जाता है, और अगर कई hooks जवाब दें तो deny जीतता है।
फिर से बनाया गया read hook वही 350 का threshold और वही तीन exceptions रखता है, और "block" की जगह एक deny लौटाता है, ऐसे reason के साथ जो Explore subagent और इस्तेमाल किए जाने वाले model का नाम लेता है। एक जाल जिसे docs साफ़ शब्दों में बताते हैं: आपकी settings के hooks subagents के अंदर भी चलते हैं। किसी escape के बिना Haiku reader अपने ही reads पर deny हो जाता है और अपना काम कभी कर ही नहीं पाता, इसलिए script देखती है कि call कौन कर रहा है और दोनों workers को जाने देती है।
Wiring एक settings फ़ाइल है जिसमें तीन matchers हैं, Read, Bash और Agent, हर एक अपनी script की ओर इशारा करता है, और threshold एक environment variable के तौर पर सेट है। असल में 1,090 लाइनों की फ़ाइल पर एक read एक error के रूप में लौटता है, उसी लिखे हुए वाक्य के साथ: यह read explorer को delegate करो, model Haiku। फिर delegation होता है: main model पहले लाइनें गिनता है, model Haiku सेट करके explorer को call करता है, और bullets वापस आते हैं, हर एक अपने line number के साथ। तीन turns, 44 seconds।
Spotify की बात टिकती है: layering का मतलब है कि system gracefully degrade करता है। instruction routing करती है, hook जाल है। पर जाल में एक छेद है। जो model पूरी फ़ाइल चाहता है, वह उसे offset और limit से टुकड़ों में पढ़ सकता है, जो पास हो जाता है, या sed range से shell के ज़रिए dump कर सकता है, जिसे यह hook नहीं पकड़ता। माप दोनों को गिनता है।
माप
Test repository Fastify है, Node का web framework: 294 फ़ाइलें, जिनमें से 63 threshold से ऊपर। दो एक जैसे clones, फ़र्क सिर्फ़ .claude folder और rule फ़ाइल का। main model Opus, जो CLI का default है; reader Haiku; writer Sonnet। single-prompt sessions, कोई follow-up नहीं, हर scenario हर configuration में दो बार, कुल सोलह runs। चारों scenarios वही हैं जो Spotify के थे: एक बड़ी फ़ाइल के exports, तीन फ़ाइलें और वे एक-दूसरे को कैसे call करती हैं, एक source फ़ाइल बनाम उसका test, और एक मौजूदा फ़ाइल से disk पर लिखी गई एक नई test फ़ाइल।
| Scenario | Main context, बिना | Main context, साथ | बदलाव | कुल लागत, बिना | कुल लागत, साथ | बदलाव | अवधि, बिना | अवधि, साथ | बदलाव |
|---|---|---|---|---|---|---|---|---|---|
| एक बड़ी file | 88,693 | 51,552 | -41.9% | $0.139 | $0.087 | -37.8% | 22 s | 44 s | +100.8% |
| तीन files | 357,166 | 73,440 | -79.4% | $0.581 | $0.218 | -62.4% | 52 s | 129 s | +149.9% |
| Source बनाम test | 303,808 | 114,136 | -62.4% | $0.451 | $0.374 | -17.1% | 93 s | 125 s | +33.6% |
| नई test file | 143,432 | 121,818 | -15.1% | $0.295 | $0.302 | +2.6% | 66 s | 87 s | +32.2% |
| चारों | 223,274 | 90,236 | -59.6% | $0.366 | $0.245 | -33.1% | 58 s | 96 s | +65.3% |
Main context, यानी वे tokens जो महँगे model ने सच में देखे, पहला column है जो मायने रखता है। तीन फ़ाइलों वाले सवाल पर यह 79% गिरता है, और चारों scenarios में मिलाकर 59.6%। bill कम गिरता है, कुल मिलाकर एक तिहाई, क्योंकि reader के अपने tokens मुफ़्त नहीं हैं, और छोटे test-writing task पर bill 2.6% बढ़ गया। समय उल्टी दिशा में जाता है: setup के बिना औसतन 58 seconds, साथ में 96। delegation हर बार धीमी है।
Quality वह जगह है जहाँ दोनों configurations सबसे ज़्यादा अलग पड़ती हैं। setup के बिना main model ने फ़ाइलें बिना line numbers के shell से dump कीं और हाथ से गिना, जिससे हर जगह गलत line numbers निकले: जो function line 149 पर बताया गया, वह असल में line 156 पर था। setup के साथ, चार में से एक run ने reader की summary को जस का तस मान लिया और तीन झूठे दावे साथ ले आया, उनमें से एक ऐसा function जिसे reader के मुताबिक route फ़ाइल कभी call नहीं करती, जबकि करती है, line 553 पर। चारों generated test फ़ाइलें pass होती हैं, और deny hooks सोलह runs में शून्य बार चले: rule फ़ाइल मौजूद होने पर main model ने हर बार line count देखा और खुद ही delegate किया।
Traces से एक और बात: rule के बिना main model ने Read tool कभी इस्तेमाल ही नहीं किया। उसने सब कुछ shell के ज़रिए पढ़ा, और shell का range read उतने ही tokens खर्च करता है और hook से पास हो जाता है। तो Spotify की table 90 कहती है; यह वाली context पर 60 और bill पर एक तिहाई कहती है।
block रखो। bill के नब्बे प्रतिशत गिरने की उम्मीद मत करो।
तीन चीज़ें रखने लायक हैं: Haiku पर एक project Explore subagent, instruction फ़ाइल में तीन लाइन का rule, और safety net के तौर पर read hook। मापा गया नतीजा है 60% कम main context, bill में एक तिहाई की कटौती, और दो तिहाई ज़्यादा wall time।
Hook पर भरोसा करने से पहले दो चीज़ें ठीक कीजिए। hooks subagents के अंदर चलते हैं, इसलिए अपने workers को exempt कीजिए। और shell वाला छेद: bash hook cat, head और tail को पकड़ता है, लेकिन range read पास हो जाता है, और rule न होने पर main model ने ठीक यही इस्तेमाल किया।
Spotify की अपनी सीमाएँ कायम हैं। आप editing delegate नहीं कर सकते और reasoning delegate नहीं कर सकते; worker एक thread-safety bug चूक गया जिसे Claude ने seconds में पकड़ लिया, और हर delegation एक round trip है। Hacker News के skeptics एक बात पर सही भी थे: input tokens bill नहीं हैं। output tokens ज़्यादा महँगे हैं, और यह setup उनके लिए कुछ नहीं करता।
कौन बचाता है, यह इस पर निर्भर है कि आप भुगतान कैसे करते हैं। API पर, एक तिहाई की बचत। Pro या Max plan पर वही setup आपकी five-hour और weekly windows को हिलाता है, dollars को नहीं। threshold का भी ध्यान रखिए: उससे नीचे delegation जितना बचाती है उससे ज़्यादा खर्च करती है, और 45 लाइनों का test case इसका सबूत है, plus 2.6%। आखिर में, आठ में से दो runs में reader की summary में गलतियाँ थीं, और main model के verification turn ने उन्हें पकड़ लिया। वह turn छोड़ दीजिए और वे गलतियाँ आपके edits तक पहुँच जाएँगी।
AIDive