Skip to main content

title: आर्किटेक्चर description: “हुक हैंडलर, कॉन्फ़िग लोडिंग, और पॉलिसी मूल्यांकन कैसे काम करते हैं” icon: sitemap

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

अवलोकन

failproofai के दो स्वतंत्र सबसिस्टम हैं:
  1. हुक हैंडलर - एक तेज़ CLI सबप्रोसेस जो Claude Code हर एजेंट टूल कॉल पर चलाता है। पॉलिसीज़ का मूल्यांकन करता है और एक निर्णय देता है।
  2. एजेंट मॉनिटर (डैशबोर्ड) - एजेंट सेशन की निगरानी और पॉलिसीज़ को प्रबंधित करने के लिए एक Next.js वेब एप्लिकेशन।
दोनों सबसिस्टम ~/.failproofai/ और प्रोजेक्ट की .failproofai/ डायरेक्टरी में कॉन्फ़िग फ़ाइलें साझा करते हैं, लेकिन वे अलग-अलग प्रक्रियाओं के रूप में चलते हैं और केवल फ़ाइलसिस्टम के माध्यम से संचार करते हैं।

हुक हैंडलर

Claude Code के साथ एकीकरण

जब आप failproofai policies --install चलाते हैं, तो यह ~/.claude/settings.json में इस तरह की प्रविष्टियाँ लिखता है:
Claude Code फिर हर टूल कॉल से पहले failproofai --hook PreToolUse को एक सबप्रोसेस के रूप में चलाता है, stdin पर एक JSON पेलोड भेजता है।

पेलोड प्रारूप

PostToolUse इवेंट के लिए, पेलोड में tool_result भी होता है जिसमें टूल का आउटपुट होता है। हैंडलर 1 MB stdin लिमिट लागू करता है। इस सीमा से अधिक पेलोड छोड़ दिए जाते हैं और सभी पॉलिसीज़ निहित रूप से अनुमति देती हैं।

रेस्पांस प्रारूप

Deny (PreToolUse):
Deny (PostToolUse):
Instruct (किसी भी ईवेंट को छोड़कर Stop):
Stop event instruct:
  • एक्जिट कोड: 2
  • कारण stderr में लिखा गया (stdout में नहीं)
Allow:
  • एक्जिट कोड: 0
  • खाली stdout
संदेश के साथ Allow: allow(message) एक पॉलिसी को Claude को सूचनात्मक संदर्भ वापस भेजने देता है यहाँ तक कि जब ऑपरेशन की अनुमति हो। हुक हैंडलर निम्नलिखित JSON को stdout में लिखता है (एक कॉन्फ़िग फ़ाइल में नहीं — यह हैंडलर का Claude Code को रेस्पांस है, जैसे deny और instruct रेस्पांस के ऊपर):
  • एक्जिट कोड: 0 (ऑपरेशन की अनुमति है)
  • जब कई पॉलिसीज़ संदेश के साथ allow देते हैं, तो उनके संदेश नई पंक्तियों के साथ जुड़ जाते हैं एक एकल additionalContext स्ट्रिंग में
  • अगर कोई पॉलिसी संदेश प्रदान नहीं करती है, तो stdout खाली है (पहले जैसे)

प्रोसेसिंग पाइपलाइन

src/hooks/handler.ts पूरी पाइपलाइन को लागू करता है:
बिना LLM कॉल के विशिष्ट पेलोड के लिए पूरी प्रक्रिया 100ms में पूरी हो जाती है।

कॉन्फ़िग लोडिंग

src/hooks/hooks-config.ts तीन-स्कोप कॉन्फ़िग लोडिंग को लागू करता है।
मर्ज लॉजिक:
  • enabledPolicies - सभी तीन फ़ाइलों में डीडुप्लिकेटेड यूनियन
  • policyParams - प्रति-पॉलिसी कुंजी, पहली फ़ाइल जो इसे परिभाषित करती है पूरी तरह जीतती है
  • customPoliciesPath - पहली फ़ाइल जो इसे परिभाषित करती है जीतती है
  • llm - पहली फ़ाइल जो इसे परिभाषित करती है जीतती है
वेब डैशबोर्ड पढ़ने और लिखने के लिए readHooksConfig() (केवल ग्लोबल) का उपयोग करता है, क्योंकि इसे प्रोजेक्ट cwd के साथ नहीं चलाया जाता है।

पॉलिसी मूल्यांकन

src/hooks/policy-evaluator.ts क्रम में पॉलिसीज़ चलाता है। प्रत्येक पॉलिसी के लिए:
  1. पॉलिसी के params स्कीमा को देखें (यदि इसके पास है)।
  2. मर्ज किए गए कॉन्फ़िग से policyParams[policy.name] को पढ़ें।
  3. उपयोगकर्ता-प्रदान किए गए मानों को स्कीमा डिफ़ॉल्ट पर मर्ज करें ctx.params का उत्पादन करने के लिए।
  4. हल किए गए संदर्भ के साथ policy.fn(ctx) कॉल करें।
  5. यदि परिणाम deny है, तो तुरंत रुकें और वह निर्णय दें।
  6. यदि परिणाम instruct है, तो संदेश जमा करें और जारी रखें।
  7. यदि परिणाम allow है, तो अगली पॉलिसी पर जाएं।
