← वापस Blueprint line-art of interconnected gears and pipes forming a closed loop with a pressure gauge and exit valve.

Claude Code में Ralph Loops: Verifiers, Budgets और Stop Conditions

Ralph loop तीन चीजें हैं: एक task, एक verifier, और एक budget। बस यही पूरा pattern है। Geoffrey Huntley ने इसका नाम The Simpsons के एक character के नाम पर रखा है जो बस चलता रहता है, भले ही कुछ काम न कर रहा हो, और यह analogy ठीक है। खतरा यह नहीं है कि Claude जल्दी बंद हो जाए। खतरा यह है कि वह broken state पर success declare कर दे, आपका token budget जला दे, या दोनों। यह post covers करता है कि तीनों elements को precisely कैसे define करें, अपनी situation के लिए सही implementation pick करें, और loop को safely कैसे रोकें जब यह actually done हो। Agentic development workflow एक अलग concern है; यह post strictly iteration तक सीमित है जब तक एक condition hold न हो।

Goal, Verifier और Budget को Define करें

एक भी command लिखने से पहले, तीन sentences लिखें। "Done" कैसा दिखता है? आप mechanically उसे कैसे check करेंगे? और आप कितने iterations के लिए pay करने को तैयार हैं?

Goal machine-checkable होना चाहिए। "Code अच्छा है" एक goal नहीं है। "npm test में सभी tests pass हैं और git status clean है" एक goal है। अंतर इसलिए मायने रखता है क्योंकि verifier केवल वही observe कर सकता है जो उसे दिख सकता है। अगर आपकी completion condition किसी को कुछ देखने पर निर्भर करती है, तो आपके पास verifier नहीं है; आपके पास एक review step है, और ये दोनों चीजें एक ही loop में नहीं होनी चाहिएँ।

Verifier Claude का अपना opinion नहीं है। यह वह part है जहाँ ज्यादातर लोग गलती करते हैं। जैसे एक Hacker News commenter ने कहा, "अगर AI को लगता है कि चीजें काम कर रही हैं, तो वह COMPLETE कह देगा भले ही आपको न लगे कि वह complete है।" Model-generated DONE एक signal है, verifier नहीं। Real verifier एक external process है: आपका test runner, आपका linter, एक live endpoint के against curl जो expected status code return कर रहा हो। यह हर iteration के बाद चलता है और deterministic true/false produce करता है। पहले यह build करें।

Budget आपका safety valve है। एक ऐसा number pick करें जिसे जलाने के लिए आप actually comfortable हैं। frankbria/ralph-claude-code community implementation दोनों चीजें require करती है: heuristic completion indicators (दो या उससे ज्यादा) और एक explicit EXIT_SIGNAL: true model के RALPH_STATUS block में exit से पहले। यह dual-condition design सिर्फ इसलिए exist करती है क्योंकि single signals unreliable हैं। आपका --max-iterations पहली run के लिए conservative होना चाहिए। जब आप देख लें कि loop actually कितनी दूर जाता है, तो आप इसे raise कर सकते हैं।

सरल कहूँ तो, कुछ भी run करने से पहले आपका setup यह जवाब दे:

  • कौन सा shell command exit code 0 return करता है सिर्फ तब जब task genuinely complete हो?
  • मैं कितने iterations allow करूँगा — maximum?
  • कौन सी file या log iteration outcomes record करेगी ताकि मैं बाद में उन्हें inspect कर सकूँ?

Loop Implementation चुनें

Claude Code 2.1 तीन built-in primitives के साथ ship होता है जो most Ralph use cases को cover करते हैं बिना किसी plugin के। Awesome Claude guide तीनों को document करती है:

