सामग्री पर जाएँ
Blume
Esc
↑↓नेविगेट↵खोलें⌘Jप्रीव्यू
इस पेज पर

एजेंट डिस्कवरी

एजेंट बिना अनुमान लगाए आपकी मशीन-रीडेबल सरफेस को कैसे ढूँढते हैं — एजेंट-रीडेबिलिटी मैनिफ़ेस्ट, Link हेडर, RFC 9727 API कैटलॉग, WebMCP, आपकी साइट की जनरेट की गई स्किल और प्रकाशित स्किल्स, DNS-आधारित डिस्कवरी, और Web Bot Auth कीज़।

llms.txt, Markdown मिरर, एक JSON API, और एक MCP सर्वर प्रकाशित करना केवल आधा काम है — एजेंट को अब भी उन्हें ढूँढना पड़ता है। Blume पूरी सरफेस का प्रचार उन्हीं परंपराओं के माध्यम से करता है जिन्हें एजेंट वास्तव में जाँचते हैं: साइट रूट पर एक मैनिफ़ेस्ट, Link हेडर और <link> टैग, well-known फ़ाइलें, और ब्राउज़र का अपना मॉडल कॉन्टेक्स्ट। यहाँ सब कुछ डिफ़ॉल्ट रूप से चालू है और उसी से व्युत्पन्न है जो आपने पहले ही सक्षम कर रखा है।

एजेंट रीडेबिलिटी

Blume आपकी साइट रूट पर एक /agent-readability.json मैनिफ़ेस्ट लिखता है जो इस अनुभाग में वर्णित एजेंट-मुखी सरफेस को इंडेक्स करता है — ताकि एजेंट परंपराओं का अनुमान लगाने या HTML स्क्रैप करने के बजाय एक ही फ़ेच में उसे खोज सके। llms.txt की तरह, यह डिफ़ॉल्ट रूप से चालू है:

agents: {
  agentReadability: true,
}

मैनिफ़ेस्ट केवल वही सूचीबद्ध करता है जो आपने सक्षम किया है — रॉ Markdown मिरर पैटर्न, JSON API और उसका OpenAPI विवरण, llms.txt और llms-full.txt, MCP सर्वर और उसका डिस्कवरी डॉक्यूमेंट, असिस्टेंट एंडपॉइंट, साइटमैप, और RSS फ़ीड — साथ ही आपकी साइट का नाम, विवरण, सोर्स रिपॉज़िटरी, और content-signal उपयोग नीति। deployment.site सेट होने पर URL निरपेक्ष होते हैं और अन्यथा रूट-सापेक्ष:

{
  "artifacts": {
    "markdown": {
      "contentNegotiation": "text/markdown",
      "pattern": "https://docs.example.com/{route}.md"
    },
    "api": {
      "openapi": "https://docs.example.com/openapi.json",
      "pages": "https://docs.example.com/api/docs/pages.json",
      "search": "https://docs.example.com/api/docs/search"
    },
    "llmsFullTxt": "https://docs.example.com/llms-full.txt",
    "llmsTxt": "https://docs.example.com/llms.txt",
    "mcp": {
      "discovery": "https://docs.example.com/.well-known/mcp.json",
      "url": "https://docs.example.com/mcp"
    }
  },
  "description": "Docs for the Acme API.",
  "generator": "blume@2.0.0",
  "name": "Acme Docs",
  "site": "https://docs.example.com",
  "contentUsage": { "search": true, "ai-input": true, "ai-train": true },
  "repository": "https://github.com/acme/docs"
}

contentNegotiation फ़ील्ड केवल तभी दिखाई देता है जब डिप्लॉय की गई साइट वास्तव में Accept: text/markdown हेडर का सम्मान करती है — देखें कॉन्टेंट नेगोशिएशन; हर दूसरे डिप्लॉयमेंट पर मैनिफ़ेस्ट केवल .md मिरर पैटर्न का प्रचार करता है।

इसे छोड़ने के लिए agents.agentReadability को false पर सेट करें, या नियंत्रण अपने हाथ में लेने के लिए अपनी स्वयं की public/agent-readability.json भेजें — Blume उस फ़ाइल को कभी अधिलेखित नहीं करता जिसे आप public/ में रखते हैं।