सभी पॉलिसीज़ चलने के बाद:
  • अगर कोई deny दिया गया था, तो deny रेस्पांस उत्सर्जित करें।
  • यदि कोई instruct रिटर्न एकत्र किए गए हैं, तो सभी संदेशों को जुड़े हुए एकल instruct रेस्पांस उत्सर्जित करें।
  • अन्यथा, allow रेस्पांस उत्सर्जित करें (खाली stdout, एक्जिट 0)।

बिल्ट-इन पॉलिसीज़

src/hooks/builtin-policies.ts सभी 39 बिल्ट-इन पॉलिसीज़ को BuiltinPolicyDefinition ऑब्जेक्ट के रूप में परिभाषित करता है:
जो पॉलिसीज़ params स्वीकार करती हैं वे प्रत्येक पैरामीटर के लिए प्रकार और डिफ़ॉल्ट के साथ PolicyParamsSchema की घोषणा करती हैं। पॉलिसी मूल्यांकनकर्ता fn को कॉल करने से पहले हल किए गए मानों को ctx.params में इंजेक्ट करता है। पॉलिसी फ़ंक्शन ctx.params को पढ़ते हैं बिना null-गार्डिंग के क्योंकि डिफ़ॉल्ट हमेशा पहले लागू होते हैं। पॉलिसीज़ के अंदर पैटर्न मिलान पार्स किए गए कमांड टोकन (argv) का उपयोग करता है, कच्ची स्ट्रिंग मिलान नहीं। यह शेल ऑपरेटर इंजेक्शन के माध्यम से बाईपास को रोकता है (उदाहरण के लिए sudo systemctl status * के लिए एक पैटर्न ; rm -rf / को अपेंड करके बाईपास नहीं किया जा सकता)।

कस्टम पॉलिसीज़

src/hooks/custom-hooks-registry.ts एक globalThis-समर्थित रजिस्ट्री को लागू करता है:
src/hooks/custom-hooks-loader.ts उपयोगकर्ता की पॉलिसी फ़ाइल लोड करता है:
  1. कॉन्फ़िग से customPoliciesPath पढ़ें; अनुपस्थित होने पर छोड़ें।
  2. पूर्ण पथ में हल करें; फ़ाइल मौजूद है यह जाँचें।
  3. सभी from "failproofai" आयात को वास्तविक dist पथ में फिर से लिखें ताकि customPolicies समान globalThis रजिस्ट्री को हल करे।
  4. ESM संगतता सुनिश्चित करने के लिए संक्रमणीय स्थानीय आयात को पुनरावर्ती रूप से फिर से लिखें।
  5. अस्थायी .mjs फ़ाइलें लिखें और entry फ़ाइल को import() करें।
  6. getCustomHooks() को कॉल करके पंजीकृत हुक्स को पुनः प्राप्त करें।
  7. finally ब्लॉक में सभी अस्थायी फ़ाइलें साफ करें।
किसी भी त्रुटि पर (फ़ाइल नहीं मिली, syntax त्रुटि, आयात विफलता), त्रुटि को ~/.failproofai/hook.log में लॉग किया जाता है और लोडर एक खाली सरणी देता है। बिल्ट-इन पॉलिसीज़ प्रभावित नहीं होती हैं। कस्टम पॉलिसीज़ का मूल्यांकन सभी बिल्ट-इन पॉलिसीज़ के बाद किया जाता है। एक कस्टम पॉलिसी deny अभी भी आगे की कस्टम पॉलिसीज़ को शॉर्ट-सर्किट करता है (लेकिन सभी बिल्ट-इन्स पहले ही चल चुकी होती हैं)।

गतिविधि लॉगिंग

प्रत्येक हुक ईवेंट के बाद, हैंडलर ~/.failproofai/hook-activity.jsonl में एक JSONL पंक्ति को अपेंड करता है:
एक पंक्ति प्रति पॉलिसी जिसने एक गैर-allow निर्णय दिया। Allow निर्णय लॉग नहीं होते हैं (फ़ाइल को छोटा रखने के लिए)।

डैशबोर्ड आर्किटेक्चर

डैशबोर्ड एक Next.js 16 एप्लिकेशन है जो App Router के साथ React Server Components और Server Actions का उपयोग करता है।
डेटा प्रवाह:
  • पेज कंपोनेंट प्रोजेक्ट/सेशन डेटा को सीधे फ़ाइलसिस्टम से पढ़ने के लिए lib/projects.ts और lib/log-entries.ts को कॉल करते हैं (पढ़ने के लिए कोई API परत नहीं)।
  • पॉलिसीज़ पेज सभी mutations के लिए Server Actions का उपयोग करता है (टॉगल, params अपडेट, इंस्टॉल/हटाएँ)।
  • सेशन दर्शक Claude के JSONL ट्रांसक्रिप्ट प्रारूप को पार्स करता है और संदेशों और टूल कॉल की एक टाइमलाइन रेंडर करता है।
मुख्य डिज़ाइन निर्णय:
  • कोई डेटाबेस नहीं - सभी स्थायी स्थिति सादे फ़ाइलों में है (~/.failproofai/, ~/.claude/projects/)।
  • Mutations के लिए Server Actions - CRUD संचालन के लिए कोई REST API आवश्यक नहीं।
  • पढ़ने के पृष्ठों के लिए React Server Components - तेज़ प्रारंभिक लोड, डेटा फ़ेचिंग के लिए कोई क्लाइंट बंडल नहीं।
  • क्लाइंट कंपोनेंट केवल जहाँ आवश्यकता हो (पॉलिसी टॉगल, गतिविधि खोज, लॉग दर्शक)।

फ़ाइल लेआउट