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

AI

llms.txt और OpenAPI द्वारा वर्णित एक JSON API के साथ अपने डॉक्स को मशीन-पठनीय बनाएँ, एक वैकल्पिक इन-पेज Ask AI सहायक जोड़ें, और कोडिंग एजेंट्स के लिए एक होस्टेड MCP सर्वर उपलब्ध कराएँ।

Blume में कुछ AI सुविधाएँ हैं: बाहरी टूल्स के लिए मशीन-पठनीय डॉक्स (llms.txt और एक OpenAPI विवरण के साथ एक JSON API, दोनों डिफ़ॉल्ट रूप से चालू), एक इन-पेज Ask AI सहायक, और कोडिंग एजेंट्स के लिए एक होस्टेड MCP सर्वर। Ask AI और MCP ऑप्ट-इन हैं, और जब तक आप कोई सुविधा चालू नहीं करते, स्टैटिक डॉक्स पूरी तरह स्टैटिक बने रहते हैं।

llms.txt

Blume आपके डॉक्स के मशीन-पठनीय संस्करण उत्सर्जित करता है जिन्हें कोडिंग एजेंट और चैट सहायक उपभोग कर सकते हैं। यह डिफ़ॉल्ट रूप से चालू है; इसे बंद करने के लिए llmsTxt: false सेट करें:

ai: {
  llmsTxt: false,
}

सक्षम होने पर, blume build आपकी साइट के रूट में दो फ़ाइलें लिखता है:

  • /llms.txt — एक संक्षिप्त इंडेक्स: आपकी साइट का शीर्षक और विवरण, फिर हर पेज की एक लिंक की गई सूची उसके सारांश के साथ, ऐसे अनुभागों में व्यवस्थित जो आपके साइडबार को प्रतिबिंबित करते हैं — फ़ोल्डर और समूह शीर्षक बन जाते हैं, इसलिए एजेंट को डॉक्स की संरचना दिखती है, एक सपाट ढेर नहीं।
  • /llms-full.txt — पूरा संग्रह: हर पेज का पूरा Markdown मुख्य भाग, उसके स्रोत URL के साथ, एक ही फ़ाइल में।

ड्राफ़्ट पेज बाहर रखे जाते हैं। deployment.site सेट करें ताकि लिंक और स्रोत URL निरपेक्ष पतों में हल हों।

llmsTxt एक ऑब्जेक्ट रूप भी लेता है जिसमें यह नियंत्रित करने के विकल्प हैं कि फ़ाइलों में क्या शामिल हो। यदि आपका API संदर्भ किसी प्लेसहोल्डर या उदाहरण स्पेक का दस्तावेज़ीकरण करता है, तो उसके जनरेट किए गए पेजों को दोनों फ़ाइलों से बाहर रखने के लिए openapi: false सेट करें:

ai: {
  llmsTxt: {
    enabled: true, // default
    openapi: false, // exclude generated API reference pages
  },
}

ऑब्जेक्ट रूप details भी लेता है: ऐसा Markdown जो llms.txt में शीर्षक और सारांश के ठीक बाद, पेज अनुभागों से पहले रखा जाता है — llms.txt स्पेक का मुक्त-रूप “details” ब्लॉक। यही वह जगह है जहाँ एजेंट्स को बताया जाता है कि आपके उत्पाद का सहारा कब लेना है और उसे कैसे कॉल करना है, जिसे रेडीनेस स्कैनर स्पष्ट रूप से खोजते हैं; एक इंस्टॉल कमांड और पैकेज नाम भी यहीं आते हैं:

ai: {
  llmsTxt: {
    details: [
      "## When to use Acme",
      "",
      "Reach for Acme when a project needs hosted feature flags. Install the CLI with `npm install -g acme`; the API reference below covers every endpoint.",
    ].join("\n"),
  },
}

llms.txt का अंत दो जनरेट किए गए अनुभागों से होता है जिन्हें किसी कॉन्फ़िगरेशन की ज़रूरत नहीं। Agent skills ai.skills के माध्यम से प्रकाशित प्रत्येक स्किल को उसके विवरण के साथ सूचीबद्ध करता है (जहाँ कोई स्किल बताती है कि उसका उपयोग कब करना है)। Agent resources बिल्ड द्वारा उत्सर्जित हर मशीन-पठनीय आर्टिफ़ैक्ट को लिंक करता है — llms-full.txt, प्रति-पेज कच्चा Markdown प्रतिबिंब, MCP सर्वर और उसका डिस्कवरी दस्तावेज़, स्किल्स इंडेक्स, API कैटलॉग, agent-readability.json, और साइटमैप — प्रत्येक केवल तभी जब वह मौजूद हो, ताकि जो एजेंट llms.txt के अलावा कुछ न पढ़े, वह भी पूरी सतह खोज ले।

किसी एक पेज को दोनों फ़ाइलों से बाहर रखने के लिए, उसके फ़्रंटमैटर में ai.exclude सेट करें:

---
title: Internal notes
ai:
  exclude: true
---

पेज फिर भी रेंडर होता है, खोज में बना रहता है, और साइटमैप में अपना स्थान बनाए रखता है — केवल llms.txt फ़ाइलें ही इसे छोड़ती हैं।

किसी भी फ़ाइल पर पूर्ण नियंत्रण लेने के लिए, अपने public/ फ़ोल्डर में अपनी स्वयं की llms.txt या llms-full.txt जोड़ें। कस्टम फ़ेविकॉन की तरह, इसे स्वचालित रूप से उठा लिया जाता है और जनरेट की गई फ़ाइल के स्थान पर भेजा जाता है — एक को ओवरराइड करें और Blume फिर भी दूसरी जनरेट करता है।

