• Anthropic के डेवलपर्स ने Claude Fable 5, Claude Opus 4.8 और dynamic workflows का उपयोग करके पिछले एक महीने में दस ऐसे पैकेज migrate किए जिनका आकार दसियों हज़ार से लेकर लाखों lines of code तक था, और उन्होंने अलग-अलग code को ठीक करने के बजाय code generate करने वाली iterative process को बेहतर बनाया।
  • Bun का Zig→Rust migration 2 हफ्तों से कम समय में 10 लाख lines generate करके पूरा किया गया और merge से पहले मौजूदा tests 100% पास किए गए, जबकि Python→TypeScript प्रोजेक्ट में वीकेंड के दौरान 1,65,000 lines migrate की गईं और इसमें सैकड़ों agents, 8-stage gates और 3 adversarial reviews का उपयोग हुआ।
  • बड़े migration parallelize किए जा सकते हैं, मौजूदा code specification और ground truth का काम करता है, और compile/test failures अपने-आप अगली task queue बना देते हैं, इसलिए objective validation loop बनाना आसान होता है।
  • यह प्रक्रिया judgment criteria तैयार करने से शुरू होकर rulebook, dependency map और gap inventory बनाने, rules का stress test करने, full translation, compile, run और behavior comparison तक चरणबद्ध तरीके से चलती है; और बार-बार आने वाली errors को file-by-file ठीक करने के बजाय ऊपरी rules बदलकर फिर से generate किया जाता है।
  • लागत अब भी कई दसियों हज़ार से लेकर लाखों डॉलर तक हो सकती है, लेकिन failed branches को फेंककर फिर से कोशिश की जा सकती है; Bun migration ने API pricing के हिसाब से लगभग 165,000 डॉलर खर्च किए और इसके बाद memory usage कम हुआ, binary size 19% घटी और real workload performance 2~5% बेहतर हुई।

code नहीं, generation loop को बेहतर बनाने का तरीका

  • AI code migration वह तरीका है जिसमें agents production codebase को किसी नई language या framework में ले जाते हैं।
    • Engineer files को सीधे translate करने के बजाय migration rules और validation loops लिखता है।
    • Agent translation, compile और test को तब तक दोहराते हैं जब तक नए code का behavior source से मेल न खा जाए।
    • जिन projects में पहले कई साल लगते थे, उन्हें अब कुछ हफ्तों में पूरा किया जा सकता है।
  • Anthropic में Claude Fable 5, Claude Opus 4.8 और dynamic workflows का उपयोग करके एक महीने में दस ऐसे code packages migrate किए गए जिनका आकार दसियों हज़ार से लेकर लाखों lines तक था।
  • मुख्य operating principle यह था कि generated code को सीधे patch नहीं करना है, बल्कि उस code को बनाने वाले loop को बदलना है

वास्तविक migration के उदाहरण

  • Bun का Zig→Rust migration

    • Jarred Sumner ने Claude Code के साथ Bun को Zig से Rust में migrate किया
    • 2 हफ्तों से कम में 10 लाख lines का code generate किया गया।
    • Merge से पहले CI में Bun का मौजूदा test suite 100% पास हुआ।
    • Merge के बाद मिली 19 regressions सभी ठीक कर दी गईं।
    • Rust port जून में Claude Code में शामिल किया गया।
    • Bun के monthly downloads 1 करोड़ से ज़्यादा हैं और Claude Code के अंदर भी इसका व्यापक उपयोग होता है।
  • Python→TypeScript migration

    • Mike Krieger ने एक वीकेंड में Python codebase को 1,65,000 lines of TypeScript में migrate किया।
    • इसमें सैकड़ों agents, 8-stage gates और 3 adversarial reviews का उपयोग किया गया।
    • सभी commands के output को Python source से compare करने वाला अंतिम equivalence check किया गया।
    • पूरे migration result को फेंककर rules और workflow बदलने की प्रक्रिया कई बार दोहराई गई, और तीसरे run के नतीजे को अपनाया गया।

