एजेंट्स के लिए Markdown
प्रत्येक पृष्ठ का कच्चा Markdown एक .md URL पर या Accept कंटेंट नेगोशिएशन के माध्यम से, आपके अपने कंपोनेंट्स के लिए कस्टम सीरियलाइज़र, और Copy as Markdown तथा Open in chat क्रियाएँ जो पाठकों को मुफ़्त में मिलती हैं।
HTML ब्राउज़रों के लिए है। एजेंट और LLM उस Markdown के साथ बेहतर काम करते हैं जिसमें आपके पृष्ठ लिखे गए हैं — कम टोकन, कोई क्रोम नहीं, और कंपोनेंट्स ऐसे रूप में रेंडर होते हैं जिसे कोई मॉडल पढ़ सके। Blume प्रत्येक पृष्ठ के लिए वह Markdown परोसता है, dev और production दोनों में, बिना किसी कॉन्फ़िगरेशन के।
कच्चा Markdown
किसी भी पृष्ठ के URL में .md या .mdx जोड़ें और उसका कच्चा Markdown स्रोत प्राप्त करें — LLM, कोडिंग एजेंट्स और “copy as Markdown” वर्कफ़्लो के लिए एकदम उपयुक्त।
| URL | क्या लौटाता है |
|---|---|
/quickstart |
रेंडर किया गया पृष्ठ |
/quickstart.md |
सादा Markdown, कंपोनेंट्स परिवर्तित किए हुए |
/quickstart.mdx |
MDX स्रोत, कंपोनेंट्स जैसे लिखे गए वैसे ही |
नेस्टेड रूट भी उसी तरह काम करते हैं (/content/syntax.md), और होम पेज /index.md पर परोसा जाता है।
.md संस्करण उन उपभोक्ताओं के लिए कंपोनेंट्स को सादे Markdown में डाउनलेवल कर देता है जो JSX की व्याख्या नहीं कर सकते: <TypeTable> एक Markdown तालिका बन जाता है, <Callout> एक लेबल वाला ब्लॉककोट, <Steps> एक क्रमित सूची, <Tabs> बोल्ड-लेबल वाले खंड, <Card> अपने शीर्षक को अपने बॉडी के ऊपर एक लिंक के रूप में (और <CardGroup> उन कार्ड्स को जो वह रखता है), <Accordion> बोल्ड प्रश्न और उनके नीचे उनके उत्तर, <FileTree> अपनी सूची, <CodeGroup> अपने शीर्षक-युक्त कोड ब्लॉक्स, <YouTube> एक लिंक, और हर अन्य अंतर्निर्मित कंपोनेंट — Columns, Frame, Expandable, Badge, Tooltip, और बाकी सभी — अपनी पठनीय सामग्री। <AutoTypeTable>, जिसे टाइप चेकर की आवश्यकता होती है, जैसा लिखा गया है वैसा ही बना रहता है, और यही बात उस <Diff> पर लागू होती है जो अपने पक्षों को फ़ाइलों से पढ़ता है (src, या before और after), तथा owner और repo के बिना किसी <GithubInfo> पर भी। जिन कंपोनेंट्स से एक जनरेट किया गया API संदर्भ पृष्ठ बना होता है, वे भी डाउनलेवल होते हैं: <Operation> अपने स्पेक के अपने ही नोटेशन में एंडपॉइंट बन जाता है (GET /pets/{id}, SEND user/signup, query pets) एक अप्रचलन मार्कर के साथ, और किसी OpenAPI ऑपरेशन के लिए उसके अनुरोध बॉडी की प्रॉपर्टीज़ और उदाहरण तथा उसकी प्रतिक्रियाएँ उनके उदाहरणों सहित, <ApiTagOperations> उन एंडपॉइंट्स की एक सूची जो उनके पृष्ठों से लिंक की हुई और उनके सारांश सहित हो, और <ApiOverview> API का संस्करण और बेस URL — ताकि किसी संदर्भ पृष्ठ को पढ़ने वाला एजेंट जान सके कि क्या कॉल करना है, और साइट सर्च किसी एंडपॉइंट के पथ से मेल खा सके। <Changelog /> उस रिलीज़ सूची में बदल जाता है जिसे वह रेंडर करता है: वर्ष शीर्षक, और उनके नीचे प्रति रिलीज़ एक लिंक की हुई पंक्ति। Props को शाब्दिक डेटा के रूप में पढ़ा जाता है और कभी निष्पादित नहीं किया जाता — स्ट्रिंग्स, नंबर्स, बूलियन्स, ऐरे, ऑब्जेक्ट्स और टेम्पलेट स्ट्रिंग्स, साथ ही पृष्ठ के frontmatter के संदर्भ, इसलिए title={frontmatter.status} जैसा कोई prop उसी मान में हल होता है जो रेंडर किया गया पृष्ठ दिखाता है। केवल props ही हल होते हैं: पृष्ठ के अपने पाठ में कोई एक्सप्रेशन, जैसे Owned by {frontmatter.owner}, Markdown प्रति में जैसा लिखा गया है वैसा ही बना रहता है। ऐसे मान के लिए जिसे एजेंट्स को भी पढ़ना चाहिए, उसे पाठ में लिखें, या, जब वह हर पृष्ठ पर एक जैसा हो, तो उसे एक कंटेंट वेरिएबल बनाएँ, जिसे हर सतह प्रतिस्थापित करती है। जो कुछ भी सटीक रूप से परिवर्तित नहीं किया जा सकता — कोई कस्टम कंपोनेंट, या किसी फ़ंक्शन कॉल द्वारा या किसी import से गणना किया गया prop — उसे ज्यों का त्यों छोड़ दिया जाता है, और कोड के भीतर कंपोनेंट मार्कअप को, चाहे वह fenced हो या इनलाइन, कभी नहीं छुआ जाता। यही रूपांतरण llms-full.txt और MCP सर्वर के get_page टूल पर भी लागू होता है, इसलिए एजेंट-सम्मुख हर सतह स्वच्छ Markdown पढ़ती है।
जब आपको स्वयं MDX चाहिए, तो .mdx संस्करण का उपयोग करें: उसके कंपोनेंट्स जैसे लिखे गए हैं वैसे ही बने रहते हैं, और शेष सामग्री को URL के माध्यम से उसे पढ़ने वाले एजेंट के लिए तैयार किया जाता है, ठीक .md संस्करण की तरह। इन्क्लूड्स अपनी जगह पर जोड़ दिए जाते हैं, <Visibility> एजेंट्स के लिए हल हो जाता है (for="web" सामग्री हटा दी जाती है, for="agents" सामग्री रखी जाती है), सापेक्ष इमेज और पृष्ठ के साथ स्थित अन्य फ़ाइलों के लिंक अपने परोसे गए URL की ओर संकेत करते हैं, सापेक्ष पृष्ठ लिंक और किसी कंटेंट फ़ाइल के रूट-सापेक्ष लिंक (/guides/setup.md) उन रूट्स की ओर संकेत करते हैं जिनसे उनका आशय है, और रूट-सापेक्ष लिंक (/guides/install) साइट का deployment.base और basePath प्राप्त करते हैं तथा, किसी अनूदित पृष्ठ पर, पृष्ठ के लोकेल में चले जाते हैं, ठीक उसी तरह जैसे रेंडर किए गए पृष्ठ के लिंक करते हैं। public/ में स्थित फ़ाइलों (/spec.pdf) की ओर संकेत करने वाली रूट-सापेक्ष इमेज और लिंक केवल deployment.base प्राप्त करते हैं, क्योंकि वे फ़ाइलें वहीं से परोसी जाती हैं।
कंटेंट नेगोशिएशन
एजेंट्स को .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 का विज्ञापन केवल उन डिप्लॉयमेंट्स पर करता है जो इस हेडर का सम्मान करते हैं।
किसी क्लाइंट को Markdown तब मिलता है जब उसका Accept हेडर text/markdown (या text/x-markdown, अक्षरों के किसी भी केस में) को ऐसे q-value के साथ सूचीबद्ध करता है जो शून्य से अधिक हो और कम से कम text/html के q-value जितना हो: text/markdown और text/markdown, text/html को Markdown मिलता है, जबकि text/html, text/markdown;q=0.9 को HTML मिलता है। Vercel के रूटिंग नियम दो q-values की तुलना नहीं कर सकते, इसलिए जब दोनों प्रकारों का q-value 1 से कम हो (text/markdown;q=0.9, text/html;q=0.8), तो Vercel HTML परोसता है जबकि dev सर्वर और Cloudflare Markdown परोसते हैं। हर जगह Markdown प्राप्त करने के लिए text/markdown को बिना q-value के भेजें।
अनुपस्थित पृष्ठ भी नेगोशिएट करते हैं। डिफ़ॉल्ट 404 पृष्ठ का /404.md पर एक Markdown प्रतिरूप होता है — नहीं-मिला संदेश और उसके बाद प्रत्येक शीर्ष-स्तरीय खंड, साइटमैप और llms.txt तक रिकवरी लिंक — और Vercel या Cloudflare सर्वर बिल्ड पर किसी अस्तित्वहीन URL के लिए ऐसा अनुरोध जो Markdown को प्राथमिकता देता है, उसे HTML शेल के बजाय वास्तविक 404 स्टेटस के साथ वही बॉडी मिलती है। Vercel पर यही बात किसी भी ऐसे .md URL पर लागू होती है जिसके पीछे कोई पृष्ठ न हो। आपका अपना 404 पृष्ठ (एक pages/404.astro, या /404 पर एक कंटेंट पृष्ठ) डिफ़ॉल्ट को उसके /404.md प्रतिरूप सहित प्रतिस्थापित कर देता है, इसलिए तब अनुपस्थित पृष्ठ आपके HTML पृष्ठ के साथ उत्तर देते हैं।
कस्टम कंपोनेंट सीरियलाइज़र
agents.markdownComponents के साथ अपने स्वयं के कंपोनेंट्स को एक Markdown रूप दें — JSX नाम से सीरियलाइज़र का एक मानचित्र। प्रत्येक सीरियलाइज़र कंपोनेंट के props (MDX एट्रिब्यूट्स से शाब्दिक डेटा के रूप में पढ़े गए, frontmatter संदर्भों को हल करके), उसके children (पहले से Markdown में डाउनलेवल किए हुए), और पृष्ठ का frontmatter डेटा प्राप्त करता है, और प्रतिस्थापन लौटाता है — या JSX को ज्यों का त्यों छोड़ने के लिए null:
import { defineConfig } from "blume";
import type { ComponentMarkdown } from "blume";
const chart: ComponentMarkdown = ({ props }) =>
``;
export default defineConfig({
agents: {
markdownComponents: {
Chart: chart,
},
},
});
कंटेनर कंपोनेंट्स के लिए, childComponents("Name") टैग के अनुसार सीधे चिल्ड्रन निकालता है — ठीक उसी तरह जैसे अंतर्निर्मित <Steps> सीरियलाइज़र अपने <Step> आइटम एकत्र करता है — और childBlocks() प्रत्येक सीधे चाइल्ड को क्रम में लौटाता है, कंपोनेंट्स और गद्य दोनों, प्रत्येक पहले से Markdown के एक ब्लॉक में डाउनलेवल किया हुआ (अंतर्निर्मित <CardGroup> सीरियलाइज़र बस वही ब्लॉक हैं जो रिक्त पंक्तियों से जुड़े हुए हैं)। एक ही नाम वाली प्रविष्टि किसी अंतर्निर्मित सीरियलाइज़र को प्रतिस्थापित कर देती है, इसलिए आप यह पुनः शैलीबद्ध कर सकते हैं कि <Callout> कैसे डाउनलेवल होता है — या उसे पूरी तरह से बाहर रखने के लिए null लौटा सकते हैं।
सीरियलाइज़र blume.config.ts में रहते हैं, components.tsx में नहीं: कॉन्फ़िग फ़ाइल बिल्ड समय पर निष्पादित होती है, जबकि कंपोनेंट्स फ़ाइल का केवल स्थैतिक विश्लेषण किया जाता है (वह .astro फ़ाइलें import कर सकती है, जो साइट बिल्ड के बाहर नहीं चल सकतीं)। आपके कंपोनेंट्स स्वयं पहले की तरह ही components.tsx में पंजीकृत रहते हैं — markdownComponents केवल उनका एजेंट-सम्मुख Markdown रूप जोड़ता है।
Copy as Markdown
प्रत्येक पृष्ठ में एक Copy as Markdown क्रिया होती है — विषय-सूची के नीचे पृष्ठ क्रियाओं में — जो पृष्ठ के कच्चे Markdown को क्लिपबोर्ड पर कॉपी कर देती है। यह वही स्रोत है जो ऊपर .md URL पर परोसा जाता है, किसी LLM, किसी issue, या आपके नोट्स में पेस्ट करने के लिए तैयार। यह प्रत्येक पृष्ठ पर उपलब्ध है, dev और production दोनों में, बिना किसी कॉन्फ़िगरेशन के।
जहाँ Clipboard API उपलब्ध नहीं है या ब्राउज़र उसे अस्वीकार कर देता है — इन-ऐप ब्राउज़र, WebViews, असुरक्षित ऑरिजिन — वहाँ यह क्रिया पुराने कॉपी कमांड पर वापस गिर जाती है, और यदि क्लिपबोर्ड पर कुछ भी नहीं पहुँचता तो बटन मौन रहने के बजाय Copy failed (actions.copyFailed के माध्यम से स्थानीयकृत) की सूचना देता है। यही फ़ॉलबैक Blume द्वारा रेंडर किए गए प्रत्येक कॉपी बटन को समर्थन देता है।
Open in chat
Open in chat क्रिया वर्तमान पृष्ठ को किसी AI सहायक में खोलती है — v0, ChatGPT, Claude, T3 Chat, Scira, या Cursor — एक ऐसे प्रॉम्प्ट के साथ पहले से भरी हुई जो उसे पृष्ठ के कच्चे Markdown की ओर इंगित करता है ताकि वह उस बारे में प्रश्नों के उत्तर दे सके जिसे आप पढ़ रहे हैं:
https://your-site/this-page.mdपढ़ें ताकि मैं आपसे इस पृष्ठ के बारे में प्रश्न पूछ सकूँ।
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 लिंक के साथ एक लेबल वाली पंक्ति रेंडर करता है।