कच्चा Markdown

किसी भी पेज के URL में .md या .mdx जोड़ें ताकि उसका कच्चा Markdown स्रोत प्राप्त हो — LLMs, कोडिंग एजेंट्स और “copy as Markdown” वर्कफ़्लो के लिए एकदम सही। यह हर पेज के लिए, dev और production दोनों में, बिना किसी कॉन्फ़िगरेशन के उपलब्ध है।

URL क्या लौटाता है
/quickstart रेंडर किया गया पेज
/quickstart.md सादा Markdown, कंपोनेंट्स परिवर्तित किए हुए
/quickstart.mdx कच्चा MDX स्रोत, ठीक वैसा ही जैसा लिखा गया

नेस्टेड रूट्स भी उसी तरह काम करते हैं (/content/syntax.md), और होम पेज /index.md पर सर्व किया जाता है।

.md वैरिएंट उन उपभोक्ताओं के लिए कंपोनेंट्स को सादे Markdown में डाउनलेवल करता है जो JSX की व्याख्या नहीं कर सकते: <TypeTable> एक Markdown तालिका बन जाती है, <Callout> एक लेबल किया गया ब्लॉककोट, <Steps> एक क्रमबद्ध सूची, <Tabs> बोल्ड-लेबल वाले अनुभाग, <Card> अपने मुख्य भाग के ऊपर अपना शीर्षक एक लिंक के रूप में (और <CardGroup> उसमें रखे कार्ड्स), और <YouTube> एक लिंक। प्रॉप्स का मूल्यांकन पेज के frontmatter को स्कोप में रखकर किया जाता है, इसलिए title={frontmatter.status} जैसा प्रॉप उसी मान में हल होता है जो रेंडर किया गया पेज दिखाता है। जो कुछ भी सटीक रूप से परिवर्तित नहीं किया जा सकता — कोई कस्टम कंपोनेंट, या किसी इम्पोर्ट से गणना किया गया प्रॉप — उसे जस का तस छोड़ दिया जाता है, और फ़ेंस किए गए कोड ब्लॉक्स के भीतर के कंपोनेंट मार्कअप को कभी नहीं छुआ जाता। यही रूपांतरण llms-full.txt और MCP सर्वर के get_page टूल पर भी लागू होता है, इसलिए हर एजेंट-सामने वाली सतह साफ़ Markdown पढ़ती है। जब आपको अपरिवर्तित स्रोत चाहिए, तो .mdx वैरिएंट का उपयोग करें।

कंटेंट नेगोशिएशन

एजेंट्स को .md परंपरा जानने की ज़रूरत नहीं है: किसी पेज के अपने URL को Accept: text/markdown हेडर के साथ अनुरोध करने पर उसी पते पर Markdown वैरिएंट सर्व होता है, Vary: Accept के साथ ताकि कैश दोनों को अलग रखें। dev सर्वर हेडर को बिना किसी सेटअप के सम्मानित करता है, और एक Vercel या Cloudflare सर्वर बिल्ड उसी नेगोशिएशन को डिप्लॉय में स्वचालित रूप से जोड़ देता है — Vercel पर रूटिंग नियम, Cloudflare पर एक जनरेट किया गया Worker — किसी कॉन्फ़िगरेशन की आवश्यकता नहीं। होमपेज हमेशा नेगोशिएट करता है, तब भी जब वह किसी कंटेंट पेज के बजाय एक कस्टम लैंडिंग पेज हो: उसका Markdown प्रतिबिंब llms.txt इंडेक्स पर वापस गिरता है, इसलिए साइट रूट से Markdown माँगने वाले एजेंट को साइट का मशीन-पठनीय नक्शा मिलता है। Markdown प्रतिक्रियाएँ एक x-markdown-tokens हेडर भी ले जाती हैं — एक अनुमानित टोकन गणना (~4 अक्षर प्रति टोकन), Cloudflare के Markdown for Agents की परंपरा का अनुसरण करते हुए — हर उस सतह पर जहाँ Blume प्रतिक्रिया हेडर नियंत्रित करता है: dev सर्वर, सर्वर-रेंडर की गई प्रतिक्रियाएँ, और Vercel तथा Cloudflare पर नेगोशिएट किया गया होमपेज। अन्य डिप्लॉय लक्ष्य पूर्व-रेंडर किए गए पेजों को एक स्टैटिक परत से सर्व करते हैं जिसमें अनुरोध-समय का कोई हुक नहीं होता, इसलिए वहाँ एजेंट सीधे .md URL लाते हैं; एजेंट रीडेबिलिटी मैनिफ़ेस्ट केवल उन डिप्लॉयमेंट्स पर contentNegotiation का विज्ञापन करता है जो हेडर को सम्मानित करते हैं।

अनुपस्थित पेज भी नेगोशिएट करते हैं। हर बिल्ड /404.md पर एक Markdown 404 पेज उत्सर्जित करता है — नहीं-मिला संदेश, उसके बाद हर शीर्ष-स्तरीय अनुभाग, साइटमैप, और llms.txt की ओर पुनर्प्राप्ति लिंक — और Vercel पर, किसी अस्तित्वहीन URL के लिए ऐसा अनुरोध जो Markdown को प्राथमिकता देता है, या ऐसा कोई भी .md URL जिसके पीछे कोई पेज न हो, HTML शेल के बजाय वही बॉडी एक वास्तविक 404 स्थिति के साथ प्राप्त करता है।

कस्टम कंपोनेंट सीरियलाइज़र