किन स्थितियों में language migration पर फिर से विचार करें

  • अगर शुरुआती development के बाद technical environment बदल गया हो, पुराने trade-offs अब constraints बन गए हों, बेहतर approach आ गई हो, या मूल ecosystem छोटा हो गया हो, तो migration पर विचार किया जा सकता है।
  • Zig ने C-level performance और simplicity दी, इसलिए Bun को अकेले develop किए जाने वाले शुरुआती phase में वह उपयुक्त था, लेकिन उसकी simplicity के साथ कुछ ज्ञात trade-offs भी थे।
  • पहले language migration के लिए roadmap रोकना पड़ता था और कई quarters तक resources लगाने पड़ते थे।
    • दो codebases को कई quarters या कई साल तक साथ बनाए रखना पड़ सकता था।
    • अगर अंत में behavior match सिर्फ 90% तक ही पहुँचे, तो शुरुआत से भी बड़ी maintenance problem पैदा हो सकती थी।
    • अब failed branch को delete करके फिर से run करने का विकल्प मौजूद है।
  • 10 लाख lines का migration अब 4 साल की engineering cost यानी 30~40 लाख डॉलर की मांग नहीं करता, लेकिन फिर भी इसमें कई दसियों हज़ार से लेकर लाखों डॉलर तक खर्च हो सकते हैं।
    • Bun migration में 5.9 अरब uncached input tokens और 69 करोड़ output tokens खर्च हुए।
    • API pricing के हिसाब से इसकी लागत लगभग 165,000 डॉलर थी।
    • Mike के port में core phase ने 2.7 करोड़ tokens का उपयोग किया।
  • Migration का business case अब जीवन-मरण का सवाल होना ज़रूरी नहीं है; एक साल तक बार-बार memory bug fix करना या कोई chronic bottleneck भी इसे justify कर सकता है।
  • Python build bottleneck हटाना

    • Mike का internal tool users को single binary के रूप में दिया जाता था, लेकिन Python toolchain से platform-specific binaries बनाने में लगभग 8 मिनट लगते थे।
    • पूरे build matrix में हर release के लिए लगभग 30 मिनट इंतज़ार करना पड़ता था।
    • TypeScript migration के बाद compile time लगभग 2 सेकंड रह गया, binary startup 6 गुना तेज़ हुआ, और अलग deployment pipeline भी हटा दी गई।

AI agents migration के लिए क्यों उपयुक्त हैं

  • Parallel work संभव है।
    • Files, crates और अन्य हज़ारों independent units में बाँटकर कई agents एक साथ काम कर सकते हैं।
  • मौजूदा code एक साफ़ और व्यापक specification की तरह काम करता है।
    • यह translation agents के लिए instructions बनाने का अहम reference भी बन सकता है।
  • Test suite एक built-in judge का काम करता है।
    • अगर validation objective हो, तो इंसानों को लगातार quality mediate नहीं करनी पड़ती और model कई दिनों तक ground truth के आधार पर iteration कर सकता है।
  • Compile या test failure अपने-आप अगली task item बन जाते हैं, इसलिए अलग से task queue लिखने की ज़रूरत कम हो जाती है।
  • Consistency और exception handling को loop में शामिल किया जा सकता है।
    • Reviewer हर समस्या को किसी violated rule से जोड़ता है।
    • जिस तरीके से किसी exception को हल किया गया, वह बाद में सभी agents के लिए follow किया जाने वाला rule बन जाता है।
    • Silent behavior mismatch की जगह rule violation एक explicit task item बन जाता है।
  • Fable और Opus 4.8 का उपयोग sub-agents के parallel work को delegate, orchestrate और validate करने, और लक्ष्य तक पहुँचने के कई रास्ते खोजने के लिए किया जाता है।
  • कई model tiers को मिलाकर advisor pattern से token usage optimize किया जाता है।

पूर्वशर्त: source और port को बराबरी से judge करना

  • Migration शुरू करने से पहले एक मज़बूत judge चाहिए जो source और target code को एक ही मानक से evaluate कर सके।
    • Judge के बिना success criteria और stopping condition दोनों नहीं होते।
    • Source language के internal functions पर निर्भर tests target code पर वैसे के वैसे चल नहीं सकते।
  • मौजूदा tests को उन tests में बाँटा जाता है जिन्हें external calls के रूप में व्यक्त किया जा सकता है, और उन tests में जो ऐसे internal implementations पर निर्भर हैं जिन्हें port नहीं किया जाएगा।
  • External behavior tests को फिर से ऐसे assertions के रूप में लिखा जाता है जिन्हें source और port दोनों पर चलाया जा सके।
    • Adversarial agent यह verify करता है कि rewrite के दौरान assertions कमजोर न हो जाएँ।
  • Judge को source code पर चलाकर उसके पास होने की पुष्टि की जाती है, फिर जानबूझकर तोड़े गए code पर fail होने की भी जाँच की जाती है।
  • Jarred के पास TypeScript जैसी तीसरी language में लिखा हुआ एक बड़ा test suite था।
  • Mike ने 7 real-world usage scenarios के साथ एक equivalence harness बनाया और behavior में होने वाले हर बदलाव को bug माना जिसे ठीक करना ज़रूरी था।