जो एजेंट किसी साइट की जाँच करते हैं वे मैनिफ़ेस्ट को ढूँढना नहीं जानते — इसलिए Blume IANA-पंजीकृत रिलेशन प्रकारों का उपयोग करते हुए, होमपेज पर एक RFC 8288 Link रिस्पॉन्स हेडर में भी इसका प्रचार करता है:

Link: </.well-known/api-catalog>; rel="api-catalog"; type="application/linkset+json; profile=\"https://www.rfc-editor.org/info/rfc9727\"",
  </.well-known/ai-catalog.json>; rel="ai-catalog"; type="application/ai-catalog+json",
  </openapi.json>; rel="service-desc"; type="application/json",
  </agent-readability.json>; rel="describedby"; type="application/json",
  </llms.txt>; rel="describedby"; type="text/plain",
  </index.md>; rel="alternate"; type="text/markdown"

प्रत्येक प्रविष्टि केवल तभी दिखाई देती है जब उसकी सुविधा चालू हो। alternate लिंक होमपेज के Markdown मिरर की ओर संकेत करता है — जब होम रूट एक कॉन्टेंट पेज हो तो पेज का अपना रॉ Markdown, या जब वह एक लैंडिंग पेज हो तो संश्लेषित llms.txt फ़ॉलबैक। service-desc लिंक (RFC 8631) JSON API के OpenAPI विवरण की ओर संकेत करता है, api-catalog जनरेट किए गए API कैटलॉग की ओर, और ai-catalog AI कैटलॉग की ओर। यह हेडर हर उस सरफेस पर चलता है जिसे Blume नियंत्रित करता है: उत्सर्जित _headers फ़ाइल के माध्यम से स्टैटिक बिल्ड (Netlify और Cloudflare), डिप्लॉय के रूटिंग नियमों के माध्यम से Vercel सर्वर बिल्ड, और dev सर्वर (curl -I localhost:4321 से इसे जाँचें)। dev सर्वर का हेडर केवल वही सूचीबद्ध करता है जो वह सर्व करता है — service-desc और alternate लिंक — क्योंकि blume build कैटलॉग, agent-readability.json, और llms.txt को बिल्ड आउटपुट में लिखता है।

हालाँकि हर एजेंट रूट से प्रवेश नहीं करता — कोई एजेंट जो किसी खोज परिणाम या साझा किए गए लिंक का अनुसरण करता है, वह किसी गहरे पेज पर पहुँचता है और होमपेज हेडर कभी नहीं देखता। इसलिए हर रेंडर किया गया पेज भी उन्हीं IANA-पंजीकृत रिलेशनों का उपयोग करते हुए, अपने HTML <head> में वही डिस्कवरी लिंक रखता है:

<link
  rel="describedby"
  href="/agent-readability.json"
  type="application/json"
/>
<link rel="describedby" href="/llms.txt" type="text/plain" />
<link
  rel="ai-catalog"
  href="/.well-known/ai-catalog.json"
  type="application/ai-catalog+json"
/>
<link rel="ard" href="/.well-known/ard.json" type="application/json" />
<link rel="alternate" href="/docs/example.md" type="text/markdown" />

यहाँ alternate लिंक उसी पेज के अपने रॉ-Markdown मिरर की ओर संकेत करता है, ताकि एजेंट जिस HTML पर पहुँचा है वहाँ से सीधे टोकन-कुशल संस्करण पर जा सके। चूँकि हेड लिंक प्रीरेंडर किए गए HTML के साथ यात्रा करते हैं, वे उन होस्ट्स पर भी काम करते हैं जो _headers को अनदेखा करते हैं और कस्टम रिस्पॉन्स हेडर बिल्कुल नहीं भेज सकते (GitHub Pages, S3) — चाहे एजेंट किसी भी पेज से प्रवेश करे।

API कैटलॉग

जब साइट API प्रकाशित करती है, तो Blume /.well-known/api-catalog पर एक RFC 9727 API कैटलॉग जनरेट करता है — एक linkset जो एजेंटों को केवल डोमेन से ही आपके API की गणना करने देता है, जिसे हर बिल्ड सरफेस पर उसके पंजीकृत application/linkset+json मीडिया प्रकार और RFC के profile="https://www.rfc-editor.org/info/rfc9727" पैरामीटर के साथ सर्व किया जाता है। कॉन्फ़िगर करने के लिए कुछ नहीं है: कैटलॉग उसी से व्युत्पन्न होता है जो पहले से blume.config.ts में है। प्रत्येक OpenAPI, AsyncAPI, या GraphQL रेफ़रेंस अपने रेंडर किए गए डॉक्स रूट पर एंकर की गई एक प्रविष्टि बन जाता है, जिसमें service-doc उन डॉक्स की ओर और service-desc स्पेक की ओर संकेत करता है जब वह किसी फ़ेच करने योग्य URL पर रहती है; साइट का अपना JSON API अपने /openapi.json द्वारा वर्णित एक प्रविष्टि बन जाता है; और MCP सर्वर अपने डिस्कवरी डॉक्यूमेंट को सेवा विवरण के रूप में रखते हुए एक प्रविष्टि बन जाता है:

{
  "linkset": [
    {
      "anchor": "https://docs.example.com/reference",
      "service-doc": [
        { "href": "https://docs.example.com/reference", "type": "text/html" }
      ],
      "service-desc": [{ "href": "https://api.example.com/openapi.json" }]
    },
    {
      "anchor": "https://docs.example.com/api/docs",
      "service-desc": [
        {
          "href": "https://docs.example.com/openapi.json",
          "type": "application/json"
        }
      ],
      "service-doc": [
        { "href": "https://docs.example.com/", "type": "text/html" }
      ]
    },
    {
      "anchor": "https://docs.example.com/mcp",
      "service-desc": [
        {
          "href": "https://docs.example.com/.well-known/mcp.json",
          "type": "application/json"
        }
      ],
      "service-doc": [
        { "href": "https://docs.example.com/", "type": "text/html" }
      ]
    }
  ]
}

ऐसी साइट जिसमें कोई API रेफ़रेंस नहीं है, कोई MCP सर्वर नहीं है, और JSON API बंद है, कोई कैटलॉग उत्सर्जित नहीं करती — उसमें कुछ होता ही नहीं। हर जगह की तरह, आपके द्वारा स्वयं भेजी गई public/.well-known/api-catalog फ़ाइल जनरेट की गई फ़ाइल पर वरीयता पाती है।

AI कैटलॉग

API कैटलॉग API सूचीबद्ध करता है। AI कैटलॉग वह सब कुछ सूचीबद्ध करता है जिसे कोई एजेंट साइट से उठा सकता है — MCP सर्वर, प्रत्येक प्रकाशित स्किल, JSON API, प्रत्येक रेंडर किया गया API रेफ़रेंस, और llms.txt — उसी प्रारूप में जिसे एजेंट रजिस्ट्रियाँ इंडेक्स करती हैं: /.well-known/ai-catalog.json पर एक AI Catalog डॉक्यूमेंट, जो वही मैनिफ़ेस्ट भी है जिसे Agentic Resource Discovery (ARD) उपभोक्ता हल करते हैं। प्रत्येक प्रविष्टि एक डोमेन-एंकर किया गया urn:air:<host>:<namespace>:<name> पहचानकर्ता, एक प्रदर्शन नाम, एक-पंक्ति का विवरण, आर्टिफ़ैक्ट का मीडिया प्रकार, उसका URL, और कुछ representativeQueries रखती है — नमूना प्रश्न जिनका उत्तर वह संसाधन दे सकता है, जिन्हें रजिस्ट्रियाँ सिमेंटिक खोज के लिए एम्बेड करती हैं। यहाँ “Acme” शीर्षक वाली ऐसी साइट का कैटलॉग है जिसमें MCP सर्वर चालू है और एक स्किल प्रकाशित है:

{
  "specVersion": "1.0",
  "host": {
    "displayName": "Acme",
    "identifier": "did:web:docs.example.com",
    "documentationUrl": "https://docs.example.com/"
  },
  "entries": [
    {
      "identifier": "urn:air:docs.example.com:mcp:acme",
      "displayName": "Acme",
      "description": "Model Context Protocol server over the Acme documentation: full-text search, page Markdown, the page index, and the navigation tree.",
      "type": "application/mcp-server-card+json",
      "url": "https://docs.example.com/.well-known/mcp/server-card.json",
      "capabilities": [
        "search_docs",
        "get_page",
        "list_pages",
        "get_navigation"
      ],
      "representativeQueries": [
        "search the Acme documentation",
        "get a page of the Acme docs as Markdown",
        "list every page in the Acme docs"
      ]
    },
    {
      "identifier": "urn:air:docs.example.com:skill:acme",
      "displayName": "acme",
      "description": "Set up an Acme project and call its API.",
      "type": "application/agent-skills+md",
      "url": "https://docs.example.com/.well-known/agent-skills/acme/SKILL.md",
      "representativeQueries": [
        "load the acme agent skill",
        "how do I use acme"
      ]
    },
    {
      "identifier": "urn:air:docs.example.com:api:docs",
      "displayName": "Acme docs API",
      "description": "REST API over the Acme documentation: the page index, each page as JSON or Markdown, and the navigation tree, described by this OpenAPI document.",
      "type": "application/vnd.oai.openapi+json",
      "url": "https://docs.example.com/openapi.json",
      "representativeQueries": [
        "fetch a page of the Acme docs as JSON",
        "list the pages in the Acme docs",
        "get the navigation tree of the Acme docs"
      ]
    },
    {
      "identifier": "urn:air:docs.example.com:docs:llms-txt",
      "displayName": "Acme llms.txt",
      "description": "llms.txt index of the Acme documentation: every page with a one-line summary, plus the agent-facing resources on this site.",
      "type": "text/plain",
      "url": "https://docs.example.com/llms.txt",
      "representativeQueries": [
        "what is Acme",
        "overview of the Acme documentation"
      ]
    }
  ]
}

ARD का वर्तमान संशोधन मैनिफ़ेस्ट को /.well-known/ard.json से पढ़ता है और ai-catalog.json को पूर्ववर्ती पथ कहता है, इसलिए Blume वही डॉक्यूमेंट दोनों जगह लिखता है, हर पेज के हेड में उसे दोनों लिंक रिलेशनों (ai-catalog और ard) के अंतर्गत प्रचारित करता है, और उसे llms.txt तथा agent-readability.json में सूचीबद्ध करता है। कैटलॉग और उसके .well-known पड़ोसी (API कैटलॉग, MCP डिस्कवरी फ़ाइलें) हर बिल्ड सरफेस पर Access-Control-Allow-Origin: * के साथ सर्व किए जाते हैं, ताकि किसी अन्य ऑरिजिन से उन्हें पढ़ने वाली रजिस्ट्री ब्लॉक न हो।

प्रविष्टि पहचानकर्ता आपके डोमेन पर एंकर किए जाते हैं, इसलिए कैटलॉग को एक deployment.site की आवश्यकता होती है — उसके बिना कुछ भी उत्सर्जित नहीं होता। यह डिफ़ॉल्ट रूप से चालू है; agents.catalog: false इसे बंद कर देता है। जनरेट किए गए प्रश्न साइट शीर्षक और प्रत्येक प्रविष्टि के अपने नाम से व्युत्पन्न होते हैं। किसी प्रविष्टि के लिए अपने स्वयं के प्रश्न लिखने हेतु, उन्हें पहचानकर्ता की पूँछ (<namespace>:<name>) द्वारा कुंजीबद्ध करें:

export default defineConfig({
  agents: {
    catalog: {
      queries: {
        "mcp:acme": ["how do I install Acme", "search the Acme docs"],
        "skill:acme": ["set up an Acme project", "write an Acme plugin"],
      },
    },
  },
});

कोई सूची उस प्रविष्टि के लिए जनरेट किए गए प्रश्नों को प्रतिस्थापित कर देती है; जिन प्रविष्टियों का नाम आप नहीं लेते वे अपने प्रश्न बनाए रखती हैं। हर जगह की तरह, आपके द्वारा स्वयं भेजी गई public/.well-known/ai-catalog.json (या ard.json) जनरेट की गई फ़ाइल पर वरीयता पाती है।

WebMCP

WebMCP एक उभरता हुआ ब्राउज़र API है जो किसी पेज को सीधे एजेंटिक ब्राउज़र के साथ टूल पंजीकृत करने देता है — किसी अलग सर्वर कनेक्शन की आवश्यकता नहीं। हर Blume पेज पेज के मॉडल कॉन्टेक्स्ट पर डॉक्स की रीड-ओनली सरफेस पंजीकृत करता है: search_docs (साइट खोज), get_page (किसी पेज का रॉ Markdown), और list_pages (llms.txt इंडेक्स)। स्क्रिप्ट बहुत छोटी है, जब तक कोई टूल वास्तव में कॉल न किया जाए तब तक कोई खोज मशीनरी लोड नहीं करती, और API के बिना हर ब्राउज़र में चुपचाप no-op हो जाती है — जो आज Chrome के अर्ली प्रीव्यू के बाहर हर ब्राउज़र है। यह उसी सरफेस पर पंजीकरण करती है जिसे अस्थिर स्पेक उजागर करता है (navigator.modelContext या document.modelContext), provideContext या प्रति-टूल registerTool के माध्यम से।