ai.markdownComponents के साथ अपने स्वयं के कंपोनेंट्स को एक Markdown रूप दें — JSX नाम से सीरियलाइज़र का एक मानचित्र। प्रत्येक सीरियलाइज़र कंपोनेंट के props (MDX एट्रिब्यूट्स से स्थैतिक रूप से मूल्यांकित, पेज के frontmatter को स्कोप में रखकर), उसके children (पहले ही Markdown में डाउनलेवल किए हुए), और पेज का frontmatter डेटा प्राप्त करता है, और प्रतिस्थापन लौटाता है — या JSX को जस का तस छोड़ने के लिए null:

import { defineConfig } from "blume";
import type { ComponentMarkdown } from "blume";

const chart: ComponentMarkdown = ({ props }) =>
  `![${props.title}](/charts/${props.slug}.png)`;

export default defineConfig({
  ai: {
    markdownComponents: {
      Chart: chart,
    },
  },
});

कंटेनर कंपोनेंट्स के लिए, childComponents("Name") टैग के अनुसार सीधे चिल्ड्रन निकालता है — ठीक उसी तरह जैसे अंतर्निर्मित <Steps> सीरियलाइज़र अपने <Step> आइटम एकत्र करता है — और childBlocks() हर सीधे चाइल्ड को क्रम में लौटाता है, कंपोनेंट्स और गद्य दोनों, प्रत्येक पहले ही Markdown के एक ब्लॉक में डाउनलेवल किया हुआ (अंतर्निर्मित <CardGroup> सीरियलाइज़र बस उन्हीं ब्लॉक्स को खाली पंक्तियों से जोड़कर बना है)। समान नाम वाली एक प्रविष्टि अंतर्निर्मित सीरियलाइज़र को बदल देती है, इसलिए आप बदल सकते हैं कि <Callout> कैसे डाउनलेवल होता है — या किसी एक को पूरी तरह बाहर करने के लिए null लौटा सकते हैं।

सीरियलाइज़र blume.config.ts में रहते हैं, components.tsx में नहीं: कॉन्फ़िग फ़ाइल बिल्ड समय पर निष्पादित होती है, जबकि कंपोनेंट्स फ़ाइल का केवल स्थैतिक विश्लेषण किया जाता है (यह .astro फ़ाइलें इम्पोर्ट कर सकती है, जो साइट बिल्ड के बाहर नहीं चल सकतीं)। आपके कंपोनेंट्स स्वयं पहले की तरह ही components.tsx में पंजीकृत रहते हैं — markdownComponents केवल उनका एजेंट-सामने वाला Markdown रूप जोड़ता है।

Copy as Markdown

हर पेज पर एक Copy as Markdown क्रिया होती है — विषय-सूची के नीचे पेज क्रियाओं में — जो पेज का कच्चा Markdown क्लिपबोर्ड पर कॉपी करती है। यह वही स्रोत है जो ऊपर .md URL पर सर्व किया जाता है, किसी LLM, किसी इशू, या आपके नोट्स में पेस्ट करने के लिए तैयार। यह हर पेज पर, dev और production दोनों में, बिना किसी कॉन्फ़िगरेशन के उपलब्ध है।

जहाँ Clipboard API उपलब्ध न हो या ब्राउज़र इसे अस्वीकार कर दे — इन-ऐप ब्राउज़र, WebViews, असुरक्षित ऑरिजिन — वहाँ यह क्रिया पुराने कॉपी कमांड पर वापस गिरती है, और यदि क्लिपबोर्ड पर कुछ भी न पहुँचे तो बटन चुप रहने के बजाय Copy failed बताता है (actions.copyFailed के माध्यम से स्थानीयकृत)। यही फ़ॉलबैक Blume द्वारा रेंडर किए जाने वाले हर कॉपी बटन के पीछे है।

चैट में खोलें

Open in chat क्रिया वर्तमान पेज को किसी AI सहायक में खोलती है — v0, ChatGPT, Claude, T3 Chat, Scira, या Cursor — एक ऐसे प्रॉम्प्ट के साथ पहले से भरा हुआ जो उसे पेज के कच्चे Markdown की ओर इंगित करता है ताकि वह उसके बारे में सवालों का जवाब दे सके जो आप पढ़ रहे हैं:

Read https://your-site/this-page.md so I can ask you questions about this page.

Copy as Markdown की तरह, इसे किसी सेटअप की ज़रूरत नहीं है। सहायक पेज को उसके सार्वजनिक URL से लाता है, इसलिए यह पेज डिप्लॉय होते ही काम करने लगता है।

यह प्रॉम्प्ट UI शब्दकोश (actions.openInChatPrompt) का हिस्सा है, इसलिए स्थानीयकृत साइटें इसे अपनी भाषा में भेजती हैं, और i18n.ui शब्दावली को ओवरराइड कर सकता है — {url} प्लेसहोल्डर बनाए रखें, जिसे पेज के कच्चे-Markdown URL से बदल दिया जाता है।

क्रिया को अनुकूलित करने के लिए, ai.openInChat सेट करें। false इसे पूरी तरह छिपा देता है, और प्रदाता कुंजियों की एक सरणी — "v0", "chatgpt", "claude", "t3", "scira", "cursor" — केवल उन्हीं प्रदाताओं को दिखाती है, उसी क्रम में जिस क्रम में आप उन्हें सूचीबद्ध करते हैं:

ai: {
  openInChat: ["claude", "chatgpt", "cursor"],
}

