# किसी बड़े कोडबेस को पूरी तरह लोकल सिमैंटिक कोड सर्च के लिए कैसे इंडेक्स करें

> जब grep काफी नहीं रह जाता, तब किसी AI एजेंट को विशाल मोनोरेपो की ओर इंगित करने की व्यावहारिक गाइड। Octocode कैसे tree-sitter से कोड को चंक करता है, बिना GPU और बिना क्लाउड के लोकल एम्बेडिंग चलाता है, सिमैंटिक और सटीक सर्च को जोड़ता है, और यह सब MCP के ज़रिए उजागर करता है — साथ ही वे दिक्कतें जिन्होंने हमें परेशान किया।

रेपो में लगभग 11,000 फाइलें थीं। एजेंट के पास एक `bash` टूल था और एक अस्पष्ट निर्देश: "ढूंढो कि हम वेबहुक सिग्नेचर कहाँ वैलिडेट करते हैं।" उसने `grep -rn "signature" .` चलाया, वेंडर किए गए JS, टेस्ट फिक्स्चर, एक `CHANGELOG`, और तीन असंबंधित क्रिप्टो हेल्पर्स में फैले 600 मैच पाए, और फिर पूरे आत्मविश्वास से गलत फाइल की ओर इशारा कर दिया। हमने उसे लगातार चार बार अलग-अलग शब्दों के साथ ऐसा करते देखा, इससे पहले कि किसी ने वह स्पष्ट बात कही: grep स्ट्रिंग्स को मैच करता है, और एजेंट _अर्थ_ के बारे में सवाल पूछ रहा था।

यही पूरी समस्या एक वाक्य में है। `grep` और `rg` "यह सटीक टोकन कहाँ दिखता है" के लिए बेहतरीन हैं। वे "वह चीज़ कहाँ है जो X करती है" के लिए बेकार हैं, क्योंकि X करने वाले कोड में लगभग कभी वे शब्द नहीं होते जिनसे आप X का वर्णन करते। फ़ंक्शन का नाम `verify_hmac` है। आपने "webhook signature" खोजा। शून्य ओवरलैप, और एजेंट जिस इकलौते टूल की ओर पहले हाथ बढ़ाता है, वह कुछ भी उपयोगी नहीं लौटाता।

समाधान है सिमैंटिक सर्च: कोड को एम्बेड करो, क्वेरी को एम्बेड करो, उन चंक्स को ढूंढो जिनका अर्थ सबसे करीब है। पेच यह है कि "बस एम्बेडिंग इस्तेमाल करो" वाली ज़्यादातर सलाह यह मान लेती है कि आप अपना सोर्स कोड किसी क्लाउड API को भेजेंगे और एक GPU किराये पर लेंगे। एक निजी मोनोरेपो के लिए, दोनों में से कोई भी स्वीकार्य नहीं: लीगल टीम प्रोप्रायटरी कोड किसी तीसरे पक्ष को अपलोड करने की मंज़ूरी नहीं देगी, और आप एक ऐसा प्रति-टोकन बिल नहीं चाहते जो हर री-इंडेक्स के साथ बढ़े।

