जो चार prompt आप दोहराते हैं, वे चार फ़ाइलें बनते हैं
Claude Code extensions वे फ़ाइलें हैं जिन्हें एक repo अपने अंदर रख सकता है, ताकि आपको वही prompt बार-बार टाइप न करना पड़े: एक skill, एक hook, एक subagent और एक MCP server। हमने एक असली repo पर चार बार-बार आने वाले काम चलाए, एक छोटा इनवॉइस API जिसका डेटाबेस एक JSON फ़ाइल है। हर काम को पहले गलत extension दिया गया, और गलत चुनाव हर बार स्क्रीन पर फेल हुआ। फिर हर काम एक committed फ़ाइल बन गया। यह पेज चारों तरीके और वह चुनाव कार्ड दिखाता है जो तय करता है कि कौन सा प्रकार इस्तेमाल करना है।
दो नतीजे नीचे की हर बात का ढाँचा तय करते हैं। hook को अक्सर गारंटी कहा जाता है और memory फ़ाइल के नियम को अनुरोध, फिर भी हमारा पहला hook चला, उसने अपनी चेतावनी छापी, और write फिर भी हो गया। जो hook सिर्फ़ चलता है, उसे जो hook रोकता है उसमें क्या बदलता है, यह hook वाले सेक्शन में है। पहला docs server जो हमने जोड़ा उससे कुछ नहीं बदला, और जिसने जवाब दिया वह टूल का अपना docs server था। ज़्यादातर लोग जो hook नुस्खा कॉपी करते हैं उसे एक अलग स्क्रिप्ट फ़ाइल भी चाहिए, लेकिन हमारा पूरा का पूरा settings फ़ाइल में समा जाता है।
चारों फ़ाइलों में से कोई भी लिखने से पहले आपको जानना होगा कि आपका session पहले से क्या लोड करता है।
ये चारों क्या हैं, और आपका session पहले से क्या लोड करता है
Claude Code extension वह फ़ाइल है जिसे आप अपने repo में जोड़ते हैं ताकि वही निर्देश prompt बॉक्स में बार-बार टाइप न करने पड़ें। चार प्रकार हैं, और जो पाठक इन्हें पहले से जानते हैं वे अगले सेक्शन पर जा सकते हैं।
- skill आपके repo में रखा एक runbook है। Claude उसके steps तभी लोड करता है जब वह काम सामने आता है, और आप उसका नाम टाइप करके उसे शुरू कर सकते हैं।
- hook git के commit hook जैसा है, लेकिन Claude के अपने कामों के लिए। यह एक स्क्रिप्ट है जो किसी event पर चलती है, जैसे किसी edit पर, चाहे Claude का इरादा कुछ भी हो।
- subagent एक खाली मेज़ वाला ठेकेदार है। उसे आपकी brief मिलती है, वह पढ़ने का काम करता है, और ढेर की जगह एक रिपोर्ट वापस भेजता है।
- MCP server एक API क्लाइंट है जिसे Claude कॉल कर सकता है, उस डेटा के लिए जो आपकी डिस्क पर नहीं है, जैसे कोई डेटाबेस या किसी टूल के docs।
कुछ भी मापने के लिए पहले एक बेसलाइन चाहिए। एक नया session खोलिए और context कमांड चलाइए। यह आपके पहले शब्द से पहले लोड हुई हर चीज़ की तालिका छापता है। हमारे bench पर कुल 26.2k token थे, 1m window में से, और न memory फ़ाइलों की कोई लाइन थी, न MCP की कोई लाइन। अब से Claude को दिया हर काम या तो उस तालिका में एक लाइन जोड़ेगा या उसे जस का तस छोड़ेगा।
पहला काम: release चेकलिस्ट skill बनती है
skill एक चेकलिस्ट है जो अपने फ़ोल्डर में रखी होती है और Claude उसे तभी पढ़ता है जब आप उसे बुलाते हैं। पहला काम एक release चेकलिस्ट है जिसे आप prompt बॉक्स में चिपकाते रहते हैं: typecheck, tests, version bump, changelog की एक लाइन, commit और tag।
इसके लिए सबसे साफ़ दिखने वाली जगह memory फ़ाइल है, और वह गलत चुनाव है, क्योंकि उस फ़ाइल की हर चीज़ हर session के हर turn पर लोड होती है। हमने steps वहाँ रखे और context तालिका फिर पढ़ी। उसमें 210 token की एक Memory files लाइन जुड़ गई थी, जो आप release कर रहे हों या नहीं, लोड होती है। docs भी यही कहते हैं: जब उस फ़ाइल का कोई हिस्सा प्रक्रिया बन जाए, तो उसकी जगह skill में है।
सही चुनाव skills डायरेक्टरी के नीचे एक फ़ोल्डर है, जिसमें steps .claude/skills/release/SKILL.md में हों, ऊपर एक छोटा description हो, और frontmatter की एक अतिरिक्त लाइन disable-model-invocation: true हो। यह लाइन skill को Claude की अपनी सूची से बाहर रखती है, इसलिए उसे सिर्फ़ आप शुरू कर सकते हैं, और जो चीज़ commit और tag करती है उसके लिए आप यही चाहते हैं। फिर आप स्लैश और उसका नाम टाइप करते हैं, और चेकलिस्ट चल पड़ती है।
| Context रीडिंग | कुल | Memory files लाइन |
|---|---|---|
| बेसलाइन, नया session | 26.2k / 1m | कोई नहीं |
| चेकलिस्ट memory फ़ाइल में | 26.4k / 1m | 210 token |
| चेकलिस्ट skill के रूप में | 26.2k / 1m | कोई नहीं, skill सूचीबद्ध नहीं |
जब हमने इसे चलाया, Claude ने एक मिनट से कम में सभी छह steps पूरे किए: typecheck, 34 tests, version bump 0.4.0 से 0.4.1, changelog की लाइन, commit और tag। उसने हमारी अपनी चेकलिस्ट की एक खामी भी पकड़ी। जैसा लिखा था वैसा commit कमांड untracked फ़ाइलें छोड़ देता है, इसलिए Claude ने पहले नया changelog stage किया और यह बताया भी। अब release एक ऐसा कमांड है जो आप टाइप करते हैं, वह पूरी टीम के लिए repo में रहता है, और जब तक आप टाइप न करें, context में उसकी कोई कीमत नहीं।
दूसरा काम: जो नियम टिकना चाहिए वह hook बनता है
hook एक स्क्रिप्ट है जिसे Claude Code किसी टूल के चलने से पहले चलाता है, यहाँ किसी भी edit या write से पहले, और वह स्क्रिप्ट जो जवाब देती है उसी से तय होता है कि आगे क्या होगा। दूसरा काम एक ऐसा नियम है जो कभी नहीं टूटना चाहिए: इस repo में संग्रहीत डेटा फ़ाइल को कभी हाथ से edit नहीं किया जाता, और हर बदलाव एक migration से होता है।
उस नियम को memory फ़ाइल में बड़े अक्षरों में लिख देने से वह लागू नहीं होता। docs साफ़ कहते हैं: वह फ़ाइल context है, लागू की गई configuration नहीं, और "इस फ़ाइल को कभी edit मत करो" जैसा निर्देश एक अनुरोध है, गारंटी नहीं, जबकि edit को रोकने वाला hook enforcement है।
सबसे साफ़ दिखने वाला पहला hook वही है जो हमने लिखा। settings फ़ाइल में वह डेटा फ़ाइल पर writes पर नज़र रखता है, एक चेतावनी छापता है, और exit code शून्य से बाहर निकलता है, ठीक किसी लॉगिंग स्क्रिप्ट की तरह। फिर हमने Claude से कहा कि वह बिना किसी migration के सीधे फ़ाइल में एक इनवॉइस की रकम बदल दे। hook चला और चेतावनी छपी, लेकिन write हो गया: तीसरे इनवॉइस की unit price 8000 से 12000 हो गई। Claude के जवाब में hook का ज़िक्र कभी नहीं आया, क्योंकि जो hook साफ़ exit करता है और कुछ नहीं छापता उसने कोई फ़ैसला किया ही नहीं, और उसकी चेतावनियाँ Claude तक पहुँचती नहीं।
गारंटी hook का चलना नहीं है, वह जवाब है जो वह लौटाता है। समाधान वही hook रखता है और उसे deny फ़ैसला लौटाने वाला बनाता है: JSON की एक छोटी लाइन जिसमें वह कारण हो जो आप Claude को पढ़ाना चाहते हैं। exit code दो से बाहर निकलना भी उसी तरह रोकता है। पूरा hook .claude/settings.json में एक inline कमांड है, बिना किसी स्क्रिप्ट फ़ाइल के:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "jq -c 'if (.tool_input.file_path // \"\") | test(\"data/.*\\\\.json$\") then {hookSpecificOutput: {hookEventName: \"PreToolUse\", permissionDecision: \"deny\", permissionDecisionReason: \"Stored data is never edited by hand: write a migration in src/store/migrations.ts (README § Conventions).\"}} else empty end'"
}
]
}
]
}
}
उसी अनुरोध पर edit रोक दिया गया और डेटा फ़ाइल अछूती रही। Claude को यह error दिखा: PreToolUse:Edit hook error: Stored data is never edited by hand: write a migration in src/store/migrations.ts (README § Conventions). उसने कहा कि उसने कुछ नहीं बदला और पूछा कि guardrail को override करे या migration लिखे।
सीमा, जिसे Claude ने खुद बताया: यह hook सिर्फ़ edit और write टूल्स पर नज़र रखता है, और एक बाद के run में Claude ने वही बदलाव shell के रास्ते करने की पेशकश की। hook को shell भी कवर करना होगा, या shell को आपकी allow सूची से बाहर रखना होगा, क्योंकि जो पहरा सिर्फ़ एक दरवाज़े को ढकता है वह अब भी सिर्फ़ एक अनुरोध है। hook की context में कोई कीमत नहीं, क्योंकि वह आपकी बातचीत के बाहर चलता है।
तीसरा काम: जो ऑडिट थ्रेड भरता है वह subagent बनता है
subagent एक अलग Claude session है जिसका अपना खाली context होता है। उसे आपकी brief मिलती है, वह जो चाहिए पढ़ता है, और सिर्फ़ एक सारांश वापस आता है। तीसरा काम एक ऐसा ऑडिट है जो आपका thread भर देता है: source फ़ोल्डर की हर फ़ाइल को README की conventions से मिलाओ, और फ़ाइल और लाइन के साथ हर उल्लंघन की सूची दो।
inline पूछने पर Claude हर फ़ाइल आपकी बातचीत में पढ़ लेता है, और वह सारा कंटेंट बाकी session तक वहीं रहता है। हमारे run में Claude ने सभी 19 source फ़ाइलें पढ़ीं, context तालिका की Messages लाइन फूल गई, और निष्कर्ष ढेर के नीचे दब गए।
सही चुनाव .claude/agents/ के नीचे एक फ़ाइल है, यहाँ .claude/agents/conventions-auditor.md, जिसमें एक नाम, कब इस्तेमाल करना है इसका description, कौन से टूल्स वह इस्तेमाल कर सकता है, और एक पिन किया हुआ model हो। model को पिन करना मायने रखता है, क्योंकि वरना subagent वही model ले लेता है जिस पर आपका session चल रहा है, और पढ़ने के ज़्यादातर काम को बड़े model की ज़रूरत नहीं होती।
हमने ठीक वही सवाल फिर पूछा, और Claude ने फ़ाइलें खुद पढ़ लीं। दोनों कोशिशों में उसने agent को कभी कॉल नहीं किया, भले ही वह सूचीबद्ध था: 2 में से 0 delegations। जो काम आया वह prompt की शुरुआत में उसका नाम लेना था: "use the conventions auditor subagent"। एक ही कॉल गई और एक छोटा सारांश लौटा।
| Run | कुल context | Messages लाइन |
|---|---|---|
| Inline ऑडिट | 46.1k | 19.3k |
| नाम लिया हुआ subagent | 34.1k | 7.2k |
निष्कर्ष भी उतने ही अच्छे थे: subagent ने एक path bug पकड़ा जो inline run से छूट गया था, और एक ऐसा चूक गया जो inline run को मिला था। तो फ़ाइल subagent को अस्तित्व देती है, और आपका prompt Claude से उसका इस्तेमाल करवाता है; जब तक Claude खुद उसे नहीं चुनता, आप उसका नाम लेते हैं। एक सीमा: बिल नहीं हिला। दोनों runs की लागत बराबर रही, क्योंकि पढ़ना फिर भी होता है, बस आपकी window में नहीं।
चौथा काम: जो डेटा Claude तक नहीं पहुँचता वह MCP server बनता है
MCP server एक API क्लाइंट है जिसे Claude कॉल कर सकता है, और जिस काम के लिए वह बना है वह model से नया डेटा या वह डेटा है जो आपकी डिस्क के बाहर रहता है। यहाँ का सहज चुनाव गलत है, इसलिए हमने पहले वही किया।
हमने अपनी test लाइब्रेरी के लिए एक सार्वजनिक docs server जोड़ा और Claude से fake timers वाला एक test माँगा। कुछ नहीं बदला: Claude उस लाइब्रेरी को पहले से जानता था, और server को तभी कॉल किया जब हमने उसका नाम लिया। जो docs model पहले से जानता है, वे ऐसा डेटा नहीं जिस तक वह न पहुँच सके।
असली परीक्षा Claude Code के बारे में ही एक सवाल है, एक ऐसी hook सेटिंग के बारे में जो model से नई है: कौन सी सेटिंग फेल हुए hook को रोकने वाला बनाती है, कौन से version ने उसे जोड़ा, और सही JSON क्या है। server के बिना Claude ने अपने install की settings schema पढ़ी, कुछ नहीं मिला, और जवाब दिया कि उसे वह सेटिंग नहीं मिली और वह अंदाज़ा नहीं लगाएगा। वह जवाब ईमानदार है और बेकार है, क्योंकि सेटिंग मौजूद है; वह model के ज्ञान के बाद आई।
समाधान यह है कि Claude Code का अपना docs server repo में जोड़ें, project scope के साथ ताकि config repo की जड़ की एक फ़ाइल में जाए जो आपकी पूरी टीम को मिले:
claude mcp add --transport http claude-docs --scope project https://code.claude.com/docs/mcp
यह .mcp.json लिखता है। Claude Code server को pending दिखाता है जब तक आप अगले session में उसे मंज़ूर न करें, और उसके बाद उसके टूल्स Claude को उपलब्ध रहते हैं। हमने वही सवाल सादे शब्दों में पूछा, server का नाम लिए बिना। Claude ने docs खोजे, पेज पाया, और सेटिंग, version और जोड़ने वाले JSON के साथ, लिंक देकर जवाब दिया।
सेटिंग "onFailure": "block" है, जो फेल होते hook को कार्रवाई जाने देने की जगह उसे रोकने वाला बनाती है। यह v2.1.295 में आई, जबकि हमारा install अभी 2.1.294 पर था। यही सीमा है: Claude ने कभी नहीं कहा कि हमारा install इसे इस्तेमाल नहीं कर सकता, क्योंकि उसने version जाँचा ही नहीं, इसलिए अपना version आप खुद जाँचिए। context तालिका में server सिर्फ़ अपने टूल नामों के रूप में दिखता है, जो तब तक ज़रूरत पर लोड होते हैं जब तक Claude उनमें से किसी तक न पहुँचे।
चार फ़ाइलें, एक चुनाव कार्ड
चारों कामों के बाद git status ठीक चार फ़ाइलें दिखाता है, क्योंकि hook को अपनी कोई स्क्रिप्ट नहीं चाहिए:
.claude/skills/release/SKILL.md.claude/settings.json.claude/agents/conventions-auditor.md.mcp.json
इन्हें commit कीजिए, और इस repo पर अगले session में ये सब मौजूद होंगी, और जो भी इसे clone करे उसके पास भी।
हर चुनाव सही क्यों था, इसकी वजह वह तालिका है जो docs देते हैं, और जिसे आप निर्णय कार्ड की तरह रख सकते हैं:
| स्थिति | Extension |
|---|---|
| एक प्रक्रिया जिसे आप फिर चिपका रहे हैं | Skill |
| कुछ जो हर बार बिना पूछे होना चाहिए | Hook |
| एक साइड काम जो आपकी बातचीत को ऐसे आउटपुट से भर देता है जिसे आप दोबारा नहीं पढ़ेंगे | Subagent |
| वह डेटा जिसे आप ऐसी जगह से कॉपी करते रहते हैं जो Claude को दिखती नहीं | MCP server |
ये प्रकार मिलकर भी काम करते हैं। docs skill को MCP server के साथ जोड़ते हैं: server कनेक्शन देता है, और skill Claude को सिखाती है कि उसे अच्छी तरह कैसे इस्तेमाल करना है। एक skill forked subagent के अंदर भी चल सकती है, ताकि उसका पढ़ना आपकी window से बाहर रहे। जब किसी दूसरे repo को वही सेटअप चाहिए, तो plugin वह डिब्बा है जो सबको साथ भेजता है।
कार्ड प्रकार तय करता है, गुणवत्ता नहीं। जो hook सिर्फ़ लॉग करता है, जिस subagent का आप नाम नहीं लेते, और जिस लाइब्रेरी को model पहले से जानता है उसके लिए बना server, वे सब सही प्रकार में थे और फिर भी फेल हुए। प्रकार कार्ड से चुनिए, फिर फ़ाइल से जवाब दिलवाइए, सिर्फ़ उसे मौजूद मत रखिए।
निष्कर्ष: कब कौन सा, कब कोई नहीं, और एक नियम
जिन चारों कामों को आप दोहराकर टाइप करते थे, उन सबको पहले गलत तरीके से आज़माया गया, वे स्क्रीन पर फेल हुए, और अब वे repo में ऐसी फ़ाइलें हैं जो काम करती हैं। release एक ऐसा कमांड है जो आप टाइप करते हैं। डेटा का नियम एक hook है जो edit से इनकार करता है और Claude से पूछवाता है। ऑडिट एक सारांश बनकर लौटता है। docs का सवाल वह सेटिंग और वह version पाता है जो Claude अकेले नहीं खोज सका।
जिस hook से हमने शुरुआत की, जो चला और write को जाने दिया, उसने इन सबके नीचे का नियम सिखाया: hook सिर्फ़ उससे फ़ैसला करता है जो उसका कमांड लौटाता है, इसलिए जो hook सिर्फ़ लॉग करता है वह वेशभूषा में एक अनुरोध है।
कुछ मामलों में इनमें से कुछ भी नहीं चाहिए:
- जो convention Claude बार-बार गलत करता है, वह अब भी memory फ़ाइल में एक लाइन के रूप में रहती है, प्रक्रिया के रूप में नहीं।
- जो काम आपको आगे-पीछे चलाना है, अपने इतिहास को सामने रखकर, वह मुख्य thread में रहता है, subagent में नहीं।
- जिस लाइब्रेरी को model पहले से जानता है उसके लिए docs server context खर्च करता है और कुछ नहीं बदलता। वह जोड़िए जो model के पास हो ही नहीं सकता, वह नहीं जो उसके पास पहले से है।
याद रखने का नियम: जिस भी काम को आप दोहराकर टाइप करते हैं उसे उसकी अपनी फ़ाइल दीजिए, प्रकार कार्ड से चुनिए, और जानिए कि इन सबमें से सिर्फ़ hook कभी नहीं पूछता।
AIDive