अपनी सामग्री में इनलाइन एक कॉपी-करने-योग्य प्रॉम्प्ट एम्बेड करने के लिए — पूरे-पेज की क्रिया के बजाय — Prompt कंपोनेंट का उपयोग करें, जो एक Copy prompt बटन और एक वैकल्पिक open-in-Cursor लिंक के साथ एक लेबल की गई पंक्ति रेंडर करता है।

Ask AI

एक सहायक जोड़ें जो पाठकों के सवालों का जवाब एक इन-पेज चैट पैनल में देता है, जिसके पीछे एक स्ट्रीमिंग सर्वर एंडपॉइंट और AI SDK है:

ai: {
  ask: {
    enabled: true,
    provider: "gateway", // default
    model: "openai/gpt-5.5",
  },
}

सुझाए गए प्रश्न

खाली स्थिति को कुछ शुरुआती प्रॉम्प्ट्स से भरें। प्रत्येक एक क्लिक-योग्य सुझाव के रूप में रेंडर होता है — भेजने के लिए किसी एक पर क्लिक करें — लेबल के बगल में एक वैकल्पिक Lucide आइकन के साथ:

ai: {
  ask: {
    enabled: true,
    suggestions: [
      { label: "What is Blume?", icon: "rocket" },
      { label: "How do I write a docs page?", icon: "file-text" },
      { label: "How do I configure the theme?", icon: "settings" },
    ],
  },
}

label वह प्रश्न है जो पूछा जाता है; icon वैकल्पिक है। suggestions को अनसेट (या खाली) छोड़ दें और पैनल एक सादे इनपुट के साथ खुलता है।

कस्टम निर्देश

instructions के साथ अपना स्वयं का सिस्टम-प्रॉम्प्ट टेक्स्ट जोड़ें — पहचान, भाषा, लहजा, या कुछ भी और जो सहायक को ध्यान में रखना चाहिए:

ai: {
  ask: {
    enabled: true,
    instructions:
      "You are Bloomy, the Acme docs assistant. Answer in the language the question was asked in, and keep answers under three paragraphs.",
  },
}

आपका टेक्स्ट अंतर्निर्मित निर्देशों को बदलने के बजाय उनमें जोड़ा जाता है: अंतर्निर्मित भाग ग्राउंडिंग अनुबंध रखता है — केवल पुनःप्राप्त पेजों से उत्तर दें, उन्हें Markdown लिंक्स के रूप में उद्धृत करें — जिस पर चैट पैनल के उद्धरण निर्भर करते हैं, इसलिए आप जो भी जोड़ें, वह बरकरार रहता है।

ग्राउंडिंग

Ask AI आपके डॉक्स में ग्राउंडेड है। हर प्रश्न के लिए यह सबसे प्रासंगिक पेज पुनःप्राप्त करता है — वही लेक्सिकल Orama इंडेक्स उपयोग करते हुए जो ऑन-पेज खोज को शक्ति देता है — और उन्हें मॉडल के सिस्टम प्रॉम्प्ट में डालता है, ताकि उत्तर मॉडल के अपने ज्ञान के बजाय आपकी सामग्री से आएँ। सहायक को कहा जाता है कि वह केवल पुनःप्राप्त पेजों से उत्तर दे, बताए कि कब कोई बात कवर नहीं है, और जिन पेजों से उसने लिया है उनका उद्धरण दे।

पाठक वर्तमान में जिस पेज पर है, उसे सबसे पहले संदर्भ में जोड़ा जाता है और पुनःप्राप्ति को उस पेज की भाषा तक सीमित करने के लिए उपयोग किया जाता है, ताकि उत्तर इस बात के अनुरूप रहें कि वे डॉक्स में कहाँ हैं। पुनःप्राप्ति अनुरोध समय पर बिल्ड में पकाए गए एक स्नैपशॉट से चलती है, इसलिए यह आपके खोज प्रदाता की परवाह किए बिना काम करती है — तब भी जब खोज none पर सेट हो — और इसे किसी कॉन्फ़िगरेशन की ज़रूरत नहीं है।

Inkeep को छोड़कर हर बैकएंड के लिए ग्राउंडिंग चालू है, जो अपने डैशबोर्ड में आपके द्वारा इंडेक्स की गई सामग्री पर अपनी स्वयं की पुनःप्राप्ति चलाता है।

पुनःप्राप्ति आकार

कोई प्रश्न कितना दस्तावेज़ीकरण साथ ले जाता है, यह इस बात पर सबसे बड़ा लीवर है कि पाठक पहले शब्द के लिए कितनी देर प्रतीक्षा करता है: मॉडल एक भी टोकन उत्सर्जित करने से पहले हर डाले गए अक्षर को पढ़ता है। किसी होस्टेड फ्रंटियर मॉडल पर यह अदृश्य होता है, लेकिन किसी स्व-होस्टेड बैकएंड पर यह हावी रहता है। retrieval इसका आकार तय करता है:

ai: {
  ask: {
    enabled: true,
    retrieval: {
      maxResults: 3, // fewer pages retrieved per question
      excerptChars: 1200, // shorter excerpt from each one
      contextBudget: 3000, // smaller total injection
    },
  },
}
विकल्प डिफ़ॉल्ट विवरण
maxResults 6 प्रति प्रश्न पुनःप्राप्त किए गए दस्तावेज़।
excerptChars 2000 प्रत्येक पुनःप्राप्त पेज से रखे गए अक्षर।
contextBudget 10000 सभी अंशों में मिलाकर, कुल डाले गए अक्षर।

