---
title: エージェント向けの Markdown
description: >-
  すべてのページの生の Markdown を .md URL または Accept コンテンツネゴシエーションで提供し、独自のコンポーネント用のカスタムシリアライザーを定義でき、読者は Markdown としてコピーとチャットで開くのアクションを追加設定なしで利用できます。
---

HTML はブラウザーのためのものです。エージェントや LLM は、ページの記述に使われている Markdown のほうがうまく扱えます — トークンが少なく、余計な装飾がなく、コンポーネントもモデルが読める形式でレンダリングされます。Blume は、開発環境でも本番環境でも、設定不要ですべてのページの Markdown を配信します。

## 生の Markdown [#raw-markdown]

任意のページの URL に `.md` または `.mdx` を付けると、その生の Markdown ソースを取得できます — LLM、コーディングエージェント、「Markdown としてコピー」のワークフローに最適です。

| URL               | 返される内容                                  |
| ----------------- | --------------------------------------------- |
| `/quickstart`     | レンダリングされたページ                      |
| `/quickstart.md`  | コンポーネントが変換されたプレーンな Markdown |
| `/quickstart.mdx` | 記述されたままの生の MDX ソース               |

ネストされたルートも同じように機能し (`/content/syntax.md`)、ホームページは `/index.md` で配信されます。

`.md` バリアントは、JSX を解釈できないコンシューマー向けにコンポーネントをプレーンな Markdown へ*ダウンレベル*します。`<TypeTable>` は Markdown のテーブルに、`<Callout>` はラベル付きの引用ブロックに、`<Steps>` は順序付きリストに、`<Tabs>` は太字ラベルのセクションに、`<Card>` は本文にリンクとしてタイトルを重ねたものに (そして `<CardGroup>` はそれが保持するカードに)、`<YouTube>` はリンクになります。生成された [API リファレンス](/docs/advanced/api-reference)ページを構成するコンポーネントもダウンレベルされます。`<Operation>` はそのスペック独自の記法によるエンドポイント (`GET /pets/{id}`、`SEND user/signup`、`query pets`) と非推奨マーカーになり、`<ApiTagOperations>` はそれらのエンドポイントを各ページへのリンクと概要付きで並べたリストになり、`<ApiOverview>` は API のバージョンとベース URL になります — これにより、リファレンスページを読むエージェントは何を呼び出せばよいかが分かり、サイト検索でもエンドポイントのパスがマッチします。プロパティはページの `frontmatter` をスコープに入れて評価されるため、`title={frontmatter.status}` のようなプロパティはレンダリングされたページと同じ値に解決されます。忠実に変換できないもの — カスタムコンポーネントや、import から計算されたプロパティ — はそのまま残され、フェンス付きコードブロック内のコンポーネントマークアップには一切手が加えられません。同じ変換は [`llms-full.txt`](/docs/discoverability/llms-txt) と [MCP サーバー](/docs/discoverability/mcp)の `get_page` ツールにも適用されるため、エージェント向けのあらゆる面がクリーンな Markdown を読み取れます。変換されていないソースが必要な場合は、`.mdx` バリアントを使用してください。

### コンテンツネゴシエーション [#content-negotiation]