Blueprint line-art of a forked pipe with two paths, one open and one with a shutoff valve, representing loop implementation choices.
  1. /goal, turns भर चलता रहता है जब तक एक condition verify न हो जाए। Ranjan Kumar की write-up के अनुसार, हर turn के बाद session transcript को पढ़ने के लिए एक छोटा model (default में Haiku) use करता है और एक सवाल का जवाब देता है: क्या goal पूरा हुआ है? अगर नहीं, तो Claude एक और turn लेता है। अगर हाँ, तो loop clear हो जाता है।
  2. /loop, एक निर्धारित या स्वनियंत्रित अंतराल पर प्रॉम्प्ट को फिर से चलाता है। रोकने के लिए Esc दबाएँ। पोलिंग कार्यों के लिए उपयोगी है।
  3. /batch, एक बड़े परिवर्तन को 5 से 30 समानांतर worktree एजेंटों में फैलाता है। बिल्कुल अलग चीज़; एक भी बंधे हुए कार्य के लिए यह वो नहीं है जो आप चाहते हैं।

फिर प्लगइन पथ है, और कच्चा bash लूप है। यहाँ वे इस तरह अलग हैं जो वास्तव में आपके काम के लिए मायने रखता है।

प्लगइन (ralph-wiggum@claude-plugins-official या कम्युनिटी फ़ोर्क) एक स्टॉप हुक का उपयोग करते हुए एक सिंगल सेशन के अंदर चलता है। जब Claude निकलने की कोशिश करता है, तो हुक इसे बाधित करता है और प्रॉम्प्ट को वापस फीड करता है। संदर्भ पुनरावृत्तियों में जमा होता है। यह सुविधाजनक है, लेकिन इसका मतलब है कि 15वीं पुनरावृत्ति तक संदर्भ विंडो हर पिछले प्रयास का अवशेष ले जा रही है, जो प्रत्येक नए टर्न की गुणवत्ता को कम कर सकता है।

कच्चा bash दृष्टिकोण, PROMPT.md को एक while लूप के अंदर claude -p में पाइप करता है, हर बार एक पूरी तरह से ताज़ी प्रक्रिया शुरू करता है। जैसा कि Steve Kinney नोट करते हैं, "हर claude -p आह्वान को पूरी तरह से स्वच्छ संदर्भ विंडो मिलती है। यह पूरी तकनीक का मूल बिंदु है, संदर्भ सड़न से बचना जानबूझकर शुरुआत से नए सिरे से करके।" ट्रेडऑफ़: आप जो कुछ कोशिश किया गया था उसकी अंतर्निहित स्मृति खो देते हैं, इसलिए आपके PROMPT.md और कार्य-अवस्था फ़ाइलों को पुनरावृत्तियों के बीच सभी संदर्भ स्पष्ट रूप से ले जाने हैं।

आप कौन सा चुनेंगे? यदि आपका कार्य छोटा है (10 पुनरावृत्तियों से कम की अपेक्षा) और संदर्भ प्रबंधनीय रहता है, तो एक टर्न कैप के साथ /goal सबसे कम घर्षण वाला विकल्प है। यदि कार्य लंबा है या संदर्भ गुणवत्ता एक चिंता है, तो ताज़े-संदर्भ bash लूप अधिक विश्वसनीय है। परीक्षण और AI कोडिंग उपकरण पोस्ट बताता है कि अपने परीक्षण सूट को कैसे संरचित करें ताकि सत्यापनकर्ता दोनों तरीकों से स्वच्छ रूप से चल सके।

बंधी हुई पुनरावृत्तियों के साथ एक कार्य चलाएँ

/goal प्राइमिटिव का उपयोग करके एक बंधे हुए कार्य के लिए यहाँ एक सचित्र सेटअप है:

/goal npm test में सभी परीक्षण पास करें और git status स्वच्छ है, या 20 टर्न के बाद रुकें

वह एक पंक्ति Claude को एक सत्यापन योग्य निकास स्थिति और एक कठोर सीमा देती है। Haiku मूल्यांकनकर्ता हर टर्न के बाद प्रतिलिपि पढ़ता है और दोनों शर्तों की जाँच करता है। or stop after 20 turns खंड आपका बजट रक्षक है।