ये तीनों आपस में विनिमेय नहीं हैं। contextBudget पूरे इंजेक्शन की सीमा तय करता है, excerptChars यह तय करता है कि किसी एक लंबे पेज के भीतर उसका अंश कितनी गहराई तक पहुँचता है — इसे तब बढ़ाएँ जब पूरा उत्तर एक ही पेज में हो और अंश उसे बीच में काट दे — और maxResults यह सीमित करता है कि पुनःप्राप्ति कितने पेज जोड़े। पाठक जिस पेज को देख रहा है, उसे पुनःप्राप्त पेजों के ऊपर डाला जाता है, इसलिए कोई उत्तर maxResults से एक पेज अधिक तक का उद्धरण दे सकता है।

डिफ़ॉल्ट मान किसी होस्टेड मॉडल के अनुकूल हैं। इन्हें तब घटाएँ जब आप अपने स्वयं के हार्डवेयर से सर्व कर रहे हों और टाइम-टू-फ़र्स्ट-टोकन का महत्व रिकॉल से अधिक हो; उत्तर दोनों ही स्थितियों में ग्राउंडेड रहते हैं, और सहायक को कहा जाता है कि खाली जगह भरने के बजाय यह बताए कि कब कोई बात कवर नहीं है।

बाहरी एंडपॉइंट

क्या आपके पास पहले से AI के लिए एक API बैकएंड है? पैनल को उसकी ओर इंगित करें और डॉक्स बिल्ड को स्टैटिक रखें:

ai: {
  ask: {
    enabled: true,
    endpoint: "https://api.example.com/v1/docs/ask",
  },
}

Blume वही POST बॉडी भेजता है जो उसका अंतर्निर्मित रूट भेजता है:

{
  "messages": [{ "role": "user", "content": "How do I deploy?" }],
  "page": { "path": "/deployment" }
}

एक सफल प्रतिक्रिया लौटाएँ जिसकी बॉडी एक सादी UTF-8 टेक्स्ट स्ट्रीम हो। यदि एंडपॉइंट किसी अन्य ऑरिजिन पर है, तो CORS के साथ डॉक्स ऑरिजिन की अनुमति दें: OPTIONS और POST स्वीकार करें, content-type अनुरोध हेडर की अनुमति दें, और प्रीफ़्लाइट तथा स्ट्रीम की गई प्रतिक्रिया दोनों पर CORS हेडर लौटाएँ। endpoint सेट होने पर, Blume चैट UI जनरेट करता है लेकिन कोई सर्वर रूट, ग्राउंडिंग स्नैपशॉट, प्रदाता निर्भरता, या प्रदाता-सीक्रेट चेतावनी नहीं; आपका बैकएंड पुनःप्राप्ति, प्रमाणीकरण, दर सीमा, मॉडल एक्सेस और उद्धरणों का स्वामी होता है।

सर्वर आउटपुट आवश्यक

Blume का अंतर्निर्मित Ask AI बैकएंड एक सर्वर रूट (POST /api/ask) है, इसलिए यह स्टैटिक बिल्ड पर नहीं चल सकता। सर्वर आउटपुट पर स्विच करें और एक एडाप्टर चुनें:

deployment: {
  output: "server",
  adapter: "vercel",
}

Ask AI सक्षम और बिना बाहरी endpoint वाला एक स्टैटिक बिल्ड तुरंत विफल हो जाता है, एक संदेश के साथ जो आपको deployment.output को server पर सेट करने के लिए कहता है। एडाप्टर्स के लिए Deployment देखें।

बैकएंड्स

डिफ़ॉल्ट रूप से Ask AI Vercel AI Gateway के माध्यम से रूट होता है: model एक provider/model स्ट्रिंग है, इसलिए आप इसे बदलकर मॉडल बदलते हैं (openai/gpt-5.5, anthropic/claude-sonnet-4-5, इत्यादि) और कोई प्रदाता SDK इंस्टॉल नहीं करना पड़ता। गेटवे आपके परिवेश से AI_GATEWAY_API_KEY पढ़ता है और जब आप Vercel पर डिप्लॉय करते हैं तो स्वचालित रूप से जुड़ जाता है।

Ask AI को कहीं और इंगित करने के लिए provider सेट करें। प्रत्येक बैकएंड अपनी API कुंजी एक परिवेश चर से पढ़ता है और एक प्रदाता SDK के माध्यम से स्ट्रीम करता है जिसे आप अपने प्रोजेक्ट में इंस्टॉल करते हैं — केवल वही जिसका आप उपयोग करते हैं:

provider model API कुंजी env चर इंस्टॉल करने योग्य SDK
gateway (डिफ़ॉल्ट) AI Gateway के माध्यम से एक provider/model स्ट्रिंग AI_GATEWAY_API_KEY कोई नहीं — Blume के साथ आता है
openrouter कोई भी OpenRouter मॉडल OPENROUTER_API_KEY @openrouter/ai-sdk-provider
llmgateway कोई भी LLMGateway मॉडल LLMGATEWAY_API_KEY @ai-sdk/openai-compatible
inkeep एक Inkeep QA मॉडल INKEEP_API_KEY @ai-sdk/openai-compatible
openai-compatible जो कुछ भी आपका एंडपॉइंट सर्व करता है apiKeyEnv से सेट करें @ai-sdk/openai-compatible

ये SDKs वैकल्पिक पीयर निर्भरताएँ हैं, इसलिए अपने प्रोजेक्ट में वही जोड़ें जिसकी आपके बैकएंड को ज़रूरत है (जैसे npm install @openrouter/ai-sdk-provider)। यदि यह अनुपस्थित है, तो Vite इम्पोर्ट हल करने में विफल हो, उससे पहले ही बिल्ड सटीक पैकेज नाम के साथ चेतावनी देता है।