यह डिफ़ॉल्ट रूप से चालू है; ऑप्ट आउट करने के लिए webmcp: false सेट करें:

agents: {
  webmcp: false,
}

आपकी साइट की स्किल

हर बिल्ड आपके डॉक्स के लिए एक एजेंट स्किल लिखता है — एक SKILL.md जिसे कोई कोडिंग एजेंट आपके प्रोडक्ट के साथ काम करने के लिए इंस्टॉल कर सकता है। इसे /skill.md पर सर्व किया जाता है और स्किल्स इंडेक्स में सूचीबद्ध किया जाता है। Blume इसे किसी मॉडल को कॉल किए बिना, उसी से बनाता है जो वह साइट के बारे में पहले से जानता है, इसलिए इसकी कोई लागत नहीं होती और जब भी आपके डॉक्स बदलते हैं, यह भी बदल जाती है। इसमें शामिल हैं:

  • साइट का शीर्षक और विवरण, और यह कि किसी एजेंट को स्किल का उपयोग कब करना चाहिए
  • किसी भी पेज को Markdown के रूप में कैसे पढ़ें, साथ ही llms.txt, llms-full.txt, MCP सर्वर, JSON API, और चेंजलॉग, जब साइट उन्हें सर्व करती है
  • आपके API रेफ़रेंस
  • साइडबार क्रम में डॉक्स का एक मानचित्र, जो प्रत्येक पेज के Markdown को उसके एक-पंक्ति के विवरण (उसका मेटा विवरण, जैसा कि llms.txt में) के साथ लिंक करता है

स्किल का नाम आपकी साइट के title के आधार पर रखा जाता है (Acme Docs, acme-docs बन जाता है)। यह डिफ़ॉल्ट भाषा में वर्तमान संस्करण को कवर करती है, API ऑपरेशन पेजों और चेंजलॉग प्रविष्टियों को छोड़ देती है (मानचित्र के ऊपर प्रत्येक की अपनी एक पंक्ति होती है), उन पेजों को भी छोड़ती है जिन्हें llms.txt छोड़ता है (ड्राफ़्ट, छिपे हुए और noindex पेज, और ai.exclude वाले पेज), और अधिकतम 200 पेज सूचीबद्ध करती है, शेष के लिए llms.txt की ओर संकेत करते हुए। लिंक निरपेक्ष होते हैं, इसलिए स्किल को deployment.site की आवश्यकता होती है; उसके बिना बिल्ड इसे छोड़ देता है।

जनरेट की गई स्किल आपके डॉक्स की एक मार्गदर्शिका है, आपके प्रोडक्ट का सारांश नहीं। ऐसी स्किल के लिए जो किसी एजेंट को आपका प्रोडक्ट सिखाए — सेटअप, मूल अवधारणाएँ, सामान्य कार्य, और सावधानियाँ — अपने कोडिंग एजेंट से उसे डॉक्स के आधार पर लिखवाएँ:

blume skill --claude   # or --codex

blume skill Claude Code या Codex को blume-write-skill स्किल के साथ खोलता है, जो आपके agents.skills फ़ोल्डर के अंतर्गत (सेट न होने पर ./skills, जिसे वह आपके कॉन्फ़िग में जोड़ देता है) आपकी साइट के नाम पर एक SKILL.md लिखती है, ताकि वह जनरेट की गई स्किल को प्रतिस्थापित कर दे। आप इसकी समीक्षा करते हैं और इसे किसी भी अन्य फ़ाइल की तरह कमिट करते हैं; इसमें आपके एजेंट के टोकन केवल एक बार खर्च होते हैं, हर बिल्ड पर नहीं। डॉक्स में किसी बड़े बदलाव के बाद इसे फिर से चलाएँ, क्योंकि हाथ से लिखी गई स्किल स्वयं अपडेट नहीं होती। बिना फ़्लैग के, blume skill यह प्रिंट करता है कि स्किल कहाँ जाएगी और किसी अन्य एजेंट को उसकी ओर कैसे निर्देशित करें।