चरण 1: rulebook, dependency map और gap inventory

  • आधारभूत output सिर्फ translation result नहीं होता, बल्कि refactor किए जाने वाले locations की list, translation method की rulebook, और work order तय करने वाला dependency map भी होता है।
  • इन्हें बनाने का क्रम महत्वपूर्ण है।
    • पहले rulebook के defaults तय करने होते हैं, ताकि जिन चीज़ों को उन defaults से handle नहीं किया जा सकता उन्हें gap inventory में डाला जा सके।
    • Rulebook और gap inventory को संयुक्त audit के ज़रिए साथ में verify किया जाता है।
  • Rulebook

    • rulebook का रूप इस बात पर निर्भर करता है कि नया code पुरानी structure बनाए रखेगा या पूरी तरह redesign होगा।
    • Jarred की तरह structure बनाए रखने पर languages के types और idioms की mapping table केंद्र में होती है, और जिन्हें translate करना मुश्किल हो वे gap inventory में जाते हैं।
    • Mike की तरह redesign करने पर rulebook design document की भूमिका निभाती है।
    • Jarred ने Claude के साथ बातचीत करते हुए हर ambiguous area के लिए policy बनाई और अनुमानित 8 error categories की अलग-अलग समीक्षा करने के लिए 8 sub-agents बनाए।
  • Dependency map

    • Parallel migration में यह जानना ज़रूरी है कि कौन-सी files पहले ले जानी हैं और किन्हें एक ही batch में रखना है, इसलिए file dependencies समझनी पड़ती हैं।
    • Legacy code, C/C++, Python जैसी codebases, या explicit manifest न होने की स्थिति में dependencies को खुद खोजकर map करना पड़ता है।
    • Claude Code agents deterministic scripts लिखने, चलाने, review करने और revise करने वाले loop के ज़रिए यह map बना सकते हैं।
    • इसका generalized example dependency map prompt में देखा जा सकता है।
  • Language gap inventory और skeptical reviewers

    • Gap inventory उस knowledge को रिकॉर्ड करती है जो पुराने code में implicitly मौजूद है लेकिन target language में explicit लिखनी पड़ती है।
    • Zig→Rust में memory management approach प्रमुख अंतर था।
    • Zig में यह बात सिर्फ comment में हो सकती है कि caller को buffer free करना है; भूल जाने पर भी code compile हो जाता है और leak runtime में दिखती है।
    • Rust में ownership caller को transfer हो जाती है और memory automatically free होती है; move के बाद use करना या double free compile ही नहीं होता।
    • Python→TypeScript में interfaces और contracts मुख्य अंतर थे।
    • Python में incoming object और return value की shape declare करना ज़रूरी नहीं होता।
    • TypeScript में methods, arguments और return shapes के contracts लिखे बिना compile नहीं होता।
    • Jarred ने translation से पहले gaps की सूची बनाई, जबकि Mike ने पहले translate करके audit के दौरान सूची बनाई; इसलिए project के अनुसार दोनों approaches उपयोगी हो सकती हैं।
    • इसका generalized example gap inventory generation prompt में देखा जा सकता है।

चरण 2: rules का stress test

  • Full migration से पहले छोटे trial migration के ज़रिए rulebook को हिलाकर उसकी समस्याएँ ढूँढी जाती हैं।
  • Jarred ने तीन agent tasks की तुलना की।
    • पहले agent ने rulebook के अनुसार 3 files translate कीं।
    • दूसरे agent ने एक अनुभवी Rust engineer की तरह उसी पैमाने का translation किया।
    • तीसरे agent ने दोनों outputs के अंतर के आधार पर नई translation rules लिखीं।
  • इस प्रक्रिया में 1,448 files तक गलती फैलने से पहले 2 बड़ी समस्याएँ पकड़ ली गईं।
  • यह तरीका सिर्फ structure-preserving migration में काम करता है, जहाँ एक ही file के दो translations को line-by-line compare किया जा सकता है।
  • Mike की तरह redesign होने पर adversarial reviewers design document पर हमला करते हैं और disposable end-to-end runs से validate करना पड़ता है।
  • Trial में translate की गई files सभी फेंक देनी चाहिए; लक्ष्य incremental code progress नहीं, बल्कि rules को बेहतर बनाना है।
  • इसका generalized task example stress test prompt में देखा जा सकता है।