उदाहरण के लिए, OpenRouter उपयोग करने के लिए:

ai: {
  ask: {
    enabled: true,
    provider: "openrouter",
    model: "anthropic/claude-sonnet-4-5",
  },
}

कोई भी OpenAI-संगत एंडपॉइंट openai-compatible के माध्यम से काम करता है — baseUrl और उसकी कुंजी रखने वाला env चर दें:

ai: {
  ask: {
    enabled: true,
    provider: "openai-compatible",
    baseUrl: "https://my-gateway.example.com/v1",
    apiKeyEnv: "MY_GATEWAY_API_KEY",
    model: "gpt-4o",
  },
}

किसी भिन्न env चर या प्रॉक्सी की ओर इंगित करने के लिए किसी भी बैकएंड पर apiKeyEnv (और, नामित प्रदाताओं के लिए, baseUrl) सेट करें।

कुंजियाँ process.env से पढ़ी जाती हैं, जो Node, Vercel और Netlify एडाप्टर्स को कवर करता है। Cloudflare पर, कुंजी को प्लेटफ़ॉर्म के रनटाइम बाइंडिंग के माध्यम से उपलब्ध कराएँ। Ask AI सक्षम करने से इन-पेज आइलैंड के लिए React भी चालू हो जाता है — देखें Customization

दर सीमा

POST /api/ask एंडपॉइंट अप्रमाणित है — इसे होना ही पड़ता है, ताकि इन-पेज सहायक इसे कॉल कर सके। Blume हर अनुरोध को मान्य करता है — विकृत बॉडी अस्वीकार करते हुए, इसे 1–40 संदेशों तक सीमित करते हुए, और केवल user/assistant भूमिकाएँ स्वीकार करते हुए ताकि कोई कॉलर अपना सिस्टम प्रॉम्प्ट इंजेक्ट करके रूट को एक सामान्य LLM प्रॉक्सी में न बदल सके — ताकि यह सीमित रहे कि एक कॉल आपके मॉडल के विरुद्ध कितना खर्च कर सकता है, लेकिन यह किसी को बार-बार एंडपॉइंट कॉल करने से नहीं रोक सकता। यदि लागत का दुरुपयोग चिंता का विषय है, तो रूट को किसी दर सीमक के पीछे रखें — आपके होस्ट की (जैसे Vercel की) एज दर सीमा, कोई मिडलवेयर, या आपके मॉडल प्रदाता की प्रति-कुंजी खर्च सीमाएँ।

MCP सर्वर

एक Model Context Protocol सर्वर होस्ट करें ताकि कोडिंग एजेंट (Claude Code, Cursor, VS Code, claude.ai कनेक्टर्स) आपके डॉक्स को सीधे खोज और पढ़ सकें — बिना स्क्रैपिंग के:

ai: {
  mcp: {
    enabled: true,
    route: "/mcp", // where the server is mounted
  },
}
विकल्प डिफ़ॉल्ट विवरण
enabled false MCP सर्वर जनरेट और होस्ट करें।
route /mcp वह पथ जिस पर Streamable-HTTP एंडपॉइंट माउंट होता है।
name title क्लाइंट्स को दिखाया जाने वाला सर्वर नाम (डिफ़ॉल्ट title)।
instructions कनेक्ट होने वाले एजेंट्स को दिया जाने वाला वैकल्पिक सिस्टम संकेत।

सर्वर केवल-पढ़ने योग्य टूल उपलब्ध कराता है — search_docs, get_page, list_pages, और get_navigation — और हर पेज को एक MCP संसाधन के रूप में (resources/list पेजों को उनके सर्व किए गए URLs पर text/markdown प्रकार के साथ गिनाता है; resources/read पेज का एजेंट Markdown लौटाता है, वही आउटपुट जो get_page देता है), ताकि जो क्लाइंट्स URI द्वारा संदर्भ जोड़ते हैं वे बिना कोई टूल कॉल किए डॉक्स ब्राउज़ कर सकें। यह /.well-known/mcp.json तथा /.well-known/mcp/server-card.json पर डिस्कवरी दस्तावेज़ प्रकाशित करता है। सर्वर कार्ड SEP-2127 Server Card एक्सटेंशन स्कीमा का अनुसरण करता है (रिवर्स-DNS name, remotes ट्रांसपोर्ट एंडपॉइंट्स), साथ ही प्रस्ताव के पूर्ववर्ती संशोधन के विरुद्ध बनाए गए स्कैनर्स के लिए initialize-आकार वाले संगतता फ़ील्ड (serverInfo, capabilities, transports) के साथ। हर पेज का Connect to MCP मेनू Claude Code, Cursor, VS Code और Codex के लिए कॉपी-एंड-गो इंस्टॉल प्रदान करता है (deployment.site सेट होने पर दिखता है)।

search_docs अपना स्वयं का पूर्ण-पाठ इंडेक्स चलाता है, इसलिए यह आपके खोज प्रदाता की परवाह किए बिना काम करता है — और तब भी जब खोज none पर सेट हो। MCP सर्वर ऑन-पेज खोज से एक अलग सुविधा है।

search_docs और list_pages दोनों एक वैकल्पिक contentTypes फ़िल्टर स्वीकार करते हैं, जो परिणामों को दिए गए फ़्रंटमैटर types वाले पेजों तक सीमित करता है — ["rfc"], ["blog", "changelog"] — ताकि ऐसी साइट पर काम करने वाला एजेंट जो डॉक्स को RFCs, रनबुक्स या नीतियों के साथ मिलाती है, पुनःप्राप्ति को उस प्रकार के पेज तक सीमित कर सके जिसकी उसे ज़रूरत है। हर परिणाम अपना कंटेंट प्रकार बताता है, और list_pages का आउटपुट उपयोग में मौजूद प्रकार दिखाता है।