तो यह रही वह सेटअप जो हम असल में चलाते हैं: [Octocode](https://github.com/Muvon/octocode), जो एक बड़े रेपो को सिमैंटिक सर्च के लिए **पूरी तरह लोकल** इंडेक्स करता है — बिना GPU, बिना क्लाउड एम्बेडिंग, मशीन से कुछ भी बाहर नहीं जाता। यह रहा कि यह बिल्कुल कैसे काम करता है, कौन सा कॉन्फ़िग मायने रखता है, और वे चार चीज़ें जिन्होंने हमें परेशान किया।

---

## grep क्यों काफी नहीं है, ठोस रूप में

एम्बेडिंग की ओर हाथ बढ़ाने से पहले, यह स्पष्ट होना ज़रूरी है कि एजेंट्स के लिए टेक्स्ट सर्च _क्यों_ विफल होता है, क्योंकि यह बताता है कि उसके विकल्प को क्या करना होगा।

- **शब्दावली का बेमेल।** क्वेरी मंशा है ("rate limiting"), कोड तंत्र है (`Semaphore`, `token_bucket`, `RetryAfter`)। कोई साझा टोकन नहीं।
- **कोई रैंकिंग नहीं।** `rg` आपको हर मैच समान वज़न के साथ देता है। 600 मैच जवाब नहीं हैं; वह एक दूसरी सर्च समस्या है।
- **कोई संरचना नहीं।** एक कमेंट में, एक टेस्ट में, और एक कोर फ़ंक्शन में टेक्स्ट मैच `grep` के लिए एक जैसे दिखते हैं। वह आपको नहीं बता सकता कि तीसरा वाला परिभाषा है।

इसके बजाय आप यह चाहते हैं: _सिमैंटिक_ निकटता से रैंक करना, लेकिन उस चीज़ को न खोना जिसमें `grep` सचमुच अच्छा है — सटीक आइडेंटिफायर मैच। Octocode का जवाब है दोनों करना और उन्हें जोड़ना, जिस पर मैं आगे आऊंगा। पहले, कोड को सर्च करने योग्य रूप में लाया कैसे जाता है।

---

## Octocode कोड को कैसे चंक और इंडेक्स करता है

मानक RAG फाइलों को निश्चित आकार की टेक्स्ट विंडो में काटता है — हर N अक्षर, थोड़ा ओवरलैप, और एम्बेड। गद्य के लिए यह ठीक है। कोड के लिए यह सक्रिय रूप से बुरा है: यह एक फ़ंक्शन को दो चंक्स में बाँट देता है, एक `match` आर्म का आधा हिस्सा एम्बेड करता है, और यह तथ्य खो देता है कि एक मेथड किसी टाइप से संबंधित है।

Octocode पहले हर फाइल को **tree-sitter** से पार्स करता है, AST में चलता है, और मनमाने बाइट ऑफसेट के बजाय असली सिंबल सीमाओं — फ़ंक्शन, मेथड, क्लास, मॉड्यूल — के अनुसार चंक करता है। आर्किटेक्चर है: हर भाषा के लिए एक पार्सर जो फ़ंक्शन, क्लास, इम्पोर्ट और एक्सपोर्ट निकालता है, फिर जो कुछ भी एक टुकड़े में एम्बेड करने के लिए बहुत बड़ा है उसके लिए चंक-आधारित प्रोसेसिंग। किसी `impl` ब्लॉक या क्लास के अंदर से निकाला गया मेथड अपनी सिंबल सूची में अपने पैरेंट टाइप का नाम साथ रखता है, इसलिए `Suppression.mark_set` या `Foo.bar` खोजना सीधे मेथड चंक पर पहुँचता है।

भाषा कवरेज असली tree-sitter ग्रामर हैं, regex ह्यूरिस्टिक्स नहीं। रेपो के अनुसार, पूर्ण AST पार्सिंग के साथ **कोड** के रूप में इंडेक्स किए जाते हैं:

| भाषा                                   | एक्सटेंशन                                                                                                          |
| -------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
| Rust                                   | `.rs`                                                                                                              |
| Python                                 | `.py`                                                                                                              |
| TypeScript / JavaScript                | `.ts`, `.tsx`, `.js`, `.jsx`                                                                                       |
| Go                                     | `.go`                                                                                                              |
| PHP                                    | `.php`                                                                                                             |
| C / C++                                | `.c`, `.h`, `.cpp`, `.hpp`, `.cc`, `.cxx`, साथ ही C++20 मॉड्यूल एक्सटेंशन `.cppm`, `.ixx`, `.mxx`, `.ccm`, `.cxxm` |
| Ruby                                   | `.rb`                                                                                                              |
| Java                                   | `.java`                                                                                                            |
| Swift                                  | `.swift`                                                                                                           |
| JSON, Bash, CSS, Lua, Svelte, Markdown | समर्पित tree-sitter पथ                                                                                             |

कॉन्टेक्स्ट के लिए उपयोगी बाकी सब कुछ (`yaml`, `toml`, `dockerfile`, `makefile`, `ini`, `conf`, `env`, `xml`, `html`, `sql`, `rst` वगैरह) **टेक्स्ट ब्लॉक** के रूप में इंडेक्स होता है, इसलिए वह अब भी खोजने योग्य रहता है, बस बिना सिमैंटिक सिंबल एक्सट्रैक्शन के।

चंकिंग के पैरामीटर `[index]` के तहत रहते हैं:

```toml
[index]
chunk_size = 2000        # प्रति कोड चंक अधिकतम अक्षर
chunk_overlap = 100      # आसपास के चंक्स के बीच ओवरलैप
quantization = true      # RaBitQ वेक्टर संपीड़न, ~32x, न्यूनतम गुणवत्ता हानि
require_git = true        # डिफ़ॉल्ट रूप से केवल git रेपो के अंदर इंडेक्स करें
```

`chunk_size` एक सीमा है, लक्ष्य नहीं — सीमा से छोटा 40-लाइन का फ़ंक्शन पूरा रहता है। सीमा केवल सचमुच बड़े बॉडी के लिए लागू होती है, और Octocode पहले से ही Python, TypeScript, C++, और Ruby में बड़ी क्लासों को मेथड-दर-मेथड इंडेक्स करता है, बजाय पूरी क्लास को एक चंक में डालने के। इस सबका मकसद: जब आप बाद में "वह फ़ंक्शन जो रिमोट पुल सेटअप संभालता है" खोजते हैं, तो जो इकाई एम्बेड होती है वह _वही फ़ंक्शन_ है — अपने नाम और जुड़े पैरेंट टाइप के साथ, न कि कोई विंडो जो संयोग से उसके आर-पार पड़ती है।

---

## लोकल एम्बेडिंग: बिना GPU, बिना क्लाउड, बिना API की

जिस हिस्से के बारे में लोग मान लेते हैं कि उसे क्लाउड चाहिए — कोड को वेक्टर में बदलना — उसे क्लाउड नहीं चाहिए।

Octocode एक [local-first स्टैक](/blog/octocode-0-15-0-local-first-hybrid-search) के साथ आता है जो `fastembed` पर बना है (पर्दे के पीछे ONNX Runtime)। आप कॉन्फ़िग को `fastembed:` प्रीफ़िक्स वाले लोकल मॉडल की ओर इंगित करते हैं और एम्बेडिंग CPU पर, आपकी मशीन पर चलती है:

```toml
[embedding]
code_model = "fastembed:jinaai/jina-embeddings-v2-base-code"   # 768-d, कोड के लिए विशेष रूप से बना
text_model = "fastembed:nomic-ai/nomic-embed-text-v1.5"        # टेक्स्ट और दस्तावेज़
```

मॉडल स्ट्रिंग हमेशा `provider:model` होती है। प्रोवाइडर प्रीफ़िक्स ही पूरा रूटिंग निर्णय है: `fastembed:` और `huggingface:` लोकल हैं (कोई की नहीं, कोई नेटवर्क नहीं); `voyage:`, `jina:`, `google:`, `openai:`, `together:`, `octohub:` क्लाउड हैं और एनवायरनमेंट में संगत API की चाहिए। चाहें तो मिला लें (लोकल कोड एम्बेडिंग, क्लाउड टेक्स्ट एम्बेडिंग), लेकिन निजी रेपो के लिए पूरी तरह लोकल रास्ता ही मकसद है।

यहाँ कोई GPU की ज़रूरत नहीं और कोई GPU कोड पथ नहीं: यह CPU पर ONNX इन्फरेंस है। AVX2 वाली आधुनिक मल्टी-कोर मशीन पर, यह इतना तेज़ है कि एम्बेडर शायद ही कभी बॉटलनेक बनता है — आमतौर पर डिस्क I/O और tree-sitter पार्सिंग बनते हैं। रेपो के अपने प्रदर्शन नोट्स लोकल FastEmbed इंडेक्सिंग को मोटे तौर पर 1,000 फाइलों के लिए लगभग 45 सेकंड बताते हैं; आपका परिणाम फाइल आकार और कोर संख्या के अनुसार बदलेगा, इसलिए इसे केवल उदाहरण मानें, वादा नहीं।

दो ईमानदार चेतावनियाँ:

1. **पहली बार चलाने पर मॉडल डाउनलोड होता है।** किसी `fastembed:` मॉडल की ओर इंगित करने के बाद पहला `octocode index` ONNX वेट्स (कुछ सौ MB) एक कैश डायरेक्टरी (`~/.local/share/octocode/fastembed/` Linux/macOS पर) में खींचता है। एक बार की लागत, उसके बाद हमेशा के लिए ऑफलाइन।
2. **लोकल प्रोवाइडर फ़ीचर-गेटेड और प्लेटफ़ॉर्म-संवेदनशील हैं।** FastEmbed और HuggingFace के लिए `fastembed`/`huggingface` बिल्ड फ़ीचर चाहिए। डिफ़ॉल्ट बिल्ड उन्हें वहाँ शामिल करते हैं जहाँ वे अच्छी तरह समर्थित हैं; जहाँ नहीं हैं, वहाँ आप क्लाउड प्रोवाइडर पर लौट आते हैं। यह देखने के लिए कि आपका बाइनरी असल में क्या उजागर करता है, `octocode models list fastembed` जाँचें। [0.17.0 में लोकल एम्बेडिंग प्रोवाइडर का हालिया काम](/blog/octocode-0-17-1-local-embedding-providers) ने ही इस सूची को इस बारे में ईमानदार बनाया कि कहाँ क्या उपलब्ध है।

अगर आपने पहले कभी कोड पर सिमैंटिक सर्च सेटअप नहीं किया, तो [Octocode सिमैंटिक कोड सर्च का परिचय](/blog/octocode-semantic-code-search) बुनियादी अवधारणाएँ कवर करता है; यह पोस्ट मानता है कि आप उससे आगे हैं और प्रोडक्शन सेटअप चाहते हैं।

---

## रेपो को इंडेक्स करना

कॉन्फ़िग तैयार होने पर, इंडेक्सिंग रेपो रूट से एक ही कमांड है:

```bash
cd /path/to/big-monorepo
octocode index
# → Indexed 12,847 blocks across 342 files
```

असल में जो होता है, क्रम में: फाइलें खोजना (इग्नोर नियमों का पालन करते हुए), हर एक को tree-sitter से पार्स करना, सिंबल निकालना, AST सीमाओं के साथ चंक करना, हर चंक को लोकल एम्बेड करना, और सब कुछ एक **LanceDB** कॉलमनर स्टोर में लिखना। डेटाबेस आपके रेपो में _नहीं_ रहता — यह सिस्टम डेटा डायरेक्टरी के तहत प्रति-प्रोजेक्ट कुंजीबद्ध होता है (`~/.local/share/octocode/<project-id>/storage` Linux/macOS पर)। इससे आपका वर्किंग ट्री साफ़ रहता है और इसका मतलब है कि `git clean -fdx` आपके इंडेक्स को नहीं मिटाएगा।

उपयोगी फ़्लैग:

```bash
octocode index --force      # इंक्रीमेंटल कैश अनदेखा करें, शून्य से फिर से बनाएँ
octocode index --verbose    # प्रति-फाइल प्रगति देखें
octocode stats              # कितने कोड/टेक्स्ट/डॉक ब्लॉक, ग्राफ नोड, इंडेक्स बासीपन
```

`octocode stats` वही है जिसे चलाना चाहिए जब कुछ गड़बड़ लगे — यह बताता है कि आपका `HEAD` पिछले इंडेक्स किए गए कमिट से मेल खाता है या नहीं, इसलिए आप एक नज़र में देख सकते हैं कि इंडेक्स बासी है या नहीं।

### इंक्रीमेंटल बनाम पूर्ण री-इंडेक्स

`octocode index` के बाद के रन इंक्रीमेंटल होते हैं — केवल बदली हुई फाइलें फिर से पार्स और एम्बेड होती हैं। हर इंडेक्सिंग रन एक टेबल ऑप्टिमाइज़ेशन पास के साथ समाप्त होता है ताकि डेटाबेस बढ़ने पर भी क्वेरी पथ तेज़ बना रहे (बार-बार इंक्रीमेंटल इंडेक्सिंग पहले एक बिना-इंडेक्स वाली पूँछ छोड़ती थी जिसे सर्च को ब्रूट-फोर्स स्कैन करना पड़ता था; अब यह अपने-आप संभलता है)।

जब आप यह बदलते हैं कि चीज़ें _कैसे_ इंडेक्स होती हैं (एक नया चंकिंग नियम, अलग एम्बेडिंग मॉडल), तो इंक्रीमेंटल अपने पास पहले से मौजूद फाइलों को पिछली तारीख से फिर से चंक नहीं करेगा। एम्बेडिंग मॉडल बदलना सबसे बड़ी बात है: एक मॉडल के वेक्टर दूसरे के वेक्टर से तुलनीय नहीं हैं। `code_model` या `text_model` बदलने के बाद, एक साफ़ रीबिल्ड करें:

```bash
octocode clear        # इंडेक्स की गई टेबल हटाएँ
octocode index        # नए मॉडल के साथ फिर से बनाएँ
```

---

## watch मोड: इंडेक्स को जीवंत रखें

जैसे ही कोई कमिट करता है, एक-बार वाला इंडेक्स बासी हो जाता है। ऐसे एजेंट के लिए जिसे रेपो की _वर्तमान_ स्थिति के बारे में जवाब देने हों, watcher चलाएँ:

```bash
octocode watch              # फाइल बदलने पर अपने-आप री-इंडेक्स
octocode watch --debounce 5 # री-इंडेक्स से पहले अंतिम बदलाव के बाद 5s प्रतीक्षा करें
octocode watch --quiet
```

Watcher डिबाउंस करता है (कॉन्फ़िगरेबल, 1–30 सेकंड), इसलिए 400 फाइलों को छूने वाला एक `git checkout` एक री-इंडेक्स ट्रिगर करता है, 400 नहीं। यह पूर्ण इंडेक्स जैसे ही इग्नोर नियमों का पालन करता है, इसलिए `node_modules` की फाइल संपादित करने से वह नहीं जागता।

अगर आप MCP सर्वर चला रहे हैं (अगला खंड), तो एक और भी साफ़ विकल्प है: `[index]` के तहत `mcp_index = true` सेट करें और MCP सर्वर **इन-प्रोसेस** इंडेक्स और वॉच करेगा — दो के बजाय एक चलती चीज़। डिफ़ॉल्ट `false` है, जो मौजूदा इंडेक्स को केवल-पढ़ने के रूप में परोसता है और मानता है कि आप अलग से इंडेक्स करते हैं; इसे तब चालू करें जब आप चाहें कि सर्वर पूरे जीवनचक्र का मालिक हो।

---

## हाइब्रिड सर्च: सिमैंटिक _और_ सटीक, एक साथ जुड़े

यह वह हिस्सा है जो grep के मूल विफलता को ठीक करता है, grep की एकमात्र ताकत को फेंके बिना।

शुद्ध वेक्टर सर्च आइडेंटिफायर-भारी क्वेरीज़ पर हारता है। `parse_remote` खोजें और डेंस एम्बेडिंग खुशी-खुशी वह सब लौटाएंगे जो `parse_remote` के _सिमैंटिक रूप से करीब_ है, जबकि शाब्दिक रूप से `parse_remote` नाम वाले फ़ंक्शन को छोड़ देंगे। BM25 कीवर्ड सर्च की उलटी कमी है: यह सटीक आइडेंटिफायर पकड़ता है और "वह फ़ंक्शन जो रिमोट पुल सेटअप संभालता है" जैसी रूपांतरित मंशा पर चूक जाता है।

Octocode हर क्वेरी पर दोनों चलाता है और उन्हें LanceDB के अंदर Weighted Reciprocal Rank Fusion से जोड़ता है। वज़न उजागर हैं:

```toml
[search.hybrid]
enabled = true
default_vector_weight  = 0.7
default_keyword_weight = 0.3
```

ऐसे कोड-भारी रेपो के लिए जहाँ सटीक आइडेंटिफायर बहुत संकेत रखते हैं, कीवर्ड की ओर झुकें। रेपो का अपना रिट्रीवल बेंचमार्क (लाइन-रेंज ग्राउंड ट्रुथ के साथ 127 कोड-सर्च क्वेरी, `jina-embeddings-v2-base-code` के साथ पूरी तरह लोकल और _बिना_ रीरैंकर चलाई गईं) प्रभाव स्पष्ट दिखाता है: डिफ़ॉल्ट `0.7/0.3` विभाजन से कीवर्ड-ट्यून किए `0.3/0.7` पर जाने से Hit@5 0.598 से 0.732 और Recall@10 0.671 से 0.807 तक बढ़ा, बिना किसी अतिरिक्त लागत के। यह एक कॉन्फ़िग लाइन से Hit@5 में +22% है। लंबे-फॉर्म दस्तावेज़ों के लिए दूसरी ओर झुकें (`0.8/0.2`), क्योंकि वहाँ मंशा हावी रहती है।

फ़्यूज़न के ऊपर, एक वैकल्पिक रीरैंकर शीर्ष उम्मीदवारों को फिर से क्रमबद्ध करता है:

```toml
[search.reranker]
enabled = true
model   = "fastembed:jina-reranker-v2-base-multilingual"   # लोकल रीरैंकर, बिना की
top_k_candidates = 50    # वेक्टर सर्च से इतने लाएँ
final_top_k = 10         # रीरैंकिंग के बाद इतने लौटाएँ
```

अगर आप इसे `fastembed:` मॉडल की ओर इंगित करें तो रीरैंकर भी लोकल चलता है। यह शीर्ष 50 उम्मीदवारों पर एक क्रॉस-एनकोडर पास है, जो उन मामलों को पकड़ता है जहाँ पहली-स्टेज रैंकिंग ने क्रम गलत किया। लागत असली है पर सीमित — यह केवल `top_k_candidates` देखता है, पूरा इंडेक्स नहीं।

CLI से, सर्च सतह सीधी है:

```bash
octocode search "webhook signature verification"
octocode search "auth" "middleware" "session"          # मल्टी-क्वेरी, 10 तक
octocode search "database connection pool" --mode code  # कोड ब्लॉक तक सीमित
octocode search "auth" --detail-level signatures        # केवल सिग्नेचर, संक्षिप्त
octocode search "authentication refactor" --mode commits # git इतिहास खोजें
```

`--mode commits` पथ जानने योग्य है: कमिट इतिहास पहली कमिट-सर्च पर आलसी रूप से इंडेक्स होता है (`octocode index` के दौरान नहीं), इसलिए आप पूछ सकते हैं "हमने auth फ्लो कब बदला" और सिर्फ़ `git log --grep` के बजाय सिमैंटिक रूप से रैंक किए गए कमिट पा सकते हैं।

---

## स्ट्रक्चरल सर्च: जब आपको अर्थ नहीं, AST पैटर्न चाहिए

कभी-कभी आपको सिमैंटिक्स बिलकुल नहीं चाहिए — आपको चाहिए "Rust में हर `.unwrap()`" या "JS में हर `new Foo()`"। यह एक स्ट्रक्चरल क्वेरी है, और टेक्स्ट सर्च इसे लगातार गलत करता है (`.unwrap()` का ज़िक्र करने वाला कमेंट कोई कॉल नहीं है)। Octocode ast-grep को रैप करता है:

```bash
octocode grep '$FUNC.unwrap()' --lang rust
octocode grep 'new $CLASS($$$ARGS)' --lang javascript
octocode grep 'console.log($ARG)' --lang javascript --rewrite 'logger.info($ARG)' --update-all
```

`$VAR` एक AST नोड से मैच करता है, `$$$ARGS` आर्गुमेंट की एक श्रृंखला से मैच करता है, और `--rewrite` जगह पर AST-सचेत रीफैक्टरिंग करता है। एजेंट्स के लिए सचमुच उपयोगी बात: LLM नोड के _kind_ में भरोसेमंद तरीके से गलती करते हैं — वे Python के लिए `function_declaration` लिखेंगे, जो असल में `function_definition` है। जब कोई पैटर्न कुछ भी मैच नहीं करता, Octocode क्रमशः ढीली व्याख्याएँ आज़माता है और हर भाषा के लिए सही kind जानता है, इसलिए एजेंट का करीब-करीब-सही प्रयास भी एक मौन शून्य के बजाय परिणाम लौटाता है।

---

## GraphRAG: रिश्ते, सिर्फ़ समानता नहीं

सिमैंटिक सर्च _समान_ कोड ढूंढता है। यह आपको नहीं बता सकता कि `auth_middleware.rs`, `jwt.rs` को इम्पोर्ट करता है, `user_store.rs` को कॉल करता है, और `router.rs` में जुड़ा है। यह एक ग्राफ सवाल है, और Octocode इंडेक्सिंग के दौरान ग्राफ बनाता है।

```toml
[graphrag]
enabled = true
use_llm = true
```

यह नौ भाषाओं में AST से `imports`, `calls`, `extends`, और `implements` एज निकालता है, और `use_llm = true` के साथ उच्च-स्तरीय आर्किटेक्चरल रिश्ते (`configures`, `uses`, factory/observer/strategy पैटर्न) जोड़ता है जिन्हें एक LLM खोजता है। CLI से:

```bash
octocode graphrag get-relationships --node-id "src/auth/middleware.rs"
octocode graphrag find-path --source-id "src/auth/mod.rs" --target-id "src/database/mod.rs"
octocode graphrag overview
```

यही फ़र्क है "मुझे ऐसा कोड दिखाओ जो auth जैसा लगे" और "मुझे वह सब दिखाओ जो auth मॉड्यूल _पर निर्भर_ है" के बीच। रीफैक्टर करने वाले एजेंट के लिए, दूसरा सवाल ही टूट-फूट रोकता है।

एक नया, वैकल्पिक मोड़ भी है: **ग्राफ-सचेत रिट्रीवल विस्तार**। `[search] graph_expansion = true` (और GraphRAG सक्षम) के साथ, सर्च रीरैंकिंग से _पहले_ आपके शीर्ष हिट्स से संरचनात्मक रूप से संबंधित फाइलों के कोड ब्लॉक खींच लाता है — ताकि auth-middleware पर पहुँचने वाली क्वेरी उसके द्वारा कॉल किए जाने वाले JWT हेल्पर को सामने ला सके, भले ही वह हेल्पर क्वेरी टेक्स्ट से मैच न करता हो। यह डिफ़ॉल्ट रूप से बंद है और कोड के कमेंट इस बारे में स्पष्ट हैं: इस पर भरोसा करने से पहले अपने मूल्यांकन पर A/B करें, क्योंकि विस्तार संकेत जितनी आसानी से, उतनी ही आसानी से शोर भी जोड़ सकता है।

---

## इसे MCP के ज़रिए एजेंट से जोड़ना

ऊपर का सब कुछ एक अंतर्निहित **MCP सर्वर** के ज़रिए AI सहायकों को उजागर होता है। Octocode इस्तेमाल करने का यही मुख्य तरीका है — एजेंट को टूल मिलते हैं, शेल नहीं।

```bash
octocode mcp --path /path/to/your/project
```

या किसी क्लाइंट कॉन्फ़िग में (Claude Desktop, Cursor, Windsurf, Claude Code):

```json
{
	"mcpServers": {
		"octocode": {
			"command": "octocode",
			"args": ["mcp", "--path", "/path/to/your/project"]
		}
	}
}
```

वे टूल जो एजेंट देखता है, सर्वर के विरुद्ध सत्यापित:

| MCP टूल             | यह क्या करता है                                                                      |
| ------------------- | ------------------------------------------------------------------------------------ |
| `semantic_search`   | हाइब्रिड सिमैंटिक + कीवर्ड सर्च, मल्टी-क्वेरी, `commits` सहित सभी मोड                |
| `view_signatures`   | फाइल संरचना (सिग्नेचर, क्लास, इम्पोर्ट) glob द्वारा, पूरी फाइलें पढ़े बिना           |
| `structural_search` | ast-grep के ज़रिए AST पैटर्न मैचिंग, kind-फॉलबैक रिकवरी के साथ                       |
| `graphrag`          | रिश्ते की क्वेरी: `search`, `get-node`, `get-relationships`, `find-path`, `overview` |

`view_signatures` अनसुना नायक है। किसी फ़ंक्शन का सिग्नेचर ढूंढने के लिए एजेंट द्वारा तीन 800-लाइन फाइलें पढ़कर कॉन्टेक्स्ट जलाने के बजाय, यह glob द्वारा सिग्नेचर माँगता है और ढाँचा पा जाता है। (हालिया संस्करणों में आप केवल एरे नहीं, बल्कि एक अकेली glob स्ट्रिंग पास कर सकते हैं — एक छोटी बात जिसने बहुत से खराब टूल कॉल रोके।)

कई उप-परियोजनाओं वाले मोनोरेपो के लिए, एक मल्टी-रेपो मोड है: `octocode mcp --multi --path /workspace` तत्काल सब-डायरेक्टरीज़ को git रेपो के लिए स्कैन करता है और उन सबको एक ही एंडपॉइंट से परोसता है, और हर टूल को लक्ष्य चुनने के लिए एक `project` आर्गुमेंट मिलता है। एक MCP सर्वर, वर्कस्पेस के सारे रेपो।

---

## चार चीज़ें जिन्होंने हमें परेशान किया

ठोस, काल्पनिक नहीं — यही वह है जिसने हमारा समय खाया।

**1. इंडेक्स रेपो के बाहर रहता है, और इसने सबको उलझाया।** पहली बार जब किसी ने ताज़ा क्लोन पर एजेंट चलाया, उसके पास कोई इंडेक्स नहीं था: डेटाबेस `~/.local/share/octocode/` के तहत प्रति-प्रोजेक्ट है, वर्किंग ट्री में नहीं। क्लोन ≠ इंडेक्स। समाधान ऑनबोर्डिंग में एक पंक्ति है: क्लोन के बाद एक बार `octocode index` चलाएँ। पीछे मुड़कर देखें तो स्पष्ट; रात के 2 बजे बिलकुल स्पष्ट नहीं।

**2. एम्बेडिंग मॉडल बदलने ने चुपचाप परिणाम बिगाड़ दिए।** किसी ने अलग लोकल मॉडल आज़माने के लिए `code_model` बदला और इंडेक्स _साफ़ नहीं किया_। नई क्वेरी नए मॉडल से एम्बेड हुईं, पुराने चंक पुराने से, वेक्टर तुलनीय नहीं, रैंकिंग कचरा। अलग मॉडलों के वेक्टर एक ही स्पेस में नहीं रहते। **एम्बेडिंग मॉडल बदलने के बाद हमेशा `octocode clear && octocode index`।** यहाँ कोई चेतावनी आपको नहीं बचाएगी — यह बस चुपचाप बदतर होता जाता है।

**3. डिफ़ॉल्ट वेक्टर/कीवर्ड विभाजन हमारे रेपो के लिए गलत था।** हम एक हफ़्ते `0.7/0.3` (वेक्टर-भारी) पर चले और सटीक-आइडेंटिफायर क्वेरीज़ चूकते रहे। कोड आइडेंटिफायर-सघन है; ऊपर का बेंचमार्क दिखाता है कि कीवर्ड-ट्यून किए वज़न कोड सर्च के लिए नाटकीय रूप से बेहतर हैं। `0.3/0.7` पर जाना हमारा किया गया सबसे प्रभावशाली कॉन्फ़िग बदलाव था।

**4. बाइनरी और जनरेटेड फाइलें इंडेक्स नहीं होतीं — और यह सही है, पर जाँच लें।** Octocode बाइनरी फाइलों को छोड़ देता है (सामग्री को टेक्स्ट मानने से पहले यह नल बाइट्स और प्रिंट करने योग्य अक्षरों का अनुपात जाँचता है) और `.gitignore`, `.git/info/exclude`, तथा `.noindex` फाइलों का पालन करता है। यही आप चाहते हैं — आपको मिनिफाइड वेंडर बंडल के एम्बेडिंग नहीं चाहिए। पर अगर कोई डायरेक्टरी जो आपके _काम की_ है gitignore में है (कुछ टीमें जनरेटेड API क्लाइंट gitignore करती हैं), तो वह इंडेक्स नहीं होगी और आप सोचेंगे कि सर्च उसे क्यों नहीं ढूंढ पाता। अतिरिक्त पथ _बाहर रखने_ के लिए `.noindex` रखें; अगर अपेक्षित कुछ गायब है तो अपना `.gitignore` जाँचें। `octocode stats` आपको ब्लॉक गिनती दिखाएगा ताकि आप कवरेज जाँच सकें।

---

## एक न्यूनतम एंड-टू-एंड सेटअप

सब जोड़कर, एक निजी मोनोरेपो के लिए यह पूरी चीज़ है, सब लोकल:

```toml
# ~/.local/share/octocode/config.toml (या एक प्रोजेक्ट-लोकल ओवरराइड)
[embedding]
code_model = "fastembed:jinaai/jina-embeddings-v2-base-code"
text_model = "fastembed:nomic-ai/nomic-embed-text-v1.5"

[search.hybrid]
enabled = true
default_vector_weight  = 0.3   # आइडेंटिफायर-सघन कोड → कीवर्ड को प्राथमिकता
default_keyword_weight = 0.7

[search.reranker]
enabled = true
model   = "fastembed:jina-reranker-v2-base-multilingual"

[graphrag]
enabled = true
use_llm = false   # केवल AST रिश्ते, कोई LLM कॉल नहीं, पूरी तरह ऑफलाइन
```

```bash
cd /path/to/monorepo
octocode index                          # पहला रन मॉडल डाउनलोड करता है, फिर इंडेक्स
octocode search "webhook signature verification"   # समझदारी जाँच
octocode watch --quiet &                # जीवंत रखें
claude mcp add octocode -- octocode mcp --path .   # एजेंट से जोड़ें
```

एक-बार मॉडल डाउनलोड के बाद उस प्रवाह में कुछ भी नेटवर्क को नहीं छूता। कोई GPU नहीं। कोई प्रति-टोकन बिल नहीं। वह एजेंट जो "signature" के लिए grep कर रहा था और गलत फाइल की ओर इशारा कर रहा था, अब `semantic_search` कॉल करता है, `verify_hmac` को पहले स्थान पर रैंक पाता है, और कुछ छूने से पहले पुष्टि के लिए `view_signatures` का उपयोग करता है।

---

## अक्सर पूछे जाने वाले सवाल

**क्या मुझे GPU चाहिए?** नहीं। लोकल एम्बेडिंग ONNX Runtime के ज़रिए CPU पर चलती हैं। एक आधुनिक मल्टी-कोर CPU काफी है; एम्बेडर शायद ही कभी बॉटलनेक होता है।

**क्या कोई कोड मेरी मशीन से बाहर जाता है?** `fastembed:`/`huggingface:` मॉडल और `graphrag.use_llm = false` के साथ, नहीं — इंडेक्सिंग, सर्च, और रीरैंकिंग सब लोकल हैं। क्लाउड एम्बेडिंग प्रोवाइडर और LLM-संचालित GraphRAG/कमिट-मैसेज फ़ीचर ऑप्ट-इन हैं और स्पष्ट रूप से की चाहिए।

**इंडेक्स कहाँ रहता है, और क्या वह मेरे रेपो में है?** सिस्टम डेटा डायरेक्टरी के तहत, प्रति-प्रोजेक्ट कुंजीबद्ध (`~/.local/share/octocode/<project-id>/` Linux/macOS पर), आपके वर्किंग ट्री में नहीं। `git clean` उसे नहीं छुएगा; ताज़ा क्लोन के पास वह नहीं होगा।

**डेटाबेस कितना बड़ा होता है?** मोटे तौर पर प्रति फाइल ~10KB के क्रम में, RaBitQ क्वांटाइज़ेशन से ~32x वेक्टर संपीड़न के साथ। 10k-फाइल रेपो दसियों से कुछ सौ MB है, गीगाबाइट नहीं।

**इंक्रीमेंटल या पूर्ण री-इंडेक्स?** डिफ़ॉल्ट रूप से इंक्रीमेंटल — केवल बदली फाइलें फिर से एम्बेड होती हैं। पूर्ण रीबिल्ड के लिए `octocode index --force`, या एम्बेडिंग मॉडल बदलने के बाद `octocode clear && octocode index`।

**क्या यह git इतिहास खोज सकता है?** हाँ, `octocode search "..." --mode commits`। कमिट पहली कमिट-सर्च पर आलसी रूप से इंडेक्स होते हैं, इसलिए शुरुआती `octocode index` तेज़ बना रहता है।

---

— Don

---

_[Octocode](https://github.com/Muvon/octocode) Apache-2.0 के तहत ओपन सोर्स है। local-first स्टैक [0.15.0](/blog/octocode-0-15-0-local-first-hybrid-search) में आया और लोकल एम्बेडिंग प्रोवाइडर सूची [0.17.x](/blog/octocode-0-17-1-local-embedding-providers) में। अगर आपका सेटअप किसी ऐसी दिक्कत से टकराता है जो इस पोस्ट ने कवर नहीं की, तो [एक issue खोलें](https://github.com/Muvon/octocode/issues) — इन्हीं में से ज़्यादातर सुझाव सबसे पहले इसी तरह लिखे गए थे।_