चरण 3: पूरे code का translation

  • इसके बाद के सभी चरण implement→review→fix वाले multi-agent loop का उपयोग करते हैं।
  • Bulk implementation छोटे models को और review बड़े models को दिया जा सकता है।
    • Mike ने core migration को parallelize करने के लिए 12 Claude Sonnet sub-agents का उपयोग किया।
  • Task queue को mechanical तरीके से manage किया जाता है।
    • Batch script translated file की disk पर मौजूदगी से completion status तय करती है।
    • बची हुई files को implementation agents के लिए batches में बाँटा जाता है।
    • हर run में disk state से queue फिर से बनती है, इसलिए यह मूल रूप से interruption के बाद resume की जा सकती है।
  • अगर agents बहुत सावधानी से बहुत कम काम कर रहे हों, तो उन्हें यह संदर्भ देते हुए अधिक सीधे निर्देश दिए जा सकते हैं कि अगला चरण compiler errors पकड़ लेगा।
  • जिन items पर agents आत्मविश्वास से आगे नहीं बढ़ पाते, उन्हें // TODO(port): <reason> से mark किया जाता है और चरण 4 में हल किया जाता है।
  • इसके बाद की task list compile errors, smoke test crashes और test failures से अपने-आप बनती है।
  • Adversarial review और rule updates

    • Independent context वाले 2 adversarial reviewers implementation results का मूल्यांकन करते हैं, और मतभेद होने पर तीसरा agent फैसला करता है।
    • अगर वही error कई files में दोहराई जाती है, तो files को अलग-अलग patch नहीं किया जाता।
    • Rulebook में एक वाक्य जोड़ा जाता है और प्रभावित batch फिर से generate किया जाता है।
    • Translation चरण में भी rulebook लगातार बढ़ती रहती है, और rules से हटे code को manually patch नहीं किया जाता।
  • Compiler को कहाँ रखना है

    • अगर compile time कम हो, तो इसे translation loop के अंदर शामिल किया जा सकता है।
    • Mike के मामले में TypeScript compile हर unit पर कुछ सेकंड में पूरा हो जाता था, इसलिए उसे हर loop में चलाया गया।
    • अगर compile में समय ज़्यादा लगे, तो उसे अगले चरण के लिए छोड़ दिया जाता है।
    • Jarred ने cargo run में कई मिनट लगने के कारण translation loop में compiler के उपयोग पर रोक लगा दी।
    • इस चरण से prompts छोटे होने लगते हैं; उदाहरण translation kickoff prompt में देखा जा सकता है।