एक bash-लूप दृष्टिकोण के लिए, Geocodio टीम की संरचना का पालन करना एक अच्छा मॉडल है। वे एक JSON फ़ाइल (एक साधारण prd.json) का उपयोग करते हैं जहाँ प्रत्येक कार्य में एक "passes": false फ़ील्ड है। हर पुनरावृत्ति "passes": false के साथ सर्वोच्च-प्राथमिकता वाली कहानी खोजता है, इसे लागू करता है, सत्यापनकर्ता को चलाता है, और सफलता पर फ़्लैग को true पर फ़्लिप करता है। while लूप तब बाहर निकलता है जब हर कहानी के पास passes: true हो। उनकी सामग्री स्वीकृति-मानदंड संरचना के लिए अकेले पढ़ने योग्य है।

एक ताज़े-संदर्भ bash लूप के लिए क्रमांकित प्रवाह इस तरह दिखता है:

  1. वर्तमान कार्य, सत्यापनकर्ता कमांड, और पास/विफल लॉग पथ के साथ PROMPT.md लिखें।
  2. while लूप शुरू करें, PROMPT.md को claude -p में पाइप करते हुए।
  3. Claude निर्देशों को पढ़ता है, एक कार्य की इकाई करता है, git में प्रतिबद्ध होता है।
  4. सत्यापनकर्ता चलता है। निकास कोड 0 का मतलब पास है; कुछ और भी का मतलब विफल है।
  5. परिणाम को एक फ़ाइल में लॉग करें (पुनरावृत्ति संख्या, पास/विफल, टोकन लागत यदि उपलब्ध है)।
  6. यदि सभी कार्य पास करें, तो स्टॉप सिग्नल लिखें और ब्रेक करें। अन्यथा, चरण 2 पर वापस लूप करें।

प्रत्येक पुनरावृत्ति को एक कार्य की इकाई तक सीमित रखें। प्रति लूप बहुत अधिक करने की कोशिश करना इसी तरह है कि आप एक आधे-अधूरे राज्य में समाप्त होते हैं जिसे सत्यापनकर्ता स्वच्छ रूप से मूल्यांकन नहीं कर सकता।

कोई प्रगति न होना और झूठी समाप्ति का पता लगाएँ

दो विफलता तरीके अनंत लूप की तुलना में बहुत अधिक सामान्य हैं: लूप पुनरावृत्तियों में कोई प्रगति नहीं करता है, और मॉडल एक टूटी हुई स्थिति पर सफलता की घोषणा करता है।

किसी भी iteration N और iteration N+1 के बीच कुछ ठोस चीज़ की तुलना करके ही no-progress detection संभव है। git diff सबसे सरल संकेत है। अगर किसी iteration के बाद जो passing verifier नहीं देता, git diff HEAD~1 खाली है, तो loop घूम रहा है। आपको यह तुरंत बताना चाहिए, बजाय तीन और iterations बर्बाद करने के और कुछ बदलने की उम्मीद करने के।

False completion ज़्यादा पेचीदा है। Model ऐसी परिस्थितियों में DONE, COMPLETE, या EXIT_SIGNAL: true produce करेगा जहाँ आपका actual verifier non-zero exit code return करेगा। frankbria implementation की dual-condition check (दो-plus heuristic indicators और explicit signal) एक reasonable mitigation है। लेकिन तेज़ fix यह है: loop को model के output अकेले के आधार पर कभी exit न होने दें। Verifier script model जो भी कहे, चलता है, और अगर verifier fail होता है तो loop जारी रहता है, बस।

एक related trap का ख्याल रखें: verifier self ही false positive return कर रहा है। अगर आपके test suite में flaky tests हैं जो कभी-कभी underlying bug fix हुए बिना pass होती हैं, तो आपको एक false completion मिलेगा जो model ने cause ही नहीं किया। यह अगला section है।

Flaky Tests और Failed Verifiers को संभालें