agents.skills में उसी नाम की कोई भी स्किल, चाहे आप उसे किसी भी तरह लिखें, इंडेक्स में जनरेट की गई स्किल को प्रतिस्थापित कर देती है, और जब वह अकेली SKILL.md हो तो /skill.md पर भी। आपके द्वारा भेजी गई public/skill.md दोनों पर वरीयता पाती है। स्किल को बंद करने के लिए:

agents: {
  skillMd: false,
}

स्किल्स डिस्कवरी

यदि आपका प्रोजेक्ट एजेंट स्किल्स भेजता है — Blume रिपॉज़िटरी स्वयं ऐसा करती है — तो agents.skills को उस डायरेक्टरी की ओर संकेत करें जो उन्हें रखती है, और बिल्ड उन्हें Agent Skills Discovery RFC के अनुसार डिस्कवरी के लिए प्रकाशित करता है:

agents: {
  skills: "./skills",
}

पथ आपके प्रोजेक्ट रूट के सापेक्ष हल होता है, और SKILL.md वाली प्रत्येक उप-डायरेक्टरी एक प्रकाशित स्किल बन जाती है। ऐसी स्किल जो अकेली SKILL.md है, उसे यथावत /.well-known/agent-skills/<name>/SKILL.md (type: "skill-md") पर कॉपी किया जाता है; सहायक संसाधनों (scripts/, references/, assets/) वाली स्किल को एक नियतात्मक .tar.gz (type: "archive") में बंडल किया जाता है ताकि अनपैक करने के बाद उसके सापेक्ष रेफ़रेंस हल हो जाएँ, और स्क्रिप्ट के एक्ज़ीक्यूट बिट्स संरक्षित रहें। /.well-known/agent-skills/index.json पर डिस्कवरी इंडेक्स v0.2.0 $schema रखता है और, प्रति स्किल, उसका नाम, प्रकार, विवरण (SKILL.md फ़्रंटमैटर से), आर्टिफ़ैक्ट URL, और वह SHA-256 डाइजेस्ट जिसके विरुद्ध क्लाइंट डाउनलोड सत्यापित करते हैं।

जिन स्किल्स का name/description अनुपस्थित या स्पेक-अमान्य है, उन्हें टूटी हुई अवस्था में प्रकाशित करने के बजाय एक बिल्ड चेतावनी के साथ छोड़ दिया जाता है, और आपके द्वारा स्वयं भेजी गई public/.well-known/agent-skills/index.json पूरी सरफेस पर नियंत्रण ले लेती है। प्रकाशित स्किल्स, आपकी साइट की अपनी स्किल सहित, llms.txt में भी सूचीबद्ध होती हैं।

DNS-आधारित डिस्कवरी (DNS-AID)

DNS for AI Discovery एक उभरता हुआ IETF ड्राफ़्ट है जो एजेंटों को एक भी HTTP अनुरोध किए बिना किसी साइट की AI सरफेस खोजने देता है, एक well-known DNS एंट्रीपॉइंट पर ServiceMode SVCB/HTTPS रिकॉर्ड क्वेरी करके। DNS रिकॉर्ड आपके ज़ोन में रहते हैं, बिल्ड में नहीं, इसलिए यह एकमात्र डिस्कवरी सरफेस है जिसे Blume आपके लिए प्रकाशित नहीं कर सकता — इसके बजाय, अपने DNS प्रदाता के पास एक रिकॉर्ड जोड़ें:

_index._agents.docs.example.com. 3600 IN HTTPS 1 docs.example.com. alpn=h2

यदि आपका प्रदाता HTTPS रिकॉर्ड प्रकार प्रदान करता है तो उसका उपयोग करें (Vercel DNS करता है; यह सादे SVCB प्रकार का समर्थन नहीं करता), अन्यथा alpn और port पैरामीटर वाला एक ServiceMode SVCB रिकॉर्ड। ड्राफ़्ट यह भी अनुशंसा करता है कि ज़ोन को DNSSEC से साइन किया जाए ताकि सत्यापन करने वाले रिज़ॉल्वर प्रमाणीकृत उत्तर लौटाएँ — Cloudflare जैसे प्रदाता इसे एक क्लिक में सक्षम कर देते हैं, जबकि कुछ (Vercel DNS सहित) इसका समर्थन बिल्कुल नहीं करते।