चरण 4~6: compile, run और behavior match

  • ये तीनों चरण एक जैसी loop structure साझा करते हैं, और आगे बढ़ने के साथ मानवीय judgment की ज़रूरत कम होती जाती है।
  • Language और project scale के अनुसार compile चरण पूरे translation चरण में absorb हो सकता है।
  • चरण 4: Compile

    • Jarred ने orchestrator script को इस तरह सेट किया कि वह पूरे workspace पर compiler को एक बार चलाए।
    • Fix agents error list को parallel में handle करते हैं, adversarial review से गुजरते हैं, फिर build दोबारा होता है; यह cycle दोहराई जाती है।
    • Error list review का उपयोग individual errors नहीं, बल्कि systemic problems खोजने के लिए किया जाता है।
    • Zig की delayed compilation से संभव हुए circular imports को ठीक करने के बाद Rust module errors की हज़ारों समस्याएँ सामने आईं।
    • कौन-सी dependencies delete, move या boundaries redesign की जाएँ, इसके लिए loop में classification logic जोड़ी गई।
  • चरण 5: Run और smoke test

    • Smoke tests में होने वाले crashes compile error list की तरह ही mechanical ground truth का काम करते हैं।
    • समस्याओं को अलग-अलग नहीं, बल्कि root cause categories में समूहित किया जाता है, और adversarial sub-agents उनकी समीक्षा करते हैं।
  • चरण 6: Source के साथ behavior comparison

    • Translation, compile और smoke test पूरे कर चुके code को विभाजित किया जाता है, और पहले से तैयार test suite को source और port दोनों पर चलाया जाता है।
    • Fix agents failed tests और दोनों codebases को साथ देखकर काम करते हैं, और adversarial reviewers fixes की पुष्टि करते हैं।
    • सिर्फ build daemon को binaries दोबारा build करने की अनुमति होती है।
    • Fix agents patches लिखते हैं, daemon उन्हें इकट्ठा करके सिर्फ एक बार rebuild करता है।
    • प्रभावित tests फिर से चलाए जाते हैं और परिणाम लौटाया जाता है।
    • Work को serial किया जाता है ताकि कई agents अलग-अलग महंगे builds न चलाएँ।
    • अगर वही failure कई tests में दोहरती है, तो उस bug को पैदा करने वाले ऊपरी rule को बदला जाता है और सिर्फ उसी rule से प्रभावित files को regenerate किया जाता है।
  • अगर test suite न हो

    • Mike ने Claude से एक छोटा script बनवाया जो 7 वास्तविक scenarios को source Python code और नए port दोनों पर चलाकर outputs compare करता था।
    • हर failed scenario के लिए अलग fix agent दिया गया और 7 में से सभी के pass होने तक यह cycle दोहराई गई।
    • Claude ने अपना end-to-end test suite भी design किया और उसे रातभर autonomously चलाया।
    • Errors ठीक करके फिर से run करने की प्रक्रिया चार रात तक दोहराई गई।
    • पहले से लिखे scenario list की वजह से ऐसे छोटे usability issues भी पकड़े गए जिनका अनुमान लगाना कठिन था।
    • पुराने tests न होने पर भी source codebase को ground truth मानकर Claude judge बना सकता है।

बार-बार के runs से निकले operating principles

  • Guide को ज्यों का त्यों follow करने के बजाय project के गुणों के अनुसार Claude के साथ migration plan बनाकर काम शुरू करना चाहिए।
  • Individual failures fix agents पर छोड़ देनी चाहिए, और इंसानों को दोहराए जाने वाले error patterns पर ध्यान देना चाहिए।
  • Review adversarial होना चाहिए, और validation mechanical।
    • Adversarial review लंबे कामों में उपयोगी है और इसके लिए अतिरिक्त token खर्च करना सार्थक हो सकता है।
    • Compiler, diff और test suite जैसे scripts को अंतिम judge के रूप में उपयोग करना चाहिए।
  • हर काम में सबसे बड़ा model उपयोग नहीं किया जाता।
    • छोटे models का उपयोग bulk implementation parallelize करने में किया जाता है।
    • सबसे बड़े models review और उन rules को लिखने पर केंद्रित रहते हैं जिन्हें दूसरे agents follow करेंगे।
  • इंसानी समय को rulebook और stress tests में शुरुआत में ही निवेश करना चाहिए; उसके बाद का अधिकांश काम queue drain करने जैसा होता है।
  • Completion state को mechanical तरीके से पहचाना जा सके, जैसे ‘output file disk पर मौजूद है’, और queue resume करने योग्य होनी चाहिए।

Bun migration के परिणाम और सीमाएँ

  • Bun का Rust port production में चल रहा है, लेकिन Rust code का लगभग 4% unsafe blocks के अंदर है।
    • इसका ज़्यादातर हिस्सा C/C++ boundaries पर होने वाली एक-line pointer operations है।
  • Tools से detect की जा सकने वाली सभी memory leaks ठीक की गईं।
    • 2,000 बार build दोहराने वाले benchmark में memory usage 6,745MB से घटकर 609MB रह गई।
  • Linux और Windows binaries का size 19% कम हुआ।
  • Languages के बीच optimization के कारण HTTP service, next build और tsc जैसे वास्तविक workloads में 2~5% performance improvement मिला।
  • बड़े migration में generated code की हर line देखने के बजाय loop के outputs और recurring patterns की समीक्षा करनी चाहिए।

संबंधित सामग्री

  • Migration starter kit: यह लेख में बताई गई प्रक्रिया का generalized template है; दोनों वास्तविक ports इसी kit से चलाए गए हों, ऐसा नहीं है।
  • Code-modernization plugin: यह language port के बजाय legacy modernization और framework upgrade के लिए plugin है।
  • Dynamic workflows in Claude Code: Claude Code के dynamic workflows का परिचय

अभी कोई टिप्पणी नहीं है.

अभी कोई टिप्पणी नहीं है.