दोनों टूल एक filters ऑब्जेक्ट भी स्वीकार करते हैं जो उन फ़ेसेट्स के विरुद्ध मिलान करता है जिन्हें कोई साइट प्रति कंटेंट प्रकार घोषित करती है (content.types.<type>.facets) — कस्टम फ़्रंटमैटर कुंजियाँ जिनके मान फ़िल्टर करने योग्य मेटाडेटा बन जाते हैं:

{
  "query": "OpenAPI request schemas",
  "contentTypes": ["rfc"],
  "filters": { "domain": "architecture", "status": "enforced" }
}

हर filters प्रविष्टि का मेल खाना आवश्यक है (परिणाम अपने फ़ेसेट मान साथ रखते हैं, और list_pages हर पेज के मान दिखाता है), इसलिए एक नॉलेज बेस प्रोग्रेसिव-डिस्क्लोज़र एजेंट वर्कफ़्लो चला सकता है — लागू मानकों की गणना करें, केवल उन्हीं के भीतर खोजें — अपने किसी सर्वर के बिना।

सर्वर आउटपुट आवश्यक

MCP सर्वर एक लाइव एंडपॉइंट (/mcp) है, इसलिए यह स्टैटिक बिल्ड पर नहीं चल सकता। सर्वर आउटपुट पर स्विच करें और एक एडाप्टर चुनें:

deployment: {
  output: "server",
  adapter: "node", // or "vercel" | "netlify" | "cloudflare"
  site: "https://docs.example.com",
}

ai.mcp.enabled वाला एक स्टैटिक बिल्ड तुरंत विफल हो जाता है, एक संदेश के साथ जो आपको deployment.output को server पर सेट करने के लिए कहता है। एडाप्टर्स के लिए Deployment देखें। डिप्लॉय होने के बाद, Claude Code से इस तरह कनेक्ट करें:

claude mcp add --transport http my-docs https://docs.example.com/mcp

JSON API

हर Blume साइट अपने डॉक्स को एक छोटे केवल-पढ़ने योग्य JSON API के रूप में भी सर्व करती है — MCP सर्वर के टूल्स का REST जुड़वाँ, उसी पेज स्नैपशॉट के ऊपर, उन एजेंट्स और फ़ंक्शन-कॉलिंग फ़्रेमवर्क्स के लिए जो MCP के बजाय सादा HTTP बोलते हैं। यह डिफ़ॉल्ट रूप से चालू है और इसे किसी कॉन्फ़िगरेशन की ज़रूरत नहीं:

एंडपॉइंट क्या लौटाता है
/api/docs/pages.json हर पेज, उसके रूट, शीर्षक, विवरण, कंटेंट प्रकार, लोकेल, फ़ेसेट्स, और उसके रेंडर किए गए, Markdown तथा JSON रूपों के URLs के साथ।
/api/docs/pages/{route}.json एक पेज: उसकी इंडेक्स प्रविष्टि और साथ में एजेंट Markdown (वही बॉडी जो get_page लौटाता है)। {route} अग्रगामी स्लैश के बिना पेज रूट है, होम के लिए index
/api/docs/navigation.json नेविगेशन ट्री — हेडर टैब्स और साइडबार पदानुक्रम।
/api/docs/search?q= पूर्ण-पाठ खोज, वही limit, contentTypes, locale, version, और filters[key] स्कोपिंग के साथ जो search_docs में है। केवल सर्वर आउटपुट।
/openapi.json पूरी मशीन-पठनीय सतह का OpenAPI 3.1 विवरण।

पेज इंडेक्स, प्रति-पेज दस्तावेज़, और नेविगेशन पूर्व-रेंडर किए जाते हैं, इसलिए एक स्टैटिक साइट उन्हें किसी भी होस्ट से फ़ाइलों के रूप में सर्व करती है। खोज एक लाइव एंडपॉइंट है और केवल सर्वर आउटपुट के अंतर्गत मौजूद रहती है, जहाँ यह वही इंडेक्स चलाती है जो search_docs चलाता है। त्रुटियाँ RFC 9457 प्रॉब्लम डिटेल्स (application/problem+json) होती हैं, जिनमें एक स्थिर code, एक detail, और एक resolution संकेत होता है जो एजेंट को बताता है कि आगे कहाँ जाना है — कोई अनुपस्थित पेज, कोई खाली खोज क्वेरी, या सर्वर आउटपुट पर कोई भी ऐसा /api/… URL जिसका उत्तर कोई एंडपॉइंट न देता हो:

{
  "code": "API_ROUTE_NOT_FOUND",
  "detail": "No API route exists at /api/nope.",
  "instance": "/api/nope",
  "links": [
    {
      "href": "https://docs.example.com/openapi.json",
      "label": "OpenAPI description"
    },
    {
      "href": "https://docs.example.com/api/docs/pages.json",
      "label": "Page index"
    }
  ],
  "resolution": "Discover the available operations through the OpenAPI description at https://docs.example.com/openapi.json, or list every page at https://docs.example.com/api/docs/pages.json.",
  "status": 404,
  "title": "API route not found",
  "type": "about:blank"
}