Flaky tests किसी भी automated loop के दुश्मन हैं। एक test जो 80% समय pass होती है, आख़िरकार 20% जहाँ वह नहीं होनी चाहिए, loop exit trigger करेगी। और क्योंकि हर iteration tokens खर्च करता है, एक false exit followed by re-run महंगा है।

Mitigation complicated नहीं है, पर इसे कुछ upfront काम की ज़रूरत है:

  • Pass पर विश्वास करने से पहले अपने verifier command को लगातार तीन बार चलाएँ। अगर यह तीन में से एक बार fail होता है, तो इसे fail मानें।
  • अपने "क्या काम complete है" tests को अपने "क्या environment काम कर रहा है" tests से अलग करें। Network-dependent tests, timing-sensitive assertions, और कुछ भी जिसे external state की ज़रूरत है, verifier में न रखें जो loop exit को control करता है।
  • हर verifier run को इसके output के साथ log करें। अगर loop रुके और कुछ गलत लगे, तो आप final iteration से full verifier output चाहते हैं, सिर्फ exit code नहीं।

अगर verifier self ही fail करता है (crashes, times out, या एक unexpected error code return करता है जो test failure नहीं है), तो इसे loop halt मानें, loop continue नहीं। Broken verifier के through iterate करने की कोशिश सिर्फ ऐसे iterations produce करेगी जिनका evaluation नहीं हो सकता।

Claude Code hooks आपको session lifecycle के specific points पर scripts attach करने देते हैं। Claude Code hooks guide mechanism को detail में cover करती है। Ralph loops के लिए, relevant hook वह है जो fire होता है जब Claude exit करने की कोशिश करता है: इसे intercept करें, अपना verifier चलाएँ, और exit को तभी allow करें अगर verifier pass होता है। अगर आप plugin path use कर रहे हैं, यह पहले से ही wired है। अगर आप bash loop पर हैं, तो exit decision आपकी shell script में होता है hook में नहीं।

Cost को Record करें और Safely Stop करें

आपको पता होना चाहिए कि loop खत्म होने से पहले हर iteration की cost क्या है। आपको real time में exact numbers की ज़रूरत नहीं, पर आपको एक log file चाहिए जो iteration number, verifier outcome, और iteration के बाद spend estimate करने के लिए enough token information record करे।

Ralph loops पर Alibaba Cloud community post तीन stop conditions को identify करता है जो किसी भी implementation में build करने लायक हैं:

  • Success: verifier 0 return करता है और सभी tasks के passes: true हों।
  • No-progress halt: दो या ज़्यादा consecutive iterations जहाँ कोई git diff नहीं है और कोई verifier improvement नहीं है।
  • Budget exhaustion: iteration counter --max-iterations को hit करता है चाहे verifier state कोई भी हो।

Budget exhaustion एक failure mode नहीं है, यह एक designed stop है। जब यह trigger होता है, loop को एक summary लिखना चाहिए कि क्या pass हुआ, क्या नहीं, और last iteration ने क्या attempt किया। यह आपको एक clean handoff देता है manual review के लिए या एक revised prompt के साथ एक fresh loop के लिए।

एक चीज़ explicitly build करें: "loop stopped क्योंकि यह successful हुआ" और "loop stopped क्योंकि यह cap hit हुआ" के बीच अंतर। अगर आप terminal पर वापस आते हैं और देखते हैं "loop stopped at iteration 20," आपको पता होना चाहिए कि ये दोनों में से कौन सा है। Log file में एक single flag, STOP_REASON: BUDGET_EXHAUSTED versus STOP_REASON: SUCCESS, बस काफ़ी है।

अगर आप इस तरह के काम scale पर कर रहे हैं या एक managed setup चाहते हैं बजाय hand-rolled scripts के, तो agentic engineering work cover करता है कि proper observability के साथ production-grade loop setup कैसा दिखता है।

FAQ

क्या `/goal` actually एक Ralph loop है, या कुछ अलग है?