blume audit --url <origin> यह आपके लिए जाँचता है: जब deployment.site सेट होता है, तो नेटवर्क टियर DNS-over-HTTPS के माध्यम से एंट्रीपॉइंट को क्वेरी करता है और यदि कोई रिकॉर्ड मौजूद नहीं है तो प्रकाशित करने योग्य सटीक रिकॉर्ड बताता है, साथ ही यह भी कि उत्तर DNSSEC-प्रमाणीकृत हैं या नहीं। यदि आपका नेटवर्क सार्वजनिक रिज़ॉल्वरों (Google, Cloudflare) को ब्लॉक करता है तो लुकअप को अपने स्वयं के रिज़ॉल्वर की ओर संकेत करने के लिए BLUME_DOH_URL सेट करें।

Web Bot Auth

Web Bot Auth दूसरी दिशा में काम करता है: यह एजेंटों द्वारा आपके डॉक्स पढ़ने के बारे में नहीं है, बल्कि आपके संगठन के एजेंटों द्वारा स्वयं की पहचान बताने के बारे में है जब वे अन्यत्र अनुरोध करते हैं। आपके एजेंट अपने अनुरोधों को HTTP Message Signatures से साइन करते हैं, और प्राप्तकर्ता साइटें उन्हें आपके डोमेन पर प्रकाशित एक सार्वजनिक-कुंजी डायरेक्टरी के विरुद्ध सत्यापित करती हैं। यदि आपका संगठन एजेंट चलाता है और आपकी Blume साइट उसी डोमेन पर रहती है जिससे वे स्वयं की पहचान बताते हैं, तो उनकी सार्वजनिक कुंजियाँ प्रकाशित करें:

agents: {
  webBotAuth: {
    keys: [{ kty: "OKP", crv: "Ed25519", x: "JrQLj5P_89iXES9-vFgrIy29c…" }],
  },
}

तब Blume हर बिल्ड सरफेस पर /.well-known/http-message-signatures-directory पर JWKS को उसके पंजीकृत मीडिया प्रकार के साथ सर्व करता है। डायरेक्टरी परिभाषा से ही सार्वजनिक है, इसलिए कॉन्फ़िग केवल सार्वजनिक कुंजियाँ ही स्वीकार करता है — निजी सामग्री (d, p, q, …) वाला JWK लीक हुए क्रेडेंशियल को भेजने के बजाय एक त्रुटि के साथ सत्यापन में विफल हो जाता है। एक Ed25519 जोड़ी इससे जनरेट करें:

node -e 'const { generateKeyPairSync } = require("node:crypto"); const { publicKey, privateKey } = generateKeyPairSync("ed25519"); console.log("public: ", JSON.stringify(publicKey.export({ format: "jwk" }))); console.log("private:", JSON.stringify(privateKey.export({ format: "jwk" })))'

सार्वजनिक JWK ऊपर के कॉन्फ़िग में जाती है; निजी वाली वहाँ जाती है जहाँ आपका साइनिंग एजेंट चलता है (एक सीक्रेट मैनेजर, कभी भी रिपॉज़िटरी नहीं)। यदि आपका संगठन एजेंट संचालित नहीं करता, तो इसे छोड़ दें — एक खाली डायरेक्टरी ऐसा कुछ नहीं दर्शाती जिसे सत्यापित करना सार्थक हो।

चूँकि blume.config.ts बिल्ड समय पर निष्पादित होती है, कुंजी को हार्डकोड करने की आवश्यकता नहीं है — कॉन्फ़िग को कुंजी ब्लॉब्स से मुक्त रखने और बिना कमिट के रोटेट करने के लिए इसे बिल्ड-टाइम एनवायरनमेंट वेरिएबल से लोड करें:

const webBotAuthKey = process.env.WEB_BOT_AUTH_PUBLIC_JWK;

export default defineConfig({
  agents: {
    webBotAuth: {
      keys: webBotAuthKey ? [JSON.parse(webBotAuthKey)] : [],
    },
  },
});

जिन एनवायरनमेंट में यह वेरिएबल नहीं है वे कोई डायरेक्टरी प्रकाशित नहीं करते, और इस तरह लोड की गई कुंजी बिल्कुल इनलाइन कुंजी की तरह ही सत्यापित होती है — निजी-सामग्री जाँच सहित। (सार्वजनिक कुंजी कोई सीक्रेट नहीं है, इसलिए उसे इनलाइन कमिट करना भी उतना ही ठीक है; env वेरिएबल एक एर्गोनॉमिक विकल्प है, सुरक्षा संबंधी नहीं।)

अंतिम अपडेट

क्या यह पेज सहायक था?