/openapi.json पर मौजूद OpenAPI दस्तावेज़ आपके कॉन्फ़िग से प्रति बिल्ड जनरेट होता है, इसलिए यह केवल उसी का वर्णन करता है जो डिप्लॉय की गई साइट सर्व करती है: हर JSON एंडपॉइंट एक अद्वितीय operationId, टाइप किए गए पैरामीटर्स, और प्रतिक्रिया स्कीमा के साथ, साथ ही उसके बगल की टेक्स्ट सतहें — .md प्रतिबिंब, llms.txt और llms-full.txt, agent-readability.json — और MCP एंडपॉइंट जब वह सक्षम हो। जो फ़्रेमवर्क किसी OpenAPI विवरण से टूल्स बनाते हैं, उन्हें वही पहुँच मिलती है जो एक MCP क्लाइंट के पास होती है। यह दस्तावेज़ API कैटलॉग, रीडेबिलिटी मैनिफ़ेस्ट, होमपेज के Link हेडर में rel="service-desc" के रूप में, और llms.txt से लिंक किया जाता है।

इसमें से कुछ भी आपके अपने API संदर्भ को नहीं छूता: कोई दस्तावेज़ीकृत स्पेक पेजों में रेंडर किया जाता है, कभी /openapi.json पर सर्व नहीं होता, और कैटलॉग दोनों को सूचीबद्ध करता है। आपके द्वारा स्वयं भेजी गई public/openapi.json उस रूट को अपने अधिकार में ले लेती है (JSON एंडपॉइंट बने रहते हैं)। /api/… कैच-ऑल तब पीछे हट जाता है जब कोई डॉक्स अनुभाग /api नेमस्पेस से सर्व होता है (content/api/overview.md) या कोई कस्टम पेज /api/ के अंतर्गत किसी शेष रूट का स्वामी हो, ताकि वे पेज जीतते रहें। इसमें से कुछ भी प्रकाशित न करने के लिए ai.api को false सेट करें:

ai: {
  api: false,
}

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

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

seo: {
  agentReadability: true,
}

मैनिफ़ेस्ट केवल वही सूचीबद्ध करता है जो आपने सक्षम किया है — कच्चा Markdown प्रतिबिंब पैटर्न, JSON API और उसका OpenAPI विवरण, llms.txt और llms-full.txt, MCP सर्वर और उसका डिस्कवरी दस्तावेज़, Ask AI एंडपॉइंट, साइटमैप, और 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@1.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 प्रतिबिंब पैटर्न का विज्ञापन करता है।

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

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

Link: </.well-known/api-catalog>; rel="api-catalog"; type="application/linkset+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 कैटलॉग की ओर। हेडर हर उस सतह पर जाता है जिसे Blume नियंत्रित करता है: dev सर्वर (curl -I localhost:4321 से जाँचें), उत्सर्जित _headers फ़ाइल के माध्यम से स्टैटिक बिल्ड (Netlify और Cloudflare), और डि��्लॉय के रूटिंग नियमों के माध्यम से Vercel सर्वर बिल्ड।

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

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

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

API कैटलॉग

जब साइट APIs प्रकाशित करती है, तो Blume /.well-known/api-catalog पर एक RFC 9727 API कैटलॉग जनरेट करता है — एक linkset जो एजेंट्स को केवल डोमेन से आपके APIs की गणना करने देता है, हर बिल्ड सतह पर उसके पंजीकृत application/linkset+json मीडिया प्रकार के साथ सर्व किया जाता है। कॉन्फ़िगर करने को कुछ नहीं है: कैटलॉग उसी से व्युत्पन्न होता है जो पहले से blume.config.ts में है। प्रत्येक OpenAPI या AsyncAPI संदर्भ अपने रेंडर किए गए डॉक्स रूट पर एंकर की गई एक प्रविष्टि बन जाता है, जिसमें 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 फ़ाइल जनरेट की गई फ़ाइल पर भारी पड़ती है।

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 सेट करें:

ai: {
  webmcp: false,
}

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

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

ai: {
  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 पूरी सतह पर नियंत्रण ले लेती है।

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 साइट उसी डोमेन पर है जिसके रूप में वे पहचान बताते हैं, तो उनकी सार्वजनिक कुंजियाँ प्रकाशित करें:

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

फिर Blume हर बिल्ड सतह पर JWKS को /.well-known/http-message-signatures-directory पर उसके पंजीकृत मीडिया प्रकार के साथ सर्व करता है। निर्देशिका परिभाषा से ही सार्वजनिक है, इसलिए कॉन्फ़िग केवल सार्वजनिक कुंजियाँ ही स्वीकार करता है — निजी सामग्री (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({
  ai: {
    webBotAuth: {
      keys: webBotAuthKey ? [JSON.parse(webBotAuthKey)] : [],
    },
  },
});

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

एजेंट स्किल

किसी कोडिंग एजेंट की मदद से Blume साइट बना रहे हैं? Blume एजेंट स्किल इंस्टॉल करें ताकि उसे पता हो कि Blume कैसे काम करता है, बिना आपके समझाए:

npx skills add haydenbleasel/blume

स्किल एजेंट को सिखाती है कि Blume क्या है और किसी साइट को कैसे स्कैफ़ोल्ड, लिखा और कॉन्फ़िगर किया जाए, और उसे इंस्टॉल किए गए पैकेज में बंडल किए गए पूरे डॉक्स की ओर इंगित करती है (blume के भीतर की docs/ डायरेक्टरी, जहाँ भी आपका पैकेज मैनेजर उसे इंस्टॉल करता है)।

यह Blume द्वारा भेजी जाने वाली एजेंट स्किल्स में से एक है, साथ ही एक अनुसूचित एजेंट रन से आपके उत्पाद के साथ डॉक्स को समन्वित रखने वाली स्किल भी है।

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