ये same principle share करते हैं (iterate जब तक condition hold न हो) पर architecture में भिन्न हैं। /goal एक single persistent session के अंदर चलता है; एक classic Ralph bash loop हर iteration पर एक fresh process spawn करता है। जैसा Ranjan Kumar documents करता है, /goal transcript के बाद evaluate करने के लिए एक separate Haiku model use करता है। Bash loop कुछ नहीं evaluate करता, आपकी shell script checking करती है। दोनों valid हैं; pick करें इस आधार पर कि आपके task के लिए context accumulation एक problem है या नहीं।

क्या मैं मॉडल के अपने `DONE` आउटपुट को वेरिफायर के रूप में उपयोग कर सकता हूँ?

नहीं। मॉडल का आउटपुट एक सिग्नल है जिसे आप एक इनपुट के रूप में उपयोग कर सकते हैं, लेकिन यह एकमात्र एक्जिट कंडीशन नहीं हो सकता। एक मॉडल पूर्णता मार्कर तब आउटपुट करता है जब वह मानता है कि कार्य पूरा हो गया है, जो वास्तविकता से अलग होता है। किसी भी मॉडल-जनरेटेड सिग्नल को एक बाहरी कमांड के साथ जोड़ें जो सिस्टम की वास्तविक स्थिति की जाँच करता है।

अगर Claude Code रन के दौरान कॉन्टेक्स्ट को कम्पैक्ट करता है तो लूप का क्या होता है?

एक persistent-session लूप (प्लगइन या /goal) में, कॉन्टेक्स्ट बढ़ने पर कम्पैक्शन स्वचालित रूप से होता है, और उस कम्पैक्शन की गुणवत्ता असंगत होती है। एक Hacker News कमेंटर ने देखा कि "Claude Code कम्पैक्शन इतनी कम गुणवत्ता वाली हैं कि यह हर कुछ बारी में इतिहास को साफ़ करने जैसा ही है।" fresh-context bash लूप इसे पूरी तरह से टालता है क्योंकि प्रत्येक इटरेशन स्वच्छ शुरू होता है। अगर आप प्लगइन पथ पर हैं और लंबे कार्य चला रहे हैं, तो कम्पैक्शन पॉइंट के बाद आउटपुट गुणवत्ता में गिरावट देखें।

प्रत्येक इटरेशन का कार्य कितना छोटा होना चाहिए?

जितना छोटा हो सके जब तक वह सार्थक हो। प्रति इटरेशन एक कार्य सही मानसिकता है। Geocodio पद्धति (prd.json से एक स्टोरी प्रति लूप) और Hacker News कमेंटर का विवरण ("यह सबसे महत्वपूर्ण कार्य चुनता है, इसे पूरा करता है, और अपना लूप समाप्त करता है") दोनों एक ही उत्तर की ओर इशारा करते हैं: छोटे, सत्यापनीय हिस्से बड़े महत्वाकांक्षी इटरेशन से कहीं अधिक विश्वसनीय होते हैं।

क्या मुझे बिल्कुल प्लगइन की जरूरत है?

अधिकांश कार्यों के लिए, नहीं। turn cap के साथ built-in /goal प्राइमिटिव सामान्य मामले को कवर करता है। जब आप विशेष रूप से stop-hook interception behaviour या वह dual-condition exit लॉजिक चाहते हैं जो वे कार्यान्वयन प्रदान करते हैं, तो प्लगइन (ralph-wiggum@claude-plugins-official या frankbria/ralph-claude-code) के लिए पहुँचें। सिर्फ इसलिए प्लगइन इंस्टॉल न करें क्योंकि आपने इसे किसी ट्यूटोरियल में देखा है।

इस पूरे पैटर्न में सबसे महत्वपूर्ण सावधानी: एक मॉडल-जनरेटेड पूर्णता सिग्नल एक वेरिफायर नहीं है। बाहरी जाँच पहले, किसी और चीज़ से पहले, बनाएं, और हर दूसरे निर्णय को उससे आगे बढ़ने दें।

← वापस