エージェントが `.md` の規約を知っている必要はありません。ページ自身の URL に [`Accept: text/markdown`](https://acceptmarkdown.com) ヘッダーを付けてリクエストすると、同じアドレスで Markdown バリアントが配信され、キャッシュが両者を区別できるよう `Vary: Accept` が付きます。開発サーバーは標準でこのヘッダーを尊重し、[Vercel または Cloudflare のサーバービルド](/docs/deployment#server-rendering)は同じネゴシエーションをデプロイに自動的に組み込みます — Vercel ではルーティングルール、Cloudflare では生成された Worker で — 設定は不要です。ホームページは、コンテンツページではなくカスタムのランディングページであっても、常にネゴシエーションを行います。その Markdown ミラーは [`llms.txt`](/docs/discoverability/llms-txt) インデックスにフォールバックするため、サイトのルートに Markdown を要求したエージェントはサイトの機械可読なマップを受け取ります。Markdown のレスポンスには `x-markdown-tokens` ヘッダーも付きます — [Cloudflare の Markdown for Agents](https://developers.cloudflare.com/fundamentals/reference/markdown-for-agents/) の慣例に従った推定トークン数 (1 トークンあたり約 4 文字) で、Blume がレスポンスヘッダーを制御できるすべての面 — 開発サーバー、サーバーレンダリングされたレスポンス、Vercel と Cloudflare でネゴシエーションされたホームページ — に付与されます。その他のデプロイ先はリクエスト時のフックを持たない静的レイヤーからプリレンダリング済みページを配信するため、そこではエージェントが `.md` URL を直接取得します。[エージェント可読性マニフェスト](/docs/discoverability/agent-discovery#agent-readability)は、ヘッダーを尊重するデプロイでのみ `contentNegotiation` を告知します。

存在しないページもネゴシエーションします。すべてのビルドは `/404.md` に Markdown の [404 ページ](/docs/advanced/custom-pages#404-page) を出力します — not-found メッセージに続いて、すべてのトップレベルセクション、サイトマップ、`llms.txt` への復帰リンクが並びます — そして Vercel では、Markdown を優先する存在しない URL へのリクエスト、あるいは背後にページがない `.md` URL は、HTML シェルではなくその本文を実際の `404` ステータスで受け取ります。

### カスタムコンポーネントシリアライザー [#custom-component-serializers]

`ai.markdownComponents` — JSX 名からシリアライザーへのマップ — を使って、独自のコンポーネントに Markdown 形式を与えられます。各シリアライザーは、コンポーネントの `props` (MDX の属性から静的に評価され、ページの `frontmatter` がスコープに入ります)、`children` (すでに Markdown へダウンレベル済み)、およびページの `frontmatter` データを受け取り、置き換える内容を返します — JSX をそのまま残す場合は `null` を返します。

```ts blume.config.ts lineNumbers
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` を返して完全に対象外にしたりできます。

シリアライザーは `components.tsx` ではなく `blume.config.ts` に置きます。設定ファイルはビルド時に実行されるのに対し、コンポーネントファイルは静的に解析されるだけだからです (コンポーネントファイルは `.astro` ファイルを import することがあり、それらはサイトのビルド外では実行できません)。コンポーネント自体はこれまでどおり `components.tsx` に登録したままです — `markdownComponents` は、そのエージェント向けの Markdown 形式を追加するだけです。

## Markdown としてコピー [#copy-as-markdown]

すべてのページには **Markdown としてコピー** のアクションがあり — 目次の下の[ページアクション](/docs/content/navigation#page-actions)にあります — ページの生の Markdown をクリップボードにコピーします。これは上記の [`.md` URL](#raw-markdown) で配信されるものと同じソースで、LLM、Issue、メモなどにそのまま貼り付けられます。開発環境でも本番環境でも、設定不要ですべてのページで利用できます。

Clipboard API が利用できない場合やブラウザーが拒否した場合 — アプリ内ブラウザー、WebView、安全でないオリジンなど — このアクションはレガシーのコピーコマンドにフォールバックし、クリップボードに何も入らなかった場合は、黙ったままにするのではなくボタンが **コピーに失敗しました** (`actions.copyFailed` でローカライズ) と表示します。同じフォールバックが、Blume がレンダリングするすべてのコピーボタンを支えています。

## チャットで開く [#open-in-chat]

**チャットで開く** アクションは、現在のページを AI アシスタント — v0、ChatGPT、Claude、T3 Chat、Scira、Cursor — で開きます。プロンプトにはページの生の Markdown を指すよう事前入力されているため、読んでいる内容についての質問に答えてもらえます。

> `https://your-site/this-page.md` を読んで、このページについて質問できるようにしてください。

Markdown としてコピーと同様、セットアップは不要です。アシスタントは公開 URL 経由でページを取得するため、ページがデプロイされ次第すぐに機能します。

このプロンプトは [UI ディクショナリー](/docs/content/i18n#translated-ui) (`actions.openInChatPrompt`) の一部なので、ローカライズされたサイトはそれぞれの言語で送信し、`i18n.ui` で文言を上書きできます — ページの生 Markdown URL に置き換えられる `{url}` プレースホルダーは残してください。

このアクションを調整するには、`ai.openInChat` を設定します。`false` は完全に非表示にし、プロバイダーキーの配列 — `"v0"`、`"chatgpt"`、`"claude"`、`"t3"`、`"scira"`、`"cursor"` — は、列挙した順序でそれらのプロバイダーだけを表示します。

```ts blume.config.ts lineNumbers
ai: {
  openInChat: ["claude", "chatgpt", "cursor"],
}
```

ページ全体のアクションではなく、コンテンツ内にコピーしてすぐ使えるプロンプトを埋め込むには、[Prompt コンポーネント](/docs/content/components#prompt)を使用してください。**プロンプトをコピー** ボタンと、任意の Cursor で開くリンクを備えたラベル付きの行をレンダリングします。
